[processing][API] Add API to QgsProcessingGuiRegistry and QgsProcessingParameterWidgetFactoryInterface

to handle creation of parameter definition widgets

Previously, these configuration widgets were all hardcoded into the Python modeler
dialog. This prevented 3rd party, plugin provided, parameters from ever being full
first class citizens in QGIS, as there was no way to allow their use as inputs to
user created models to be customised.

Now, the registry is responsible for creating the configuration widget, allowing
for 3rd party parameter types to provide their own customised configuration
widgets.

Refs #26493
This commit is contained in:
Nyall Dawson 2019-06-30 20:08:11 +10:00
parent b0d7c2927e
commit 10d6a8a122
16 changed files with 786 additions and 15 deletions

View File

@ -123,6 +123,33 @@ handles the given ``parameter``, ``None`` will be returned.
.. seealso:: :py:func:`addParameterWidgetFactory`
.. versionadded:: 3.4
%End
QgsProcessingAbstractParameterDefinitionWidget *createParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = 0,
const QgsProcessingAlgorithm *algorithm = 0 ) /Factory/;
%Docstring
Creates a new parameter definition widget allowing for configuration of an instance of
a specific parameter ``type``.
The ``context`` argument must specify a Processing context, which will be used
by the widget to evaluate existing ``definition`` properties such as default values. Similarly,
the ``widgetContext`` argument specifies the wider GUI context in which the widget
will be used.
The optional ``definition`` argument may specify an existing parameter definition which
will be reflected in the initial state of the returned widget. If ``definition`` is ``None``,
then the returned widget will use default settings instead.
Additionally, the optional ``algorithm`` parameter may be used to specify the algorithm or model
associated with the parameter.
If ``None`` is returned for a particular parameter ``type``,
it indicates that the parameter type cannot be configured via GUI.
.. versionadded:: 3.10
%End
};

View File

@ -0,0 +1,154 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessingparameterdefinitionwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsProcessingAbstractParameterDefinitionWidget : QWidget
{
%Docstring
Abstract base class for widgets which allow users to specify the properties of a
Processing parameter.
.. versionadded:: 3.10
%End
%TypeHeaderCode
#include "qgsprocessingparameterdefinitionwidget.h"
%End
public:
QgsProcessingAbstractParameterDefinitionWidget( QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = 0,
const QgsProcessingAlgorithm *algorithm = 0, QWidget *parent /TransferThis/ = 0 );
%Docstring
Creates a new QgsProcessingAbstractParameterDefinitionWidget, with the specified ``parent`` widget.
The ``context`` argument must specify a Processing context, which will be used
by the widget to evaluate existing ``definition`` properties such as default values. Similarly,
the ``widgetContext`` argument specifies the wider GUI context in which the widget
will be used.
The optional ``definition`` argument may be used to provide a parameter definition to use
to initially populate the widget's state.
Additionally, the optional ``algorithm`` parameter may be used to specify the algorithm or model
associated with the parameter.
%End
virtual QgsProcessingParameterDefinition *createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const = 0 /Factory/;
%Docstring
Returns a new instance of a parameter definition, using the current settings defined in the dialog.
Common properties for parameters, including the ``name``, ``description``, and parameter ``flags`` are passed to the
method. Subclass implementations must use these properties when crafting a parameter definition which
also respects the additional properties specific to the parameter type handled by the widget sublass.
%End
};
class QgsProcessingParameterDefinitionWidget: QWidget
{
%Docstring
A widget which allow users to specify the properties of a Processing parameter.
.. versionadded:: 3.10
%End
%TypeHeaderCode
#include "qgsprocessingparameterdefinitionwidget.h"
%End
public:
QgsProcessingParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = 0,
const QgsProcessingAlgorithm *algorithm = 0,
QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsProcessingParameterDefinitionWidget, for a parameter of the
specified ``type``.
The ``context`` argument must specify a Processing context, which will be used
by the widget to evaluate existing ``definition`` properties such as default values. Similarly,
the ``widgetContext`` argument specifies the wider GUI context in which the widget
will be used.
The optional ``definition`` argument may be used to provide a parameter definition to use
to initially populate the widget's state.
Additionally, the optional ``algorithm`` parameter may be used to specify the algorithm or model
associated with the parameter.
%End
QgsProcessingParameterDefinition *createParameter( const QString &name = QString() ) const /Factory/;
%Docstring
Returns a new instance of a parameter definition, using the current settings defined in the dialog.
The ``name`` parameter specifies the name for the newly created parameter.
%End
};
class QgsProcessingParameterDefinitionDialog: QDialog
{
%Docstring
A dialog which allow users to specify the properties of a Processing parameter.
.. versionadded:: 3.10
%End
%TypeHeaderCode
#include "qgsprocessingparameterdefinitionwidget.h"
%End
public:
QgsProcessingParameterDefinitionDialog( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = 0,
const QgsProcessingAlgorithm *algorithm = 0,
QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsProcessingParameterDefinitionDialog, for a parameter of the
specified ``type``.
The ``context`` argument must specify a Processing context, which will be used
by the widget to evaluate existing ``definition`` properties such as default values. Similarly,
the ``widgetContext`` argument specifies the wider GUI context in which the widget
will be used.
The optional ``definition`` argument may be used to provide a parameter definition to use
to initially populate the dialog's state.
Additionally, the optional ``algorithm`` parameter may be used to specify the algorithm or model
associated with the parameter.
%End
QgsProcessingParameterDefinition *createParameter( const QString &name = QString() ) const /Factory/;
%Docstring
Returns a new instance of a parameter definition, using the current settings defined in the dialog.
The ``name`` parameter specifies the name for the newly created parameter.
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessingparameterdefinitionwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -389,6 +389,36 @@ to resolve parameter values which are context dependent. The context must
last for the lifetime of the widget.
.. seealso:: :py:func:`createWidgetWrapper`
%End
virtual QgsProcessingAbstractParameterDefinitionWidget *createParameterDefinitionWidget(
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = 0,
const QgsProcessingAlgorithm *algorithm = 0 ) /Factory/;
%Docstring
Creates a new parameter definition widget allowing for configuration of an instance of
the parameter type handled by this factory.
The ``context`` argument must specify a Processing context, which will be used
by the widget to evaluate existing ``definition`` properties such as default values. Similarly,
the ``widgetContext`` argument specifies the wider GUI context in which the widget
will be used.
The optional ``definition`` argument may specify a parameter definition which
should be reflected in the initial state of the returned widget. Subclasses must
ensure that they correctly handle both the case when a initial ``definition`` is
passed, or when ``definition`` is ``None`` (in which case sensible defaults should
be shown in the returned widget).
Additionally, the optional ``algorithm`` parameter may be used to specify the algorithm or model
associated with the parameter.
If a factory subclass returns ``None`` for this method (i.e. as the base class implemention does),
it indicates that the parameter type cannot be configured via GUI. In this case the parameter
type will not be configurable when users add it as an input to their graphical models.
.. versionadded:: 3.10
%End
protected:

View File

@ -340,6 +340,7 @@
%Include auto_generated/processing/qgsprocessingmaplayercombobox.sip
%Include auto_generated/processing/qgsprocessingmodelerparameterwidget.sip
%Include auto_generated/processing/qgsprocessingmultipleselectiondialog.sip
%Include auto_generated/processing/qgsprocessingparameterdefinitionwidget.sip
%Include auto_generated/processing/qgsprocessingrecentalgorithmlog.sip
%Include auto_generated/processing/qgsprocessingtoolboxmodel.sip
%Include auto_generated/processing/qgsprocessingtoolboxtreeview.sip

View File

@ -86,7 +86,9 @@ from qgis.gui import (QgsMessageBar,
QgsFilterLineEdit,
QgsProcessingToolboxTreeView,
QgsProcessingToolboxProxyModel,
QgsVariableEditorWidget)
QgsProcessingParameterDefinitionDialog,
QgsVariableEditorWidget,
QgsProcessingParameterWidgetContext)
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
@ -96,6 +98,7 @@ from processing.modeler.ModelerScene import ModelerScene
from processing.modeler.ProjectProvider import PROJECT_PROVIDER_ID
from processing.script.ScriptEditorDialog import ScriptEditorDialog
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.dataobjects import createContext
from qgis.utils import iface
@ -787,18 +790,59 @@ class ModelerDialog(BASE, WIDGET):
param = item.data(0, Qt.UserRole)
self.addInputOfType(param)
def create_widget_context(self):
"""
Returns a new widget context for use in the model editor
"""
widget_context = QgsProcessingParameterWidgetContext()
widget_context.setProject(QgsProject.instance())
if iface is not None:
widget_context.setMapCanvas(iface.mapCanvas())
widget_context.setModel(self.model)
return widget_context
def autogenerate_parameter_name(self, parameter):
"""
Automatically generates and sets a new parameter's name, based on the parameter's
description and ensuring that it is unique for the model.
"""
validChars = \
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
safeName = ''.join(c for c in parameter.description() if c in validChars)
name = safeName.lower()
i = 2
while self.model.parameterDefinition(name):
name = safeName.lower() + str(i)
i += 1
parameter.setName(safeName)
def addInputOfType(self, paramType, pos=None):
dlg = ModelerParameterDefinitionDialog(self.model, paramType)
dlg.exec_()
if dlg.param is not None:
new_param = None
if ModelerParameterDefinitionDialog.use_legacy_dialog(paramType=paramType):
dlg = ModelerParameterDefinitionDialog(self.model, paramType)
if dlg.exec_():
new_param = dlg.param
else:
# yay, use new API!
context = createContext()
widget_context = self.create_widget_context()
dlg = QgsProcessingParameterDefinitionDialog(type=paramType,
context=context,
widgetContext=widget_context,
algorithm=self.model)
if dlg.exec_():
new_param = dlg.createParameter()
self.autogenerate_parameter_name(new_param)
if new_param is not None:
if pos is None:
pos = self.getPositionForParameterItem()
if isinstance(pos, QPoint):
pos = QPointF(pos)
component = QgsProcessingModelParameter(dlg.param.name())
component.setDescription(dlg.param.name())
component = QgsProcessingModelParameter(new_param.name())
component.setDescription(new_param.name())
component.setPosition(pos)
self.model.addModelParameter(dlg.param, component)
self.model.addModelParameter(new_param, component)
self.repaintModel()
# self.view.ensureVisible(self.scene.getLastParameterItem())
self.hasChanged = True

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
"""
***************************************************************************
@ -33,9 +34,16 @@ from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingModelParameter,
QgsProcessingModelOutput,
QgsProcessingModelChildAlgorithm,
QgsProcessingModelAlgorithm)
QgsProcessingModelAlgorithm,
QgsProject)
from qgis.gui import (
QgsProcessingParameterDefinitionDialog,
QgsProcessingParameterWidgetContext
)
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
from processing.tools.dataobjects import createContext
from qgis.utils import iface
pluginPath = os.path.split(os.path.dirname(__file__))[0]
@ -227,16 +235,45 @@ class ModelerGraphicItem(QGraphicsItem):
'The selected algorithm depends on other currently non-active algorithms.\n'
'Activate them them before trying to activate it.')
def create_widget_context(self):
"""
Returns a new widget context for use in the model editor
"""
widget_context = QgsProcessingParameterWidgetContext()
widget_context.setProject(QgsProject.instance())
if iface is not None:
widget_context.setMapCanvas(iface.mapCanvas())
widget_context.setModel(self.model)
return widget_context
def editElement(self):
if isinstance(self.element, QgsProcessingModelParameter):
dlg = ModelerParameterDefinitionDialog(self.model,
param=self.model.parameterDefinition(self.element.parameterName()))
if dlg.exec_() and dlg.param is not None:
existing_param = self.model.parameterDefinition(self.element.parameterName())
new_param = None
if ModelerParameterDefinitionDialog.use_legacy_dialog(param=existing_param):
# boo, old api
dlg = ModelerParameterDefinitionDialog(self.model,
param=existing_param)
if dlg.exec_():
new_param = dlg.param
else:
# yay, use new API!
context = createContext()
widget_context = self.create_widget_context()
dlg = QgsProcessingParameterDefinitionDialog(type=existing_param.type(),
context=context,
widgetContext=widget_context,
definition=existing_param,
algorithm=self.model)
if dlg.exec_():
new_param = dlg.createParameter(existing_param.name())
if new_param is not None:
self.model.removeModelParameter(self.element.parameterName())
self.element.setParameterName(dlg.param.name())
self.element.setDescription(dlg.param.name())
self.model.addModelParameter(dlg.param, self.element)
self.text = dlg.param.description()
self.element.setParameterName(new_param.name())
self.element.setDescription(new_param.name())
self.model.addModelParameter(new_param, self.element)
self.text = new_param.description()
self.scene.dialog.repaintModel()
elif isinstance(self.element, QgsProcessingModelChildAlgorithm):
elemAlg = self.element.algorithm()

View File

@ -79,6 +79,49 @@ from processing.modeler.exceptions import UndefinedParameterException
class ModelerParameterDefinitionDialog(QDialog):
@staticmethod
def use_legacy_dialog(param=None, paramType=None):
if paramType in (parameters.PARAMETER_BOOLEAN,
parameters.PARAMETER_TABLE_FIELD,
parameters.PARAMETER_BAND,
parameters.PARAMETER_LAYOUTITEM,
parameters.PARAMETER_VECTOR,
parameters.PARAMETER_TABLE,
parameters.PARAMETER_MULTIPLE,
parameters.PARAMETER_NUMBER,
parameters.PARAMETER_DISTANCE,
parameters.PARAMETER_SCALE,
parameters.PARAMETER_EXPRESSION,
parameters.PARAMETER_STRING,
parameters.PARAMETER_FILE,
parameters.PARAMETER_POINT,
parameters.PARAMETER_CRS,
parameters.PARAMETER_ENUM,
parameters.PARAMETER_MATRIX):
return True
elif isinstance(param, (QgsProcessingParameterBoolean,
QgsProcessingParameterField,
QgsProcessingParameterBand,
QgsProcessingParameterLayoutItem,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterScale,
QgsProcessingParameterExpression,
QgsProcessingParameterString,
QgsProcessingParameterFile,
QgsProcessingParameterPoint,
QgsProcessingParameterCrs,
QgsProcessingParameterEnum,
QgsProcessingParameterMatrix,
QgsProcessingDestinationParameter)):
return True
# yay, use new API!
return False
def __init__(self, alg, paramType=None, param=None):
self.alg = alg
self.paramType = paramType

View File

@ -205,6 +205,7 @@ SET(QGIS_GUI_SRCS
processing/qgsprocessingmatrixparameterdialog.cpp
processing/qgsprocessingmodelerparameterwidget.cpp
processing/qgsprocessingmultipleselectiondialog.cpp
processing/qgsprocessingparameterdefinitionwidget.cpp
processing/qgsprocessingrecentalgorithmlog.cpp
processing/qgsprocessingtoolboxmodel.cpp
processing/qgsprocessingtoolboxtreeview.cpp
@ -780,6 +781,7 @@ SET(QGIS_GUI_MOC_HDRS
processing/qgsprocessingmatrixparameterdialog.h
processing/qgsprocessingmodelerparameterwidget.h
processing/qgsprocessingmultipleselectiondialog.h
processing/qgsprocessingparameterdefinitionwidget.h
processing/qgsprocessingrecentalgorithmlog.h
processing/qgsprocessingtoolboxmodel.h
processing/qgsprocessingtoolboxtreeview.h

View File

@ -130,3 +130,15 @@ QgsProcessingModelerParameterWidget *QgsProcessingGuiRegistry::createModelerPara
return mParameterWidgetFactories.value( parameterType )->createModelerWidgetWrapper( model, childId, parameter, context );
}
QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGuiRegistry::createParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition,
const QgsProcessingAlgorithm *algorithm )
{
if ( !mParameterWidgetFactories.contains( type ) )
return nullptr;
return mParameterWidgetFactories.value( type )->createParameterDefinitionWidget( context, widgetContext, definition, algorithm );
}

View File

@ -29,6 +29,7 @@ class QgsProcessingAlgorithm;
class QgsProcessingAlgorithmConfigurationWidget;
class QgsProcessingAlgorithmConfigurationWidgetFactory;
class QgsProcessingModelerParameterWidget;
class QgsProcessingParameterWidgetContext;
/**
* The QgsProcessingGuiRegistry is a home for widgets for processing
@ -138,6 +139,33 @@ class GUI_EXPORT QgsProcessingGuiRegistry
const QString &childId,
const QgsProcessingParameterDefinition *parameter, QgsProcessingContext &context ) SIP_FACTORY;
/**
* Creates a new parameter definition widget allowing for configuration of an instance of
* a specific parameter \a type.
*
* The \a context argument must specify a Processing context, which will be used
* by the widget to evaluate existing \a definition properties such as default values. Similarly,
* the \a widgetContext argument specifies the wider GUI context in which the widget
* will be used.
*
* The optional \a definition argument may specify an existing parameter definition which
* will be reflected in the initial state of the returned widget. If \a definition is NULLPTR,
* then the returned widget will use default settings instead.
*
* Additionally, the optional \a algorithm parameter may be used to specify the algorithm or model
* associated with the parameter.
*
* If NULLPTR is returned for a particular parameter \a type,
* it indicates that the parameter type cannot be configured via GUI.
*
* \since QGIS 3.10
*/
QgsProcessingAbstractParameterDefinitionWidget *createParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr ) SIP_FACTORY;
private:
QList <QgsProcessingAlgorithmConfigurationWidgetFactory *> mAlgorithmConfigurationWidgetFactories;

View File

@ -0,0 +1,149 @@
/***************************************************************************
qgsprocessingparameterdefinitionwidget.cpp
------------------------------------------
begin : July 2019
copyright : (C) 2019 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsprocessingparameterdefinitionwidget.h"
#include "qgsgui.h"
#include "qgsprocessingguiregistry.h"
#include "qgsapplication.h"
#include "qgsprocessingregistry.h"
#include "qgsprocessingparametertype.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
QgsProcessingAbstractParameterDefinitionWidget::QgsProcessingAbstractParameterDefinitionWidget( QgsProcessingContext &,
const QgsProcessingParameterWidgetContext &,
const QgsProcessingParameterDefinition *,
const QgsProcessingAlgorithm *, QWidget *parent )
: QWidget( parent )
{
}
//
// QgsProcessingParameterDefinitionWidget
//
QgsProcessingParameterDefinitionWidget::QgsProcessingParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition,
const QgsProcessingAlgorithm *algorithm, QWidget *parent )
: QWidget( parent )
, mType( type )
{
mDefinitionWidget = QgsGui::instance()->processingGuiRegistry()->createParameterDefinitionWidget( type, context, widgetContext, definition, algorithm );
QVBoxLayout *vlayout = new QVBoxLayout();
QLabel *label = new QLabel( tr( "Description" ) );
vlayout->addWidget( label );
mDescriptionLineEdit = new QLineEdit();
vlayout->addWidget( mDescriptionLineEdit );
if ( definition )
{
mDescriptionLineEdit->setText( definition->description() );
}
if ( mDefinitionWidget )
vlayout->addWidget( mDefinitionWidget );
vlayout->addSpacing( 20 );
mRequiredCheckBox = new QCheckBox( tr( "Mandatory" ) );
if ( definition )
mRequiredCheckBox->setChecked( !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
else
mRequiredCheckBox->setChecked( true );
vlayout->addWidget( mRequiredCheckBox );
mAdvancedCheckBox = new QCheckBox( tr( "Advanced" ) );
if ( definition )
mAdvancedCheckBox->setChecked( definition->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
else
mAdvancedCheckBox->setChecked( false );
vlayout->addWidget( mAdvancedCheckBox );
vlayout->addStretch();
setLayout( vlayout );
}
QgsProcessingParameterDefinition *QgsProcessingParameterDefinitionWidget::createParameter( const QString &name ) const
{
std::unique_ptr< QgsProcessingParameterDefinition > param;
QgsProcessingParameterDefinition::Flags flags = nullptr;
if ( !mRequiredCheckBox->isChecked() )
flags |= QgsProcessingParameterDefinition::FlagOptional;
if ( mAdvancedCheckBox->isChecked() )
flags |= QgsProcessingParameterDefinition::FlagAdvanced;
if ( mDefinitionWidget )
{
// if a specific definition widget exists, get it to create the parameter (since it will know
// how to set all the additional properties of that parameter, which we don't)
param.reset( mDefinitionWidget->createParameter( name, mDescriptionLineEdit->text(), flags ) );
}
else if ( QgsApplication::processingRegistry()->parameterType( mType ) )
{
// otherwise, just create a default version of the parameter
param.reset( QgsApplication::processingRegistry()->parameterType( mType )->create( name ) );
if ( param )
{
param->setDescription( mDescriptionLineEdit->text() );
param->setFlags( flags );
}
}
return param.release();
}
//
// QgsProcessingParameterDefinitionDialog
//
QgsProcessingParameterDefinitionDialog::QgsProcessingParameterDefinitionDialog( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition,
const QgsProcessingAlgorithm *algorithm,
QWidget *parent )
: QDialog( parent )
{
QVBoxLayout *vLayout = new QVBoxLayout();
mWidget = new QgsProcessingParameterDefinitionWidget( type, context, widgetContext, definition, algorithm );
vLayout->addWidget( mWidget );
QDialogButtonBox *bbox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Ok );
connect( bbox, &QDialogButtonBox::accepted, this, &QgsProcessingParameterDefinitionDialog::accept );
connect( bbox, &QDialogButtonBox::rejected, this, &QgsProcessingParameterDefinitionDialog::reject );
vLayout->addWidget( bbox );
setLayout( vLayout );
setWindowTitle( definition ? tr( "%1 Parameter Definition" ).arg( definition->description() )
: QgsApplication::processingRegistry()->parameterType( type ) ? tr( "%1 Parameter Definition" ).arg( QgsApplication::processingRegistry()->parameterType( type )->name() ) :
tr( "Parameter Definition" ) );
setObjectName( QStringLiteral( "QgsProcessingParameterDefinitionDialog" ) );
QgsGui::enableAutoGeometryRestore( this );
}
QgsProcessingParameterDefinition *QgsProcessingParameterDefinitionDialog::createParameter( const QString &name ) const
{
return mWidget->createParameter( name );
}

View File

@ -0,0 +1,175 @@
/***************************************************************************
qgsprocessingparameterdefinitionwidget.h
----------------------------------------
begin : July 2019
copyright : (C) 2019 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSPROCESSINGPARAMETERDEFINITIONWIDGET_H
#define QGSPROCESSINGPARAMETERDEFINITIONWIDGET_H
#include <QWidget>
#include <QDialog>
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsprocessingparameters.h"
class QgsProcessingParameterWidgetContext;
class QLineEdit;
class QCheckBox;
/**
* Abstract base class for widgets which allow users to specify the properties of a
* Processing parameter.
*
* \ingroup gui
* \since QGIS 3.10
*/
class GUI_EXPORT QgsProcessingAbstractParameterDefinitionWidget : public QWidget
{
Q_OBJECT
public:
/**
* Creates a new QgsProcessingAbstractParameterDefinitionWidget, with the specified \a parent widget.
*
* The \a context argument must specify a Processing context, which will be used
* by the widget to evaluate existing \a definition properties such as default values. Similarly,
* the \a widgetContext argument specifies the wider GUI context in which the widget
* will be used.
*
* The optional \a definition argument may be used to provide a parameter definition to use
* to initially populate the widget's state.
*
* Additionally, the optional \a algorithm parameter may be used to specify the algorithm or model
* associated with the parameter.
*/
QgsProcessingAbstractParameterDefinitionWidget( QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Returns a new instance of a parameter definition, using the current settings defined in the dialog.
*
* Common properties for parameters, including the \a name, \a description, and parameter \a flags are passed to the
* method. Subclass implementations must use these properties when crafting a parameter definition which
* also respects the additional properties specific to the parameter type handled by the widget sublass.
*/
virtual QgsProcessingParameterDefinition *createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const = 0 SIP_FACTORY;
};
/**
* A widget which allow users to specify the properties of a Processing parameter.
*
* \ingroup gui
* \since QGIS 3.10
*/
class GUI_EXPORT QgsProcessingParameterDefinitionWidget: public QWidget
{
Q_OBJECT
public:
/**
* Constructor for QgsProcessingParameterDefinitionWidget, for a parameter of the
* specified \a type.
*
* The \a context argument must specify a Processing context, which will be used
* by the widget to evaluate existing \a definition properties such as default values. Similarly,
* the \a widgetContext argument specifies the wider GUI context in which the widget
* will be used.
*
* The optional \a definition argument may be used to provide a parameter definition to use
* to initially populate the widget's state.
*
* Additionally, the optional \a algorithm parameter may be used to specify the algorithm or model
* associated with the parameter.
*
*/
QgsProcessingParameterDefinitionWidget( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr,
QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Returns a new instance of a parameter definition, using the current settings defined in the dialog.
*
* The \a name parameter specifies the name for the newly created parameter.
*/
QgsProcessingParameterDefinition *createParameter( const QString &name = QString() ) const SIP_FACTORY;
private:
QString mType;
QgsProcessingAbstractParameterDefinitionWidget *mDefinitionWidget = nullptr;
QLineEdit *mDescriptionLineEdit = nullptr;
QCheckBox *mRequiredCheckBox = nullptr;
QCheckBox *mAdvancedCheckBox = nullptr;
};
/**
* A dialog which allow users to specify the properties of a Processing parameter.
*
* \ingroup gui
* \since QGIS 3.10
*/
class GUI_EXPORT QgsProcessingParameterDefinitionDialog: public QDialog
{
Q_OBJECT
public:
/**
* Constructor for QgsProcessingParameterDefinitionDialog, for a parameter of the
* specified \a type.
*
* The \a context argument must specify a Processing context, which will be used
* by the widget to evaluate existing \a definition properties such as default values. Similarly,
* the \a widgetContext argument specifies the wider GUI context in which the widget
* will be used.
*
* The optional \a definition argument may be used to provide a parameter definition to use
* to initially populate the dialog's state.
*
* Additionally, the optional \a algorithm parameter may be used to specify the algorithm or model
* associated with the parameter.
*
*/
QgsProcessingParameterDefinitionDialog( const QString &type,
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr,
QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Returns a new instance of a parameter definition, using the current settings defined in the dialog.
*
* The \a name parameter specifies the name for the newly created parameter.
*/
QgsProcessingParameterDefinition *createParameter( const QString &name = QString() ) const SIP_FACTORY;
private:
QgsProcessingParameterDefinitionWidget *mWidget = nullptr;
};
#endif // QGSPROCESSINGPARAMETERDEFINITIONWIDGET_H

View File

@ -315,6 +315,13 @@ QgsProcessingModelerParameterWidget *QgsProcessingParameterWidgetFactoryInterfac
return widget.release();
}
QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingParameterWidgetFactoryInterface::createParameterDefinitionWidget( QgsProcessingContext &,
const QgsProcessingParameterWidgetContext &, const QgsProcessingParameterDefinition *,
const QgsProcessingAlgorithm * )
{
return nullptr;
}
QString QgsProcessingParameterWidgetFactoryInterface::modelerExpressionFormatString() const
{
return QString();

View File

@ -37,6 +37,7 @@ class QgsVectorLayer;
class QgsProcessingModelAlgorithm;
class QgsMapCanvas;
class QgsProcessingAlgorithm;
class QgsProcessingAbstractParameterDefinitionWidget;
/**
* \class QgsProcessingContextGenerator
@ -452,6 +453,36 @@ class GUI_EXPORT QgsProcessingParameterWidgetFactoryInterface
const QgsProcessingParameterDefinition *parameter,
QgsProcessingContext &context );
/**
* Creates a new parameter definition widget allowing for configuration of an instance of
* the parameter type handled by this factory.
*
* The \a context argument must specify a Processing context, which will be used
* by the widget to evaluate existing \a definition properties such as default values. Similarly,
* the \a widgetContext argument specifies the wider GUI context in which the widget
* will be used.
*
* The optional \a definition argument may specify a parameter definition which
* should be reflected in the initial state of the returned widget. Subclasses must
* ensure that they correctly handle both the case when a initial \a definition is
* passed, or when \a definition is NULLPTR (in which case sensible defaults should
* be shown in the returned widget).
*
* Additionally, the optional \a algorithm parameter may be used to specify the algorithm or model
* associated with the parameter.
*
* If a factory subclass returns NULLPTR for this method (i.e. as the base class implemention does),
* it indicates that the parameter type cannot be configured via GUI. In this case the parameter
* type will not be configurable when users add it as an input to their graphical models.
*
* \since QGIS 3.10
*/
virtual QgsProcessingAbstractParameterDefinitionWidget *createParameterDefinitionWidget(
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr ) SIP_FACTORY;
protected:
/**

View File

@ -21,6 +21,7 @@
#define SIP_NO_FILE
#include "qgsprocessingwidgetwrapper.h"
#include "qgsprocessingparameterdefinitionwidget.h"
#include "qgsmaptool.h"
#include <QAbstractButton>

View File

@ -62,6 +62,7 @@
#include "mesh/qgsmeshlayer.h"
#include "mesh/qgsmeshdataprovider.h"
#include "qgscolorbutton.h"
#include "qgsprocessingparameterdefinitionwidget.h"
class TestParamType : public QgsProcessingParameterDefinition
{
@ -187,6 +188,7 @@ class TestProcessingGui : public QObject
void testPointWrapper();
void testColorWrapper();
void mapLayerComboBox();
void paramConfigWidget();
private:
@ -3546,6 +3548,34 @@ void TestProcessingGui::mapLayerComboBox()
QgsProject::instance()->removeAllMapLayers();
}
void TestProcessingGui::paramConfigWidget()
{
QgsProcessingContext context;
QgsProcessingParameterWidgetContext widgetContext;
std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext );
std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
// using a parameter definition as initial values
def->setDescription( QStringLiteral( "test desc" ) );
def->setFlags( QgsProcessingParameterDefinition::FlagOptional );
widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, def.get() );
def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
def->setFlags( QgsProcessingParameterDefinition::FlagAdvanced );
widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, def.get() );
def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
}
void TestProcessingGui::cleanupTempDir()
{
QDir tmpDir = QDir( mTempDir );