Begin port of modeler algorithm to c++

This commit is contained in:
Nyall Dawson 2017-06-13 16:05:59 +10:00
parent efe8bba006
commit f6358b2118
17 changed files with 2154 additions and 367 deletions

View File

@ -288,6 +288,7 @@
%Include processing/qgsprocessingalgrunnertask.sip
%Include processing/qgsprocessingcontext.sip
%Include processing/qgsprocessingfeedback.sip
%Include processing/qgsprocessingmodelalgorithm.sip
%Include processing/qgsprocessingoutputs.sip
%Include processing/qgsprocessingparameters.sip
%Include processing/qgsprocessingprovider.sip

View File

@ -276,6 +276,12 @@ class QgsProcessingAlgorithm
:rtype: bool
%End
void removeParameter( const QString &name );
%Docstring
Removes the parameter with matching ``name`` from the algorithm, and deletes any existing
definition.
%End
bool addOutput( QgsProcessingOutputDefinition *outputDefinition /Transfer/ );
%Docstring
Adds an output ``definition`` to the algorithm. Ownership of the definition is transferred to the algorithm.

View File

@ -0,0 +1,617 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/processing/qgsprocessingmodelalgorithm.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
{
%Docstring
Model based algorithm with processing.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
class ChildParameterSource
{
%Docstring
Source for the value of a parameter for a child algorithm within a model.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
enum Source
{
ModelParameter,
ChildOutput,
StaticValue,
};
ChildParameterSource();
%Docstring
Constructor for ChildParameterSource. It is recommended that the static methods
fromStaticValue(), fromModelParameter() and fromChildOutput() are used instead.
%End
bool operator==( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const;
bool operator!=( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const;
%Docstring
:rtype: bool
%End
static QgsProcessingModelAlgorithm::ChildParameterSource fromStaticValue( const QVariant &value );
%Docstring
Returns a new ChildParameterSource which takes its value from a static ``value``.
.. seealso:: fromModelParameter()
.. seealso:: fromChildOutput()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End
static QgsProcessingModelAlgorithm::ChildParameterSource fromModelParameter( const QString &parameterName );
%Docstring
Returns a new ChildParameterSource which takes its value from a parent model parameter.
.. seealso:: fromStaticValue()
.. seealso:: fromChildOutput()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End
static QgsProcessingModelAlgorithm::ChildParameterSource fromChildOutput( const QString &childId, const QString &outputName );
%Docstring
Returns a new ChildParameterSource which takes its value from an output generated by a child algorithm.
.. seealso:: fromStaticValue()
.. seealso:: fromModelParameter()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End
Source source() const;
%Docstring
Returns the parameter value's source.
:rtype: Source
%End
QVariant staticValue() const;
%Docstring
Returns the source's static value. This is only used when the source() is StaticValue.
.. seealso:: setStaticValue()
:rtype: QVariant
%End
void setStaticValue( const QVariant &value );
%Docstring
Sets the source's static value. Calling this will also change the source() to StaticValue.
.. seealso:: staticValue()
%End
QString parameterName() const;
%Docstring
Returns the source's model parameter name. This is only used when the source() is ModelParameter.
.. seealso:: setParameterName()
:rtype: str
%End
void setParameterName( const QString &name );
%Docstring
Sets the source's model parameter ``name``. Calling this will also change the source() to ModelParameter.
.. seealso:: parameterName()
%End
QString outputChildId() const;
%Docstring
Returns the source's child algorithm ID from which the output value will be taken. This is only used when the source() is ChildOutput.
.. seealso:: setOutputChildId()
.. seealso:: outputName()
:rtype: str
%End
void setOutputChildId( const QString &id );
%Docstring
Sets the source's child algorithm ``id`` from which the output value will be taken. Calling this will also change the source() to ChildOutput.
.. seealso:: parameterName()
.. seealso:: setOutputName()
%End
QString outputName() const;
%Docstring
Returns the source's child algorithm output name from which the output value will be taken. This is only used when the source() is ChildOutput.
.. seealso:: setOutputName()
.. seealso:: outputChildId()
:rtype: str
%End
void setOutputName( const QString &name );
%Docstring
Sets the source's child algorithm output ``name`` from which the output value will be taken. Calling this will also change the source() to ChildOutput.
.. seealso:: outputName()
.. seealso:: setOutputChildId()
%End
};
class Component
{
%Docstring
Represents a component of a model algorithm.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
QString description() const;
%Docstring
Returns the friendly description text for the component.
.. seealso:: setDescription()
:rtype: str
%End
void setDescription( const QString &description );
%Docstring
Sets the friendly ``description`` text for the component.
.. seealso:: description()
%End
QPointF position() const;
%Docstring
Returns the position of the model component within the graphical modeler.
.. seealso:: setPosition()
:rtype: QPointF
%End
void setPosition( const QPointF &position );
%Docstring
Sets the ``position`` of the model component within the graphical modeler.
.. seealso:: position()
%End
protected:
Component( const QString &description = QString() );
%Docstring
Only subclasses can be created
%End
Component( const QgsProcessingModelAlgorithm::Component &other );
%Docstring
Copies are protected to avoid slicing
%End
};
class ModelParameter : QgsProcessingModelAlgorithm::Component
{
%Docstring
Represents an input parameter used by the model.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
ModelParameter( const QString &parameterName = QString() );
%Docstring
Constructor for ModelParameter. The parameter name should match one of the
parameters from the parent model.
%End
QString parameterName() const;
%Docstring
Returns the associated parameter name. The parameter name should match one of the
parameters from the parent model.
.. seealso:: parameterName()
:rtype: str
%End
void setParameterName( const QString &name );
%Docstring
Sets the associated parameter name. The parameter name should match one of the
parameters from the parent model.
.. seealso:: parameterName()
%End
};
class ModelOutput : QgsProcessingModelAlgorithm::Component
{
%Docstring
Represents a final output created by the model.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
ModelOutput( const QString &description = QString() );
%Docstring
Constructor for ModelOutput with the specified ``description``.
%End
QString childId() const;
%Docstring
Returns the child algorithm ID from which this output is generated.
.. seealso:: setChildId()
:rtype: str
%End
void setChildId( const QString &id );
%Docstring
Sets the child algorithm ``id`` from which this output is generated.
.. seealso:: childId()
%End
QString outputName() const;
%Docstring
Returns the child algorithm output name from which this output is generated.
.. seealso:: setOutputName()
:rtype: str
%End
void setOutputName( const QString &name );
%Docstring
Sets the child algorithm output ``name`` from which this output is generated.
.. seealso:: outputName()
%End
};
class ChildAlgorithm : QgsProcessingModelAlgorithm::Component
{
%Docstring
Child algorithm representing a single component of a QgsProcessingModelAlgorithm.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingmodelalgorithm.h"
%End
public:
ChildAlgorithm( const QString &algorithmId = QString() );
%Docstring
Constructor for ChildAlgorithm. The ``algorithmId`` parameter
should be set to a QgsProcessingAlgorithm algorithm ID.
%End
QString childId() const;
%Docstring
Returns the child algorithm's unique ID string, used the identify
this child algorithm within its parent model.
.. seealso:: setChildId()
.. seealso:: generateChildId()
:rtype: str
%End
void setChildId( const QString &id );
%Docstring
Sets the child algorithm's unique ``id`` string, used the identify
this child algorithm within its parent model.
.. seealso:: childId()
.. seealso:: generateChildId()
%End
void generateChildId( const QgsProcessingModelAlgorithm &model );
%Docstring
Automatically generates a unique childId() for the algorithm,
avoiding child IDs which are already present in ``model``.
.. seealso:: childId()
.. seealso:: setChildId()
%End
QString algorithmId() const;
%Docstring
Returns the underlying child algorithm's ID.
.. seealso:: algorithm()
.. seealso:: setAlgorithmId()
:rtype: str
%End
void setAlgorithmId( const QString &algorithmId );
%Docstring
Sets the underlying child algorithm's ID. This
should be set to an existing QgsProcessingAlgorithm algorithm ID.
.. seealso:: algorithm()
.. seealso:: algorithmId()
%End
const QgsProcessingAlgorithm *algorithm() const;
%Docstring
Returns the underlying child algorithm, or a None
if a matching algorithm is not available.
.. seealso:: algorithmId()
:rtype: QgsProcessingAlgorithm
%End
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > parameterSources() const;
%Docstring
Returns a map of parameter sources. The keys are the child algorithm
parameter names, the values are the source for that parameter.
.. seealso:: setParameterSources()
.. seealso:: addParameterSource()
:rtype: QMap< str, QgsProcessingModelAlgorithm.ChildParameterSource >
%End
void setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &sources );
%Docstring
Sets the map of parameter ``sources``. The keys are the child algorithm
parameter names, the values are the source for that parameter.
.. seealso:: parameterSources()
.. seealso:: addParameterSource()
%End
void addParameterSource( const QString &name, const QgsProcessingModelAlgorithm::ChildParameterSource &source );
%Docstring
Adds a parameter source. The ``name`` argument should match
one of the child algorithm's parameter names, and the ``source``
argument is used to set the source for that parameter.
Any existing parameter source with matching name will be replaced.
.. seealso:: parameterSources()
.. seealso:: setParameterSources()
%End
bool isActive() const;
%Docstring
Returns true if the child algorithm is active.
.. seealso:: setActive()
:rtype: bool
%End
void setActive( bool active );
%Docstring
Sets whether the child algorithm is active.
.. seealso:: isActive()
%End
QStringList dependencies() const;
%Docstring
Returns the list of child algorithms from the parent model on which this
algorithm is dependent. The returned list contains the id() of the
dependent algorithms.
.. seealso:: setDependencies()
:rtype: list of str
%End
void setDependencies( const QStringList &dependencies );
%Docstring
Sets the list of child algorithms from the parent model on which this
algorithm is dependent. The list should contain the id() of the
dependent algorithms.
.. seealso:: dependencies()
%End
bool parametersCollapsed() const;
%Docstring
Returns true if the list of parameters for this algorithm should be collapsed
in the graphical modeller.
.. seealso:: setParametersCollapsed()
.. seealso:: outputsCollapsed()
:rtype: bool
%End
void setParametersCollapsed( bool collapsed );
%Docstring
Sets whether the list of parameters for this algorithm should be collapsed
in the graphical modeller.
.. seealso:: parametersCollapsed()
.. seealso:: setOutputsCollapsed()
%End
bool outputsCollapsed() const;
%Docstring
Returns true if the list of outputs for this algorithm should be collapsed
in the graphical modeller.
.. seealso:: setParametersCollapsed()
.. seealso:: parametersCollapsed()
:rtype: bool
%End
void setOutputsCollapsed( bool collapsed );
%Docstring
Sets whether the list of outputs for this algorithm should be collapsed
in the graphical modeller.
.. seealso:: outputsCollapsed()
.. seealso:: setParametersCollapsed()
%End
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> modelOutputs() const;
%Docstring
Returns the map of final model outputs which are generated by this child algorithm.
The keys are the output names from this child algorithm. Only outputs which are
part of the final outputs from the model are included in this map.
.. seealso:: setModelOutputs()
.. seealso:: modelOutput()
:rtype: QMap<str, QgsProcessingModelAlgorithm.ModelOutput>
%End
QgsProcessingModelAlgorithm::ModelOutput &modelOutput( const QString &name );
%Docstring
Returns the final model output with matching ``name``. If no output
exists with the name, a new one will be created and returned.
.. seealso:: modelOutputs()
.. seealso:: setModelOutputs()
:rtype: QgsProcessingModelAlgorithm.ModelOutput
%End
void setModelOutputs( const QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> &outputs );
%Docstring
Sets the map of final model ``outputs`` which are generated by this child algorithm.
The keys are the output names from this child algorithm. Only outputs which are
part of the final outputs from the model should be included in this map.
.. seealso:: modelOutputs()
%End
};
QgsProcessingModelAlgorithm( const QString &name = QString(), const QString &group = QString() );
%Docstring
Constructor for QgsProcessingModelAlgorithm.
%End
virtual QString name() const;
virtual QString displayName() const;
virtual QString group() const;
virtual QIcon icon() const;
virtual QString svgIconPath() const;
virtual bool canExecute( QString *errorMessage /Out/ = 0 ) const;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const;
QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> childAlgorithms() const;
%Docstring
Returns the map of child algorithms contained in the model. The keys
are the child algorithm ids (see QgsProcessingModelAlgorithm.ChildAlgorithm.childId()).
.. seealso:: childAlgorithm()
.. seealso:: setChildAlgorithms()
.. seealso:: addChildAlgorithm()
:rtype: QMap<str, QgsProcessingModelAlgorithm.ChildAlgorithm>
%End
void setChildAlgorithms( const QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> &childAlgorithms );
%Docstring
Sets the map of child algorithms contained in the model. The keys
are the child algorithm ids (see QgsProcessingModelAlgorithm.ChildAlgorithm.childId()).
All existing child algorithms will be replaced.
.. seealso:: childAlgorithms()
.. seealso:: childAlgorithm()
.. seealso:: setChildAlgorithm()
.. seealso:: addChildAlgorithm()
%End
void setChildAlgorithm( const QgsProcessingModelAlgorithm::ChildAlgorithm &algorithm );
%Docstring
Sets the child ``algorithm`` within the model. If a child algorithm already
exists in the model with the same child ID then that algorithm will be replaced.
.. seealso:: addChildAlgorithm()
.. seealso:: setChildAlgorithms()
%End
QString addChildAlgorithm( QgsProcessingModelAlgorithm::ChildAlgorithm &algorithm );
%Docstring
Adds a new child ``algorithm`` to the model. If a child algorithm already exists
in the model with the same child ID then ``algorithm`` will be assigned a new
autogenerated unique ID.
The assigned child ID will be returned.
.. seealso:: childAlgorithms()
.. seealso:: childAlgorithm()
.. seealso:: setChildAlgorithm()
.. seealso:: setChildAlgorithms()
:rtype: str
%End
QgsProcessingModelAlgorithm::ChildAlgorithm &childAlgorithm( const QString &id );
%Docstring
Returns the child algorithm with matching ``id``. If no child algorithm exists with
this ID a new algorithm will be added to the model and returned.
.. seealso:: addChildAlgorithm()
.. seealso:: childAlgorithms()
:rtype: QgsProcessingModelAlgorithm.ChildAlgorithm
%End
void addModelParameter( QgsProcessingParameterDefinition *definition /Transfer/, const QgsProcessingModelAlgorithm::ModelParameter &component );
%Docstring
Adds a new parameter to the model, with the specified ``definition`` and graphical ``component``.
Ownership of ``definition`` is transferred to the model.
.. seealso:: updateModelParameter()
.. seealso:: removeModelParameter()
%End
void updateModelParameter( QgsProcessingParameterDefinition *definition /Transfer/ );
%Docstring
Replaces the definition of an existing parameter (by parameter name) with a new ``definition``. Ownership of
``definition`` is transferred to the model, and any existing parameter is deleted.
.. seealso:: addModelParameter()
.. seealso:: removeModelParameter()
%End
void removeModelParameter( const QString &name );
%Docstring
Removes an existing model parameter by ``name``. The definition of the matching parameter
is deleted.
.. seealso:: addModelParameter()
.. seealso:: updateModelParameter()
%End
QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> parameterComponents() const;
%Docstring
Returns the map of parameter components used by the model. The keys
should match the algorithm's parameter names (see parameterDefinitions() ).
.. seealso:: setParameterComponent()
.. seealso:: parameterComponent()
:rtype: QMap<str, QgsProcessingModelAlgorithm.ModelParameter>
%End
void setParameterComponents( const QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> &parameterComponents );
%Docstring
Sets the map of parameter components used by the model. The keys
should match the algorithm's parameter names (see parameterDefinitions() ).
All existing parameter components will be replaced.
.. seealso:: parameterComponents()
.. seealso:: setParameterComponent()
.. seealso:: parameterComponent()
%End
void setParameterComponent( const QgsProcessingModelAlgorithm::ModelParameter &component );
%Docstring
Sets a parameter ``component`` for the model. If a parameter component already
exists in the model with the same parameter name then that component will be replaced.
.. seealso:: parameterComponents()
.. seealso:: setParameterComponents()
.. seealso:: parameterComponent()
%End
QgsProcessingModelAlgorithm::ModelParameter &parameterComponent( const QString &name );
%Docstring
Returns the parameter component with matching ``name``. If no parameter component exists with
this name a new component will be added to the model and returned.
.. seealso:: parameterComponents()
.. seealso:: setParameterComponents()
.. seealso:: setParameterComponent()
:rtype: QgsProcessingModelAlgorithm.ModelParameter
%End
QStringList dependentChildAlgorithms( const QString &childId ) const;
%Docstring
:rtype: list of str
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/processing/qgsprocessingmodelalgorithm.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -65,7 +65,8 @@ from qgis.core import (
QgsProcessingOutputRasterLayer,
QgsProcessingOutputVectorLayer,
QgsProcessingOutputString,
QgsProcessingOutputNumber)
QgsProcessingOutputNumber,
QgsProcessingModelAlgorithm)
from qgis.PyQt.QtWidgets import (
QCheckBox,

View File

@ -36,6 +36,7 @@ from qgis.PyQt.QtCore import QPointF
from operator import attrgetter
from qgis.core import (QgsApplication,
QgsProcessingAlgorithm,
QgsProcessingParameterDefinition,
QgsProcessingParameterBoolean,
QgsProcessingParameterCrs,
@ -53,10 +54,10 @@ from qgis.core import (QgsApplication,
QgsProcessingParameterExpression,
QgsProcessingParameterTable,
QgsProcessingParameterTableField,
QgsProcessingParameterFeatureSource)
QgsProcessingParameterFeatureSource,
QgsProcessingModelAlgorithm)
from qgis.gui import QgsMessageBar
from qgis.utils import iface
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.modeler.WrongModelException import WrongModelException
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
@ -65,85 +66,26 @@ from processing.gui.Help2Html import getHtmlFromDescriptionsDict
pluginPath = os.path.split(os.path.dirname(__file__))[0]
class ModelerParameter(object):
class Algorithm(QgsProcessingModelAlgorithm.ChildAlgorithm):
def __init__(self, param=None, pos=None):
self.param = param
self.pos = pos
def todict(self):
return self.__dict__
@staticmethod
def fromdict(d):
return ModelerParameter(d["param"], d["pos"])
class ModelerOutput(object):
def __init__(self, description=""):
self.description = description
self.pos = None
def todict(self):
return self.__dict__
class Algorithm(object):
def __init__(self, consoleName=""):
self.name = None
self.description = ""
# The type of the algorithm, indicated as a string, which corresponds
# to the string used to refer to it in the python console
self.consoleName = consoleName
self._algInstance = None
# A dict of Input object. keys are param names
self.params = {}
# A dict of ModelerOutput with final output descriptions. Keys are output names.
# Outputs not final are not stored in this dict
self.outputs = {}
self.pos = None
self.dependencies = []
self.paramsFolded = True
self.outputsFolded = True
self.active = True
def __init__(self, consoleName=None):
super().__init__(consoleName)
def todict(self):
return {k: v for k, v in list(self.__dict__.items()) if not k.startswith("_")}
@property
def algorithm(self):
if self._algInstance is None:
self._algInstance = QgsApplication.processingRegistry().algorithmById(self.consoleName)
return self._algInstance
def setName(self, model):
if self.name is None:
i = 1
name = self.consoleName + "_" + str(i)
while name in model.algs:
i += 1
name = self.consoleName + "_" + str(i)
self.name = name
def getOutputType(self, outputName):
output = self.algorithm.getOutputFromName(outputName)
output = self.algorithm().outputDefinition(outputName)
return "output " + output.__class__.__name__.split(".")[-1][6:].lower()
def toPython(self):
s = []
params = []
for param in self.algorithm.parameters:
value = self.params[param.name]
if not self.algorithm():
return None
for param in self.algorithm().parameterDefinitions():
value = self.parameterSources()[param.name()]
def _toString(v):
if isinstance(v, (ValueFromInput, ValueFromOutput)):
@ -155,13 +97,13 @@ class Algorithm(object):
else:
return str(value)
params.append(_toString(value))
for out in self.algorithm.outputs:
for out in self.algorithm().outputs:
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
if out.name() in self.outputs:
params.append(safeName(self.outputs[out.name()].description()).lower())
else:
params.append(str(None))
s.append("outputs_%s=processing.run('%s', %s)" % (self.name, self.consoleName, ",".join(params)))
s.append("outputs_%s=processing.run('%s', %s)" % (self.childId(), self.algorithmId(), ",".join(params)))
return s
@ -230,88 +172,31 @@ class CompoundValue(object):
return "" # TODO
class ModelerAlgorithm(GeoAlgorithm):
class ModelerAlgorithm(QgsProcessingModelAlgorithm):
CANVAS_SIZE = 4000
def __init__(self):
self._name = self.tr('Model', 'ModelerAlgorithm')
super().__init__()
# The dialog where this model is being edited
self.modelerdialog = None
self.descriptionFile = None
self.helpContent = {}
self._group = ''
# Geoalgorithms in this model. A dict of Algorithm objects, with names as keys
self.algs = {}
# Input parameters. A dict of Input objects, with names as keys
self.inputs = {}
GeoAlgorithm.__init__(self)
classes = [c for c in QgsProcessingParameterDefinition.__subclasses__()]
self.parameters = []
for c in classes:
for inp in list(self.inputs.values()):
if isinstance(inp.param, c):
self.parameters.append(inp.param)
for inp in list(self.inputs.values()):
if inp.param not in self.parameters:
self.parameters.append(inp.param)
self.parameters.sort(key=attrgetter("description"))
self.outputs = []
for alg in list(self.algs.values()):
if alg.active:
for out in alg.outputs:
modelOutput = copy.deepcopy(alg.algorithm.getOutputFromName(out))
modelOutput.name = self.getSafeNameForOutput(alg.modeler_name, out)
modelOutput.description = alg.outputs[out].description()
self.outputs.append(modelOutput)
self.outputs.sort(key=attrgetter("description"))
def name(self):
return self._name
def displayName(self):
return self._name
def group(self):
return self._group
def icon(self):
return QgsApplication.getThemeIcon("/processingModel.svg")
def svgIconPath(self):
return QgsApplication.iconPath("processingModel.svg")
def addParameter(self, param):
self.inputs[param.param.name()] = param
def updateParameter(self, param):
self.inputs[param.name()].param = param
def addAlgorithm(self, alg):
name = self.getNameForAlgorithm(alg)
alg.modeler_name = name
self.algs[name] = alg
def getNameForAlgorithm(self, alg):
i = 1
while alg.consoleName.upper().replace(":", "") + "_" + str(i) in list(self.algs.keys()):
i += 1
return alg.consoleName.upper().replace(":", "") + "_" + str(i)
def updateAlgorithm(self, alg):
alg.pos = self.algs[alg.modeler_name].pos
alg.paramsFolded = self.algs[alg.modeler_name].paramsFolded
alg.outputsFolded = self.algs[alg.modeler_name].outputsFolded
self.algs[alg.modeler_name] = alg
alg.setPosition(self.childAlgorithm(alg.childId()).position())
alg.setParametersCollapsed(self.childAlgorithm(alg.childId()).parametersCollapsed())
alg.setOutputsCollapsed(self.childAlgorithm(alg.childId()).outputsCollapsed())
self.setChildAlgorithm(alg)
from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
for i, out in enumerate(alg.outputs):
alg.outputs[out].pos = (alg.outputs[out].pos or
alg.pos + QPointF(
for i, out in enumerate(alg.modelOutputs().keys()):
alg.modelOutput(out).setPosition(alg.modelOutput(out).position() or
alg.position() + QPointF(
ModelerGraphicItem.BOX_WIDTH,
(i + 1.5) * ModelerGraphicItem.BOX_HEIGHT))
@ -331,7 +216,7 @@ class ModelerAlgorithm(GeoAlgorithm):
"""
if self.hasDependencies(name):
return False
del self.inputs[name]
self.removeModelParameter(name)
self.modelerdialog.hasChanged = True
return True
@ -357,8 +242,8 @@ class ModelerAlgorithm(GeoAlgorithm):
elif isinstance(value, ValueFromOutput):
if value.alg == name:
return True
if alg.modeler_name != name:
for dep in alg.dependencies:
if alg.childId() != name:
for dep in alg.dependencies():
if (dep == name):
return True
return False
@ -369,7 +254,7 @@ class ModelerAlgorithm(GeoAlgorithm):
"""
alg = self.algs[name]
algs = set()
algs.update(set(alg.dependencies))
algs.update(set(alg.dependencies()))
for value in list(alg.params.values()):
if value is None:
continue
@ -402,23 +287,14 @@ class ModelerAlgorithm(GeoAlgorithm):
if isinstance(value, list):
for v in value:
if isinstance(v, ValueFromOutput) and v.alg == name:
algs.update(self.getDependentAlgorithms(alg.modeler_name))
algs.update(self.getDependentAlgorithms(alg.childId()))
elif isinstance(value, ValueFromOutput) and value.alg == name:
algs.update(self.getDependentAlgorithms(alg.modeler_name))
algs.update(self.getDependentAlgorithms(alg.childId()))
return algs
def setPositions(self, paramPos, algPos, outputsPos):
for param, pos in list(paramPos.items()):
self.inputs[param].pos = pos
for alg, pos in list(algPos.items()):
self.algs[alg].pos = pos
for alg, positions in list(outputsPos.items()):
for output, pos in list(positions.items()):
self.algs[alg].outputs[output].pos = pos
def prepareAlgorithm(self, alg):
algInstance = alg.algorithm
algInstance = alg.algorithm()
for param in algInstance.parameterDefinitions():
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden:
if param.name() in alg.params:
@ -441,10 +317,11 @@ class ModelerAlgorithm(GeoAlgorithm):
# )
# )
for out in algInstance.outputs:
# note to self - these are parameters, not outputs
for out in algInstance.outputDefinitions():
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
if out.name() in alg.outputs:
name = self.getSafeNameForOutput(alg.modeler_name, out.name())
name = self.getSafeNameForOutput(alg.childId(), out.name())
modelOut = self.getOutputFromName(name)
if modelOut:
out.value = modelOut.value
@ -456,14 +333,14 @@ class ModelerAlgorithm(GeoAlgorithm):
def deactivateAlgorithm(self, algName):
dependent = self.getDependentAlgorithms(algName)
for alg in dependent:
self.algs[alg].active = False
self.algs[alg].setActive(False)
def activateAlgorithm(self, algName):
parents = self.getDependsOnAlgorithms(algName)
for alg in parents:
if not self.algs[alg].active:
if not self.childAlgorithm(alg).isActive():
return False
self.algs[algName].active = True
self.childAlgorithm(algName).setActive(True)
return True
def getSafeNameForOutput(self, algName, outName):
@ -479,47 +356,47 @@ class ModelerAlgorithm(GeoAlgorithm):
elif isinstance(value, ValueFromInput):
v = self.getParameterFromName(value.name).value
elif isinstance(value, ValueFromOutput):
v = self.algs[value.alg].algorithm.getOutputFromName(value.output).value
v = self.algs[value.alg].algorithm().outputDefinition(value.output).value
else:
v = value
return param.evaluateForModeler(v, self)
def processAlgorithm(self, parameters, context, feedback):
executed = []
toExecute = [alg for alg in list(self.algs.values()) if alg.active]
toExecute = [alg for alg in list(self.algs.values()) if alg.isActive()]
while len(executed) < len(toExecute):
for alg in toExecute:
if alg.modeler_name not in executed:
if alg.childId() not in executed:
canExecute = True
required = self.getDependsOnAlgorithms(alg.modeler_name)
required = self.getDependsOnAlgorithms(alg.childId())
for requiredAlg in required:
if requiredAlg != alg.modeler_name and requiredAlg not in executed:
if requiredAlg != alg.childId() and requiredAlg not in executed:
canExecute = False
break
if canExecute:
try:
feedback.pushDebugInfo(
self.tr('Prepare algorithm: {0}', 'ModelerAlgorithm').format(alg.modeler_name))
self.tr('Prepare algorithm: {0}', 'ModelerAlgorithm').format(alg.childId()))
self.prepareAlgorithm(alg)
feedback.setProgressText(
self.tr('Running {0} [{1}/{2}]', 'ModelerAlgorithm').format(alg.description, len(executed) + 1, len(toExecute)))
feedback.pushDebugInfo('Parameters: ' + ', '.join([str(p).strip() +
'=' + str(p.value) for p in alg.algorithm.parameters]))
t0 = time.time()
alg.algorithm.execute(parameters, context, feedback)
alg.algorithm().execute(parameters, context, feedback)
dt = time.time() - t0
# copy algorithm output value(s) back to model in case the algorithm modified those
for out in alg.algorithm.outputs:
for out in alg.algorithm().outputs:
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
if out.name() in alg.outputs:
modelOut = self.getOutputFromName(self.getSafeNameForOutput(alg.modeler_name, out.name()))
if out.name() in alg.modelOutputs():
modelOut = self.getOutputFromName(self.getSafeNameForOutput(alg.childId(), out.name()))
if modelOut:
modelOut.value = out.value
executed.append(alg.modeler_name)
executed.append(alg.childId())
feedback.pushDebugInfo(
self.tr('OK. Execution took %{0:.3f} ms ({1} outputs).', 'ModelerAlgorithm').format(dt, len(alg.algorithm.outputs)))
self.tr('OK. Execution took %{0:.3f} ms ({1} outputs).', 'ModelerAlgorithm').format(dt, len(alg.algorithm.modelOutputs())))
except GeoAlgorithmExecutionException as e:
feedback.pushDebugInfo(self.tr('Failed', 'ModelerAlgorithm'))
raise GeoAlgorithmExecutionException(
@ -534,13 +411,6 @@ class ModelerAlgorithm(GeoAlgorithm):
else:
return None
def canExecute(self):
for alg in list(self.algs.values()):
algInstance = QgsApplication.processingRegistry().algorithmById(alg.consoleName)
if algInstance is None:
return False, self.tr("The model you are trying to run contains an algorithm that is not available: <i>{0}</i>").format(alg.consoleName)
return True, None
def setModelerView(self, dialog):
self.modelerdialog = dialog
@ -642,26 +512,26 @@ class ModelerAlgorithm(GeoAlgorithm):
def toPython(self):
s = ['##%s=name' % self.name()]
for param in list(self.inputs.values()):
for param in list(self.parameterComponents().values()):
s.append(param.param.getAsScriptCode())
for alg in list(self.algs.values()):
for name, out in list(alg.outputs.items()):
for name, out in list(alg.modelOutputs().items()):
s.append('##%s=%s' % (safeName(out.description()).lower(), alg.getOutputType(name)))
executed = []
toExecute = [alg for alg in list(self.algs.values()) if alg.active]
toExecute = [alg for alg in list(self.algs.values()) if alg.isActive()]
while len(executed) < len(toExecute):
for alg in toExecute:
if alg.modeler_name not in executed:
if alg.childId() not in executed:
canExecute = True
required = self.getDependsOnAlgorithms(alg.modeler_name)
required = self.getDependsOnAlgorithms(alg.childId())
for requiredAlg in required:
if requiredAlg != alg.modeler_name and requiredAlg not in executed:
if requiredAlg != alg.childId() and requiredAlg not in executed:
canExecute = False
break
if canExecute:
s.extend(alg.toPython())
executed.append(alg.modeler_name)
executed.append(alg.childId())
return '\n'.join(s)

View File

@ -46,11 +46,11 @@
***************************************************************************
"""
from qgis.core import QgsProcessingModelAlgorithm
from qgis.PyQt.QtCore import Qt, QPointF
from qgis.PyQt.QtWidgets import QGraphicsPathItem, QGraphicsItem
from qgis.PyQt.QtGui import QPen, QPainterPath, QPolygonF, QPainter
from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
from processing.modeler.ModelerAlgorithm import Algorithm
class ModelerArrowItem(QGraphicsPathItem):
@ -75,7 +75,7 @@ class ModelerArrowItem(QGraphicsPathItem):
controlPoints = []
endPt = self.endItem.getLinkPointForParameter(self.endIndex)
startPt = self.startItem.getLinkPointForOutput(self.startIndex)
if isinstance(self.startItem.element, Algorithm):
if isinstance(self.startItem.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
if self.startIndex != -1:
controlPoints.append(self.startItem.pos() + startPt)
controlPoints.append(self.startItem.pos() + startPt +

View File

@ -29,6 +29,7 @@ __revision__ = '$Format:%H$'
import codecs
import sys
import os
import math
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QByteArray, QSize, QSizeF, pyqtSignal
@ -40,12 +41,13 @@ from qgis.core import (QgsApplication,
QgsProcessingAlgorithm,
QgsSettings,
QgsMessageLog,
QgsProcessingUtils)
QgsProcessingUtils,
QgsProcessingModelAlgorithm)
from qgis.gui import QgsMessageBar
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm, ModelerParameter
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
from processing.modeler.ModelerUtils import ModelerUtils
from processing.modeler.ModelerScene import ModelerScene
@ -62,7 +64,7 @@ class ModelerDialog(BASE, WIDGET):
update_model = pyqtSignal()
def __init__(self, alg=None):
def __init__(self, model=None):
super(ModelerDialog, self).__init__(None)
self.setupUi(self)
@ -128,6 +130,11 @@ class ModelerDialog(BASE, WIDGET):
settings = QgsSettings()
factor = settings.value('/qgis/zoom_favor', 2.0)
# "Normal" mouse has an angle delta of 120, precision mouses provide data
# faster, in smaller steps
factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y())
if (event.modifiers() == Qt.ControlModifier):
factor = 1.0 + (factor - 1.0) / 20.0
@ -135,7 +142,6 @@ class ModelerDialog(BASE, WIDGET):
factor = 1 / factor
self.view.scale(factor, factor)
self.repaintModel()
def _enterEvent(e):
QGraphicsView.enterEvent(self.view, e)
@ -228,21 +234,21 @@ class ModelerDialog(BASE, WIDGET):
self.mActionEditHelp.triggered.connect(self.editHelp)
self.mActionRun.triggered.connect(self.runModel)
if alg is not None:
self.alg = alg
self.textGroup.setText(alg._group)
self.textName.setText(alg.displayName())
if model is not None:
self.model = model
self.textGroup.setText(model.group())
self.textName.setText(model.displayName())
self.repaintModel()
else:
self.alg = ModelerAlgorithm()
self.alg.modelerdialog = self
self.model = ModelerAlgorithm()
self.model.modelerdialog = self
self.fillInputsTree()
self.fillAlgorithmTree()
self.view.centerOn(0, 0)
self.alg.setModelerView(self)
self.model.setModelerView(self)
self.help = None
self.hasChanged = False
@ -269,19 +275,19 @@ class ModelerDialog(BASE, WIDGET):
evt.accept()
def editHelp(self):
alg = self.alg
alg = self.model
dlg = HelpEditionDialog(alg)
dlg.exec_()
if dlg.descriptions:
self.alg.helpContent = dlg.descriptions
self.model.helpContent = dlg.descriptions
self.hasChanged = True
def runModel(self):
if len(self.alg.algs) == 0:
if len(self.model.childAlgorithms()) == 0:
self.bar.pushMessage("", "Model doesn't contain any algorithm and/or parameter and can't be executed", level=QgsMessageBar.WARNING, duration=5)
return
dlg = AlgorithmDialog(self.alg)
dlg = AlgorithmDialog(self.model)
dlg.exec_()
def save(self):
@ -399,7 +405,7 @@ class ModelerDialog(BASE, WIDGET):
svg.setFileName(filename)
svg.setSize(QSize(totalRect.width(), totalRect.height()))
svg.setViewBox(svgRect)
svg.setTitle(self.alg.displayName())
svg.setTitle(self.model.displayName())
painter = QPainter(svg)
self.scene.render(painter, svgRect, totalRect)
@ -418,7 +424,7 @@ class ModelerDialog(BASE, WIDGET):
if not filename.lower().endswith('.py'):
filename += '.py'
text = self.alg.toPython()
text = self.model.toPython()
with codecs.open(filename, 'w', encoding='utf-8') as fout:
fout.write(text)
@ -431,10 +437,10 @@ class ModelerDialog(BASE, WIDGET):
self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
)
return
self.alg._name = str(self.textName.text())
self.alg._group = str(self.textGroup.text())
if self.alg.descriptionFile is not None and not saveAs:
filename = self.alg.descriptionFile
self.model._name = str(self.textName.text())
self.model._group = str(self.textGroup.text())
if self.model.descriptionFile is not None and not saveAs:
filename = self.model.descriptionFile
else:
filename, filter = QFileDialog.getSaveFileName(self,
self.tr('Save Model'),
@ -443,9 +449,9 @@ class ModelerDialog(BASE, WIDGET):
if filename:
if not filename.endswith('.model'):
filename += '.model'
self.alg.descriptionFile = filename
self.model.descriptionFile = filename
if filename:
text = self.alg.toJson()
text = self.model.toJson()
try:
with codecs.open(filename, 'w', encoding='utf-8') as fout:
fout.write(text)
@ -473,8 +479,8 @@ class ModelerDialog(BASE, WIDGET):
if filename:
try:
alg = ModelerAlgorithm.fromFile(filename)
self.alg = alg
self.alg.setModelerView(self)
self.model = alg
self.model.setModelerView(self)
self.textGroup.setText(alg._group)
self.textName.setText(alg._name)
self.repaintModel()
@ -499,7 +505,7 @@ class ModelerDialog(BASE, WIDGET):
self.scene = ModelerScene()
self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
ModelerAlgorithm.CANVAS_SIZE))
self.scene.paintModel(self.alg, controls)
self.scene.paintModel(self.model, controls)
self.view.setScene(self.scene)
def addInput(self):
@ -509,14 +515,16 @@ class ModelerDialog(BASE, WIDGET):
def addInputOfType(self, paramType, pos=None):
if paramType in ModelerParameterDefinitionDialog.paramTypes:
dlg = ModelerParameterDefinitionDialog(self.alg, paramType)
dlg = ModelerParameterDefinitionDialog(self.model, paramType)
dlg.exec_()
if dlg.param is not None:
if pos is None:
pos = self.getPositionForParameterItem()
if isinstance(pos, QPoint):
pos = QPointF(pos)
self.alg.addParameter(ModelerParameter(dlg.param, pos))
component = QgsProcessingModelAlgorithm.ModelParameter(dlg.param.name())
component.setPosition(pos)
self.model.addModelParameter(dlg.param, component)
self.repaintModel()
# self.view.ensureVisible(self.scene.getLastParameterItem())
self.hasChanged = True
@ -525,8 +533,8 @@ class ModelerDialog(BASE, WIDGET):
MARGIN = 20
BOX_WIDTH = 200
BOX_HEIGHT = 80
if self.alg.inputs:
maxX = max([i.pos.x() for i in list(self.alg.inputs.values())])
if len(self.model.parameterComponents() > 0):
maxX = max([i.position().x() for i in list(self.model.parameterComponents().values())])
newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
else:
newX = MARGIN + BOX_WIDTH / 2
@ -554,24 +562,22 @@ class ModelerDialog(BASE, WIDGET):
def _addAlgorithm(self, alg, pos=None):
dlg = None
try:
dlg = alg.getCustomModelerParametersDialog(self.alg)
dlg = alg.getCustomModelerParametersDialog(self.model)
except:
pass
if not dlg:
dlg = ModelerParametersDialog(alg, self.alg)
dlg = ModelerParametersDialog(alg, self.model)
dlg.exec_()
if dlg.alg is not None:
if pos is None:
dlg.alg.pos = self.getPositionForAlgorithmItem()
dlg.alg.setPosition(self.getPositionForAlgorithmItem())
else:
dlg.alg.pos = pos
if isinstance(dlg.alg.pos, QPoint):
dlg.alg.pos = QPointF(pos)
dlg.alg.setPosition(pos)
from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
for i, out in enumerate(dlg.alg.outputs):
dlg.alg.outputs[out].pos = dlg.alg.pos + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) *
ModelerGraphicItem.BOX_HEIGHT)
self.alg.addAlgorithm(dlg.alg)
for i, out in enumerate(dlg.alg.modelOutputs()):
dlg.alg.modelOutput(out).setPosition(dlg.alg.position() + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) *
ModelerGraphicItem.BOX_HEIGHT))
self.model.addChildAlgorithm(dlg.alg)
self.repaintModel()
self.hasChanged = True
@ -579,9 +585,9 @@ class ModelerDialog(BASE, WIDGET):
MARGIN = 20
BOX_WIDTH = 200
BOX_HEIGHT = 80
if self.alg.algs:
maxX = max([alg.pos.x() for alg in list(self.alg.algs.values())])
maxY = max([alg.pos.y() for alg in list(self.alg.algs.values())])
if self.model.childAlgorithms():
maxX = max([alg.position().x() for alg in list(self.model.childAlgorithms().values())])
maxY = max([alg.position().y() for alg in list(self.model.childAlgorithms().values())])
newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH)
newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE -
BOX_HEIGHT)
@ -611,7 +617,7 @@ class ModelerDialog(BASE, WIDGET):
for alg in provider.algorithms():
if alg.flags() & QgsProcessingAlgorithm.FlagHideFromModeler:
continue
if alg.id() == self.alg.id():
if alg.id() == self.model.id():
continue
item_text = [alg.displayName().lower()]

View File

@ -33,8 +33,8 @@ from qgis.PyQt.QtCore import Qt, QPointF, QRectF
from qgis.PyQt.QtGui import QFont, QFontMetricsF, QPen, QBrush, QColor, QPolygonF, QPicture, QPainter
from qgis.PyQt.QtWidgets import QGraphicsItem, QMessageBox, QMenu
from qgis.PyQt.QtSvg import QSvgRenderer
from qgis.core import QgsProcessingParameterDefinition
from processing.modeler.ModelerAlgorithm import ModelerParameter, Algorithm, ModelerOutput
from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingModelAlgorithm)
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
@ -51,31 +51,31 @@ class ModelerGraphicItem(QGraphicsItem):
self.controls = controls
self.model = model
self.element = element
if isinstance(element, ModelerParameter):
if isinstance(element, QgsProcessingModelAlgorithm.ModelParameter):
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'input.svg'))
self.picture = QPicture()
painter = QPainter(self.picture)
svg.render(painter)
self.pixmap = None
self.text = element.param.description()
elif isinstance(element, ModelerOutput):
self.text = self.model.parameterDefinition(element.parameterName()).description()
elif isinstance(element, QgsProcessingModelAlgorithm.ModelOutput):
# Output name
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'output.svg'))
self.picture = QPicture()
painter = QPainter(self.picture)
svg.render(painter)
self.pixmap = None
self.text = element.description
self.text = element.description()
else:
self.text = element.description
self.pixmap = element.algorithm.icon().pixmap(15, 15)
self.text = element.description()
self.pixmap = element.algorithm().icon().pixmap(15, 15)
self.arrows = []
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.setZValue(1000)
if not isinstance(element, ModelerOutput) and controls:
if not isinstance(element, QgsProcessingModelAlgorithm.ModelOutput) and controls:
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'edit.svg'))
picture = QPicture()
painter = QPainter(picture)
@ -98,25 +98,27 @@ class ModelerGraphicItem(QGraphicsItem):
self.removeElement)
self.deleteButton.setParentItem(self)
if isinstance(element, Algorithm):
alg = element.algorithm
if isinstance(element, QgsProcessingModelAlgorithm.ChildAlgorithm):
alg = element.algorithm()
if [a for a in alg.parameterDefinitions() if not a.isDestination()]:
pt = self.getLinkPointForParameter(-1)
pt = QPointF(0, pt.y())
if controls:
self.inButton = FoldButtonGraphicItem(pt, self.foldInput, self.element.paramsFolded)
self.inButton = FoldButtonGraphicItem(pt, self.foldInput, self.element.parametersCollapsed())
self.inButton.setParentItem(self)
if alg.outputDefinitions():
pt = self.getLinkPointForOutput(-1)
pt = QPointF(0, pt.y())
if controls:
self.outButton = FoldButtonGraphicItem(pt, self.foldOutput, self.element.outputsFolded)
self.outButton = FoldButtonGraphicItem(pt, self.foldOutput, self.element.outputsCollapsed())
self.outButton.setParentItem(self)
def foldInput(self, folded):
self.element.paramsFolded = folded
self.element.setParametersCollapsed(folded)
#also need to update the model's stored component
self.model.childAlgorithm(self.element.childId()).setParametersCollapsed(folded)
self.prepareGeometryChange()
if self.element.algorithm.outputDefinitions():
if self.element.algorithm().outputDefinitions():
pt = self.getLinkPointForOutput(-1)
pt = QPointF(0, pt.y())
self.outButton.position = pt
@ -125,7 +127,9 @@ class ModelerGraphicItem(QGraphicsItem):
self.update()
def foldOutput(self, folded):
self.element.outputsFolded = folded
self.element.setOutputsCollapsed(folded)
# also need to update the model's stored component
self.model.childAlgorithm(self.element.childId()).setOutputsCollapsed(folded)
self.prepareGeometryChange()
for arrow in self.arrows:
arrow.updatePath()
@ -138,10 +142,10 @@ class ModelerGraphicItem(QGraphicsItem):
font = QFont('Verdana', 8)
font.setPixelSize(12)
fm = QFontMetricsF(font)
unfolded = isinstance(self.element, Algorithm) and not self.element.paramsFolded
numParams = len([a for a in self.element.algorithm.parameterDefinitions() if not a.isDestination()]) if unfolded else 0
unfolded = isinstance(self.element, Algorithm) and not self.element.outputsFolded
numOutputs = len(self.element.algorithm.outputDefinitions()) if unfolded else 0
unfolded = isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm) and not self.element.parametersCollapsed()
numParams = len([a for a in self.element.algorithm().parameterDefinitions() if not a.isDestination()]) if unfolded else 0
unfolded = isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm) and not self.element.outputsCollapsed()
numOutputs = len(self.element.algorithm().outputDefinitions()) if unfolded else 0
hUp = fm.height() * 1.2 * (numParams + 2)
hDown = fm.height() * 1.2 * (numOutputs + 2)
@ -155,15 +159,15 @@ class ModelerGraphicItem(QGraphicsItem):
self.editElement()
def contextMenuEvent(self, event):
if isinstance(self.element, ModelerOutput):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelOutput):
return
popupmenu = QMenu()
removeAction = popupmenu.addAction('Remove')
removeAction.triggered.connect(self.removeElement)
editAction = popupmenu.addAction('Edit')
editAction.triggered.connect(self.editElement)
if isinstance(self.element, Algorithm):
if not self.element.active:
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
if not self.element.isActive():
removeAction = popupmenu.addAction('Activate')
removeAction.triggered.connect(self.activateAlgorithm)
else:
@ -172,11 +176,11 @@ class ModelerGraphicItem(QGraphicsItem):
popupmenu.exec_(event.screenPos())
def deactivateAlgorithm(self):
self.model.deactivateAlgorithm(self.element.modeler_name)
self.model.deactivateAlgorithm(self.element.childId())
self.model.updateModelerView()
def activateAlgorithm(self):
if self.model.activateAlgorithm(self.element.modeler_name):
if self.model.activateAlgorithm(self.element.childId()):
self.model.updateModelerView()
else:
QMessageBox.warning(None, 'Could not activate Algorithm',
@ -184,39 +188,41 @@ class ModelerGraphicItem(QGraphicsItem):
'Activate them them before trying to activate it.')
def editElement(self):
if isinstance(self.element, ModelerParameter):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
dlg = ModelerParameterDefinitionDialog(self.model,
param=self.element.param)
param=self.model.parameterDefinition(self.element.parameterName()))
dlg.exec_()
if dlg.param is not None:
self.model.updateParameter(dlg.param)
self.element.param = dlg.param
self.model.updateModelParameter(dlg.param)
self.element.setParameterName(dlg.param.name())
# also need to update the model's stored component
self.model.childAlgorithm(self.element.childId()).setParameterName(dlg.param.name())
self.text = dlg.param.description()
self.update()
elif isinstance(self.element, Algorithm):
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
dlg = None
try:
dlg = self.element.algorithm.getCustomModelerParametersDialog(self.model, self.element.modeler_name)
dlg = self.element.algorithm().getCustomModelerParametersDialog(self.model, self.element.childId())
except:
pass
if not dlg:
dlg = ModelerParametersDialog(self.element.algorithm, self.model, self.element.modeler_name)
dlg = ModelerParametersDialog(self.element.algorithm(), self.model, self.element.childId())
dlg.exec_()
if dlg.alg is not None:
dlg.alg.modeler_name = self.element.modeler_name
dlg.alg.setChildId(self.element.childId())
self.model.updateAlgorithm(dlg.alg)
self.model.updateModelerView()
def removeElement(self):
if isinstance(self.element, ModelerParameter):
if not self.model.removeParameter(self.element.param.name):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
if not self.model.removeParameter(self.element.parameterName()):
QMessageBox.warning(None, 'Could not remove element',
'Other elements depend on the selected one.\n'
'Remove them before trying to remove it.')
else:
self.model.updateModelerView()
elif isinstance(self.element, Algorithm):
if not self.model.removeAlgorithm(self.element.modeler_name):
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
if not self.model.removeAlgorithm(self.element.childId()):
QMessageBox.warning(None, 'Could not remove element',
'Other elements depend on the selected one.\n'
'Remove them before trying to remove it.')
@ -244,11 +250,11 @@ class ModelerGraphicItem(QGraphicsItem):
ModelerGraphicItem.BOX_WIDTH + 2,
ModelerGraphicItem.BOX_HEIGHT + 2)
if isinstance(self.element, ModelerParameter):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
color = QColor(238, 242, 131)
stroke = QColor(234, 226, 118)
selected = QColor(116, 113, 68)
elif isinstance(self.element, Algorithm):
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
color = QColor(255, 255, 255)
stroke = Qt.gray
selected = QColor(50, 50, 50)
@ -267,7 +273,7 @@ class ModelerGraphicItem(QGraphicsItem):
painter.setFont(font)
painter.setPen(QPen(Qt.black))
text = self.getAdjustedText(self.text)
if isinstance(self.element, Algorithm) and not self.element.active:
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm) and not self.element.isActive():
painter.setPen(QPen(Qt.gray))
text = text + "\n(deactivated)"
fm = QFontMetricsF(font)
@ -276,14 +282,14 @@ class ModelerGraphicItem(QGraphicsItem):
pt = QPointF(-ModelerGraphicItem.BOX_WIDTH / 2 + 25, ModelerGraphicItem.BOX_HEIGHT / 2.0 - h + 1)
painter.drawText(pt, text)
painter.setPen(QPen(Qt.black))
if isinstance(self.element, Algorithm):
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
h = -(fm.height() * 1.2)
h = h - ModelerGraphicItem.BOX_HEIGHT / 2.0 + 5
pt = QPointF(-ModelerGraphicItem.BOX_WIDTH / 2 + 25, h)
painter.drawText(pt, 'In')
i = 1
if not self.element.paramsFolded:
for param in [p for p in self.element.algorithm.parameterDefinitions() if not p.isDestination()]:
if not self.element.parametersCollapsed():
for param in [p for p in self.element.algorithm().parameterDefinitions() if not p.isDestination()]:
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden:
text = self.getAdjustedText(param.description())
h = -(fm.height() * 1.2) * (i + 1)
@ -295,8 +301,8 @@ class ModelerGraphicItem(QGraphicsItem):
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
pt = QPointF(-ModelerGraphicItem.BOX_WIDTH / 2 + 25, h)
painter.drawText(pt, 'Out')
if not self.element.outputsFolded:
for i, out in enumerate(self.element.algorithm.outputDefinitions()):
if not self.element.outputsCollapsed():
for i, out in enumerate(self.element.algorithm().outputDefinitions()):
text = self.getAdjustedText(out.description())
h = fm.height() * 1.2 * (i + 2)
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
@ -311,13 +317,13 @@ class ModelerGraphicItem(QGraphicsItem):
def getLinkPointForParameter(self, paramIndex):
offsetX = 25
if isinstance(self.element, Algorithm) and self.element.paramsFolded:
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm) and self.element.parametersCollapsed():
paramIndex = -1
offsetX = 17
font = QFont('Verdana', 8)
font.setPixelSize(12)
fm = QFontMetricsF(font)
if isinstance(self.element, Algorithm):
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
h = -(fm.height() * 1.2) * (paramIndex + 2) - fm.height() / 2.0 + 8
h = h - ModelerGraphicItem.BOX_HEIGHT / 2.0
else:
@ -325,9 +331,9 @@ class ModelerGraphicItem(QGraphicsItem):
return QPointF(-ModelerGraphicItem.BOX_WIDTH / 2 + offsetX, h)
def getLinkPointForOutput(self, outputIndex):
if isinstance(self.element, Algorithm) and self.element.algorithm.outputDefinitions():
outputIndex = (outputIndex if not self.element.outputsFolded else -1)
text = self.getAdjustedText(self.element.algorithm.outputDefinitions()[outputIndex].description())
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm) and self.element.algorithm().outputDefinitions():
outputIndex = (outputIndex if not self.element.outputsCollapsed() else -1)
text = self.getAdjustedText(self.element.algorithm().outputDefinitions()[outputIndex].description())
font = QFont('Verdana', 8)
font.setPixelSize(12)
fm = QFontMetricsF(font)
@ -335,7 +341,7 @@ class ModelerGraphicItem(QGraphicsItem):
h = fm.height() * 1.2 * (outputIndex + 1) + fm.height() / 2.0
y = h + ModelerGraphicItem.BOX_HEIGHT / 2.0 + 5
x = (-ModelerGraphicItem.BOX_WIDTH / 2 + 33 + w + 5
if not self.element.outputsFolded
if not self.element.outputsCollapsed()
else 10)
return QPointF(x, y)
else:
@ -345,7 +351,15 @@ class ModelerGraphicItem(QGraphicsItem):
if change == QGraphicsItem.ItemPositionHasChanged:
for arrow in self.arrows:
arrow.updatePath()
self.element.pos = self.pos()
self.element.setPosition(self.pos())
# also need to update the model's stored component's position
if isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
self.model.childAlgorithm(self.element.childId()).setPosition(self.pos())
elif isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
self.model.parameterComponent(self.element.parameterName()).setPosition(self.pos())
elif isinstance(self.element, QgsProcessingModelAlgorithm.ModelOutput):
self.model.childAlgorithm(self.element.childId()).modelOutput(self.element.name()).setPosition(self.pos())
return value

View File

@ -127,11 +127,12 @@ class ModelerParameterDefinitionDialog(QDialog):
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
idx = 0
for param in list(self.alg.inputs.values()):
if isinstance(param.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
self.parentCombo.addItem(param.param.description(), param.param.name())
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == param.param.name():
if self.param.parentLayerParameter() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
@ -215,11 +216,12 @@ class ModelerParameterDefinitionDialog(QDialog):
self.parentCombo = QComboBox()
self.parentCombo.addItem(self.tr("None"), None)
idx = 1
for param in list(self.alg.inputs.values()):
if isinstance(param.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
self.parentCombo.addItem(param.param.description(), param.param.name())
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == param.param.name():
if self.param.parentLayerParameter() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
@ -290,8 +292,9 @@ class ModelerParameterDefinitionDialog(QDialog):
safeName = ''.join(c for c in description if c in validChars)
name = safeName.lower()
i = 2
while name in self.alg.inputs:
while self.alg.parameterDefinition(name):
name = safeName.lower() + str(i)
i += 1
else:
name = self.param.name()
if (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_BOOLEAN or

View File

@ -36,7 +36,8 @@ from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit,
from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterPoint,
QgsProcessingParameterExtent)
QgsProcessingParameterExtent,
QgsProcessingModelAlgorithm)
from qgis.gui import (QgsMessageBar,
QgsScrollArea)
@ -52,11 +53,6 @@ from processing.core.outputs import (OutputRaster,
OutputDirectory)
from processing.core.parameters import ParameterPoint, ParameterExtent
from processing.modeler.ModelerAlgorithm import (ValueFromInput,
ValueFromOutput,
Algorithm,
ModelerOutput)
class ModelerParametersDialog(QDialog):
@ -206,8 +202,8 @@ class ModelerParametersDialog(QDialog):
else:
dependent = self.model.getDependentAlgorithms(self._algName)
opts = []
for alg in list(self.model.algs.values()):
if alg.modeler_name not in dependent:
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
opts.append(alg)
return opts
@ -237,16 +233,16 @@ class ModelerParametersDialog(QDialog):
outTypes = [outTypes]
values = []
inputs = self.model.inputs
inputs = self.model.parameterComponents()
for i in list(inputs.values()):
param = i.param
param = self.model.parameterDefinition(i.parameterName())
for t in paramType:
if isinstance(param, t):
if dataType is not None:
if param.datatype in dataType:
values.append(ValueFromInput(param.name()))
values.append(QgsProcessingModelAlgorithm.ChildParameterSource.fromModelParameter(param.name()))
else:
values.append(ValueFromInput(param.name()))
values.append(QgsProcessingModelAlgorithm.ChildParameterSource.fromModelParameter(param.name()))
break
if not outTypes:
return values
@ -254,73 +250,81 @@ class ModelerParametersDialog(QDialog):
dependent = []
else:
dependent = self.model.getDependentAlgorithms(self._algName)
for alg in list(self.model.algs.values()):
if alg.modeler_name not in dependent:
for out in alg.algorithm.outputDefinitions():
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
for out in alg.algorithm().outputDefinitions():
for t in outTypes:
if isinstance(out, t):
if dataType is not None and out.datatype in dataType:
values.append(ValueFromOutput(alg.modeler_name, out.name()))
values.append(QgsProcessingModelAlgorithm.ChildParameterSource.fromChildOutput(alg.childId(), out.name()))
else:
values.append(ValueFromOutput(alg.modeler_name, out.name()))
values.append(QgsProcessingModelAlgorithm.ChildParameterSource.fromChildOutput(alg.childId(), out.name()))
return values
def resolveValueDescription(self, value):
if isinstance(value, ValueFromInput):
return self.model.inputs[value.name].param.description()
else:
alg = self.model.algs[value.alg]
return self.tr("'{0}' from algorithm '{1}'").format(alg.algorithm.outputDefinition(value.output).description(), alg.description)
if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource):
if value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.StaticValue:
return value.staticValue()
elif value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
return self.model.parameterDefinition(value.parameterName()).description()
elif value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
alg = self.model.childAlgorithm(value.outputChildId())
return self.tr("'{0}' from algorithm '{1}'").format(alg.algorithm().outputDefinition(value.outputName()).description(), alg.description())
return value
def setPreviousValues(self):
if self._algName is not None:
alg = self.model.algs[self._algName]
self.descriptionBox.setText(alg.description)
for param in alg.algorithm.parameterDefinitions():
alg = self.model.childAlgorithm(self._algName)
self.descriptionBox.setText(alg.description())
for param in alg.algorithm().parameterDefinitions():
if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if param.name() in alg.params:
value = alg.params[param.name()]
if param.name() in alg.parameterSources():
value = alg.parameterSources()[param.name()]
else:
value = param.defaultValue()
self.wrappers[param.name()].setValue(value)
for name, out in list(alg.outputs.items()):
for name, out in list(alg.modelOutputs().items()):
self.valueItems[name].setText(out.description())
selected = []
dependencies = self.getAvailableDependencies() # spellok
for idx, dependency in enumerate(dependencies):
if dependency.modeler_name in alg.dependencies:
if dependency.childId() in alg.dependencies():
selected.append(idx)
self.dependenciesPanel.setSelectedItems(selected)
def createAlgorithm(self):
alg = Algorithm(self._alg.id())
alg.setName(self.model)
alg.description = self.descriptionBox.text()
alg = QgsProcessingModelAlgorithm.ChildAlgorithm(self._alg.id())
alg.generateChildId(self.model)
alg.setDescription(self.descriptionBox.text())
for param in self._alg.parameterDefinitions():
if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
val = self.wrappers[param.name()].value()
if not isinstance(val, ValueFromInput) and not isinstance(val, ValueFromOutput) and not param.checkValueIsAcceptable(val):
if ( isinstance(val, QgsProcessingModelAlgorithm.ChildParameterSource) and val.source() == QgsProcessingModelAlgorithm.ChildParameterSource.StaticValue and not param.checkValueIsAcceptable(val.staticValue())) \
or (not isinstance(val, QgsProcessingModelAlgorithm.ChildParameterSource) and not param.checkValueIsAcceptable(val)):
self.bar.pushMessage("Error", "Wrong or missing value for parameter '%s'" % param.description(),
level=QgsMessageBar.WARNING)
return None
alg.params[param.name()] = val
alg.addParameterSource(param.name(), val)
# outputs = self._alg.outputDefinitions()
#for output in outputs:
# if not output.flags() & QgsProcessingParameterDefinition.FlagHidden:
# name = str(self.valueItems[output.name()].text())
# if name.strip() != '' and name != ModelerParametersDialog.ENTER_NAME:
# alg.outputs[output.name()] = ModelerOutput(name)
# alg.outputs[output.name()] = QgsProcessingModelAlgorithm.ModelOutput(name)
selectedOptions = self.dependenciesPanel.selectedoptions
availableDependencies = self.getAvailableDependencies() # spellok
dep_ids = []
for selected in selectedOptions:
alg.dependencies.append(availableDependencies[selected].modeler_name) # spellok
dep_ids.append(availableDependencies[selected].childId()) # spellok
alg.setDependencies(dep_ids)
try:
self._alg.processBeforeAddingToModeler(alg, self.model)

View File

@ -28,10 +28,11 @@ __revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QPointF, Qt
from qgis.PyQt.QtWidgets import QGraphicsItem, QGraphicsScene
from qgis.core import QgsProcessingParameterDefinition
from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingModelAlgorithm)
from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
from processing.modeler.ModelerArrowItem import ModelerArrowItem
from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput, CompoundValue
from processing.modeler.ModelerAlgorithm import CompoundValue
class ModelerScene(QGraphicsScene):
@ -66,93 +67,93 @@ class ModelerScene(QGraphicsScene):
if isinstance(value, list):
for v in value:
items.extend(self.getItemsFromParamValue(v))
elif isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource):
if value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
items.append((self.paramItems[value.parameterName()], 0))
elif value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
outputs = self.model.childAlgorithm(value.outputChildId()).algorithm().outputDefinitions()
for i, out in enumerate(outputs):
if out.name() == value.outputName():
break
if value.outputChildId() in self.algItems:
items.append((self.algItems[value.outputChildId()], i))
elif isinstance(value, CompoundValue):
for v in value.values:
items.extend(self.getItemsFromParamValue(v))
elif isinstance(value, ValueFromInput):
items.append((self.paramItems[value.name], 0))
elif isinstance(value, ValueFromOutput):
outputs = self.model.algs[value.alg].algorithm.outputDefinitions()
for i, out in enumerate(outputs):
if out.name() == value.output:
break
if value.alg in self.algItems:
items.append((self.algItems[value.alg], i))
return items
def paintModel(self, model, controls=True):
self.model = model
# Inputs
for inp in list(model.inputs.values()):
for inp in list(model.parameterComponents().values()):
item = ModelerGraphicItem(inp, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)
item.setPos(inp.pos.x(), inp.pos.y())
self.paramItems[inp.param.name()] = item
item.setPos(inp.position().x(), inp.position().y())
self.paramItems[inp.parameterName()] = item
# We add the algs
for alg in list(model.algs.values()):
for alg in list(model.childAlgorithms().values()):
item = ModelerGraphicItem(alg, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)
item.setPos(alg.pos.x(), alg.pos.y())
self.algItems[alg.modeler_name] = item
item.setPos(alg.position().x(), alg.position().y())
self.algItems[alg.childId()] = item
# And then the arrows
for alg in list(model.algs.values()):
for alg in list(model.childAlgorithms().values()):
idx = 0
for parameter in alg.algorithm.parameterDefinitions():
for parameter in alg.algorithm().parameterDefinitions():
if not parameter.isDestination() and not parameter.flags() & QgsProcessingParameterDefinition.FlagHidden:
if parameter.name() in alg.params:
value = alg.params[parameter.name()]
if parameter.name() in alg.parameterSources():
value = alg.parameterSources()[parameter.name()]
else:
value = None
sourceItems = self.getItemsFromParamValue(value)
for sourceItem, sourceIdx in sourceItems:
arrow = ModelerArrowItem(sourceItem, sourceIdx, self.algItems[alg.modeler_name], idx)
arrow = ModelerArrowItem(sourceItem, sourceIdx, self.algItems[alg.childId()], idx)
sourceItem.addArrow(arrow)
self.algItems[alg.modeler_name].addArrow(arrow)
self.algItems[alg.childId()].addArrow(arrow)
arrow.updatePath()
self.addItem(arrow)
idx += 1
for depend in alg.dependencies:
for depend in alg.dependencies():
arrow = ModelerArrowItem(self.algItems[depend], -1,
self.algItems[alg.modeler_name], -1)
self.algItems[alg.childId()], -1)
self.algItems[depend].addArrow(arrow)
self.algItems[alg.modeler_name].addArrow(arrow)
self.algItems[alg.childId()].addArrow(arrow)
arrow.updatePath()
self.addItem(arrow)
# And finally the outputs
for alg in list(model.algs.values()):
outputs = alg.outputs
for alg in list(model.childAlgorithms().values()):
outputs = alg.modelOutputs()
outputItems = {}
idx = 0
for key in outputs:
out = outputs[key]
for key, out in outputs.items():
if out is not None:
item = ModelerGraphicItem(out, model, controls)
item.setFlag(QGraphicsItem.ItemIsMovable, True)
item.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.addItem(item)
pos = alg.outputs[key].pos
pos = out.position()
if pos is None:
pos = (alg.pos + QPointF(ModelerGraphicItem.BOX_WIDTH, 0) +
self.algItems[alg.modeler_name].getLinkPointForOutput(idx))
item.setPos(pos)
pos = (alg.position() + QPointF(ModelerGraphicItem.BOX_WIDTH, 0) +
self.algItems[alg.childId()].getLinkPointForOutput(idx))
item.setPosition(pos)
outputItems[key] = item
arrow = ModelerArrowItem(self.algItems[alg.modeler_name], idx, item,
arrow = ModelerArrowItem(self.algItems[alg.childId()], idx, item,
-1)
self.algItems[alg.modeler_name].addArrow(arrow)
self.algItems[alg.childId()].addArrow(arrow)
item.addArrow(arrow)
arrow.updatePath()
self.addItem(arrow)
idx += 1
else:
outputItems[key] = None
self.outputItems[alg.modeler_name] = outputItems
self.outputItems[alg.childId()] = outputItems
def mousePressEvent(self, mouseEvent):
if mouseEvent.button() != Qt.LeftButton:

View File

@ -96,6 +96,7 @@ SET(QGIS_CORE_SRCS
processing/qgsnativealgorithms.cpp
processing/qgsprocessingalgorithm.cpp
processing/qgsprocessingalgrunnertask.cpp
processing/qgsprocessingmodelalgorithm.cpp
processing/qgsprocessingoutputs.cpp
processing/qgsprocessingparameters.cpp
processing/qgsprocessingprovider.cpp
@ -896,6 +897,7 @@ SET(QGIS_CORE_HDRS
processing/qgsnativealgorithms.h
processing/qgsprocessingalgorithm.h
processing/qgsprocessingcontext.h
processing/qgsprocessingmodelalgorithm.h
processing/qgsprocessingoutputs.h
processing/qgsprocessingparameters.h
processing/qgsprocessingutils.h

View File

@ -218,6 +218,16 @@ bool QgsProcessingAlgorithm::addParameter( QgsProcessingParameterDefinition *def
return true;
}
void QgsProcessingAlgorithm::removeParameter( const QString &name )
{
const QgsProcessingParameterDefinition *def = parameterDefinition( name );
if ( def )
{
delete def;
mParameters.removeAll( def );
}
}
bool QgsProcessingAlgorithm::addOutput( QgsProcessingOutputDefinition *definition )
{
if ( !definition )

View File

@ -272,6 +272,12 @@ class CORE_EXPORT QgsProcessingAlgorithm
*/
bool addParameter( QgsProcessingParameterDefinition *parameterDefinition SIP_TRANSFER );
/**
* Removes the parameter with matching \a name from the algorithm, and deletes any existing
* definition.
*/
void removeParameter( const QString &name );
/**
* Adds an output \a definition to the algorithm. Ownership of the definition is transferred to the algorithm.
* Returns true if the output could be successfully added, or false if the output could not be added (e.g.

View File

@ -0,0 +1,370 @@
/***************************************************************************
qgsprocessingmodelalgorithm.cpp
------------------------------
begin : June 2017
copyright : (C) 2017 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 "qgsprocessingmodelalgorithm.h"
#include "qgsprocessingregistry.h"
QgsProcessingModelAlgorithm::ChildAlgorithm::ChildAlgorithm( const QString &algorithmId )
: mAlgorithmId( algorithmId )
{
}
const QgsProcessingAlgorithm *QgsProcessingModelAlgorithm::ChildAlgorithm::algorithm() const
{
return QgsApplication::processingRegistry()->algorithmById( mAlgorithmId );
}
QString QgsProcessingModelAlgorithm::Component::description() const
{
return mDescription;
}
void QgsProcessingModelAlgorithm::Component::setDescription( const QString &description )
{
mDescription = description;
}
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> QgsProcessingModelAlgorithm::ChildAlgorithm::parameterSources() const
{
return mParams;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &params )
{
mParams = params;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::addParameterSource( const QString &name, const ChildParameterSource &source )
{
mParams.insert( name, source );
}
bool QgsProcessingModelAlgorithm::ChildAlgorithm::isActive() const
{
return mActive;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setActive( bool active )
{
mActive = active;
}
QPointF QgsProcessingModelAlgorithm::Component::position() const
{
return mPosition;
}
void QgsProcessingModelAlgorithm::Component::setPosition( const QPointF &position )
{
mPosition = position;
}
QgsProcessingModelAlgorithm::Component::Component( const QString &description )
: mDescription( description )
{}
QStringList QgsProcessingModelAlgorithm::ChildAlgorithm::dependencies() const
{
return mDependencies;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setDependencies( const QStringList &dependencies )
{
mDependencies = dependencies;
}
bool QgsProcessingModelAlgorithm::ChildAlgorithm::outputsCollapsed() const
{
return mOutputsCollapsed;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setOutputsCollapsed( bool outputsCollapsed )
{
mOutputsCollapsed = outputsCollapsed;
}
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> QgsProcessingModelAlgorithm::ChildAlgorithm::modelOutputs() const
{
return mModelOutputs;
}
QgsProcessingModelAlgorithm::ModelOutput &QgsProcessingModelAlgorithm::ChildAlgorithm::modelOutput( const QString &name )
{
return mModelOutputs[ name ];
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setModelOutputs( const QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> &modelOutputs )
{
mModelOutputs = modelOutputs;
}
bool QgsProcessingModelAlgorithm::ChildAlgorithm::parametersCollapsed() const
{
return mParametersCollapsed;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setParametersCollapsed( bool parametersCollapsed )
{
mParametersCollapsed = parametersCollapsed;
}
QString QgsProcessingModelAlgorithm::ChildAlgorithm::childId() const
{
return mId;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setChildId( const QString &id )
{
mId = id;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::generateChildId( const QgsProcessingModelAlgorithm &model )
{
int i = 1;
QString id;
while ( true )
{
id = QStringLiteral( "%1_%2" ).arg( mAlgorithmId ).arg( i );
if ( !model.childAlgorithms().contains( id ) )
break;
i++;
}
mId = id;
}
QString QgsProcessingModelAlgorithm::ChildAlgorithm::algorithmId() const
{
return mAlgorithmId;
}
void QgsProcessingModelAlgorithm::ChildAlgorithm::setAlgorithmId( const QString &algorithmId )
{
mAlgorithmId = algorithmId;
}
//
// QgsProcessingModelAlgorithm
//
QgsProcessingModelAlgorithm::QgsProcessingModelAlgorithm( const QString &name, const QString &group )
: QgsProcessingAlgorithm()
, mModelName( name.isEmpty() ? QObject::tr( "model" ) : name )
, mModelGroup( group )
{}
QString QgsProcessingModelAlgorithm::name() const
{
return mModelName;
}
QString QgsProcessingModelAlgorithm::displayName() const
{
return mModelName;
}
QString QgsProcessingModelAlgorithm::group() const
{
return mModelGroup;
}
QIcon QgsProcessingModelAlgorithm::icon() const
{
return QgsApplication::getThemeIcon( QStringLiteral( "/processingModel.svg" ) );
}
QString QgsProcessingModelAlgorithm::svgIconPath() const
{
return QgsApplication::iconPath( QStringLiteral( "processingModel.svg" ) );
}
QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
{
Q_UNUSED( parameters );
Q_UNUSED( context );
Q_UNUSED( feedback );
return QVariantMap();
}
QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> QgsProcessingModelAlgorithm::childAlgorithms() const
{
return mChildAlgorithms;
}
void QgsProcessingModelAlgorithm::setParameterComponents( const QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> &parameterComponents )
{
mParameterComponents = parameterComponents;
}
void QgsProcessingModelAlgorithm::setParameterComponent( const QgsProcessingModelAlgorithm::ModelParameter &component )
{
mParameterComponents.insert( component.parameterName(), component );
}
QgsProcessingModelAlgorithm::ModelParameter &QgsProcessingModelAlgorithm::parameterComponent( const QString &name )
{
if ( !mParameterComponents.contains( name ) )
{
QgsProcessingModelAlgorithm::ModelParameter &component = mParameterComponents[ name ];
component.setParameterName( name );
return component;
}
return mParameterComponents[ name ];
}
void QgsProcessingModelAlgorithm::setChildAlgorithms( const QMap<QString, ChildAlgorithm> &childAlgorithms )
{
mChildAlgorithms = childAlgorithms;
}
void QgsProcessingModelAlgorithm::setChildAlgorithm( const QgsProcessingModelAlgorithm::ChildAlgorithm &algorithm )
{
mChildAlgorithms.insert( algorithm.childId(), algorithm );
}
QString QgsProcessingModelAlgorithm::addChildAlgorithm( ChildAlgorithm &algorithm )
{
if ( algorithm.childId().isEmpty() || mChildAlgorithms.contains( algorithm.childId() ) )
algorithm.generateChildId( *this );
mChildAlgorithms.insert( algorithm.childId(), algorithm );
return algorithm.childId();
}
QgsProcessingModelAlgorithm::ChildAlgorithm &QgsProcessingModelAlgorithm::childAlgorithm( const QString &childId )
{
return mChildAlgorithms[ childId ];
}
void QgsProcessingModelAlgorithm::addModelParameter( QgsProcessingParameterDefinition *definition, const QgsProcessingModelAlgorithm::ModelParameter &component )
{
addParameter( definition );
mParameterComponents.insert( definition->name(), component );
}
void QgsProcessingModelAlgorithm::updateModelParameter( QgsProcessingParameterDefinition *definition )
{
removeParameter( definition->name() );
addParameter( definition );
}
void QgsProcessingModelAlgorithm::removeModelParameter( const QString &name )
{
removeParameter( name );
mParameterComponents.remove( name );
}
QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> QgsProcessingModelAlgorithm::parameterComponents() const
{
return mParameterComponents;
}
QStringList QgsProcessingModelAlgorithm::dependentChildAlgorithms( const QString &childId ) const
{
QSet< QString > algs;
QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
{
if ( childIt->childId() == childId )
continue;
// does alg have a direct dependency on this child?
if ( childIt->dependencies().contains( childId ) )
algs << childIt->childId();
}
return algs.toList();
}
bool QgsProcessingModelAlgorithm::canExecute( QString *errorMessage ) const
{
QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
{
if ( !childIt->algorithm() )
{
if ( errorMessage )
{
*errorMessage = QObject::tr( "The model you are trying to run contains an algorithm that is not available: <i>%1</i>" ).arg( childIt->algorithmId() );
}
return false;
}
}
return true;
}
bool QgsProcessingModelAlgorithm::ChildParameterSource::operator==( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const
{
if ( mSource != other.mSource )
return false;
switch ( mSource )
{
case StaticValue:
return mStaticValue == other.mStaticValue;
case ChildOutput:
return mChildId == other.mChildId && mOutputName == other.mOutputName;
case ModelParameter:
return mParameterName == other.mParameterName;
}
return false;
}
QgsProcessingModelAlgorithm::ChildParameterSource QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( const QVariant &value )
{
ChildParameterSource src;
src.mSource = StaticValue;
src.mStaticValue = value;
return src;
}
QgsProcessingModelAlgorithm::ChildParameterSource QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( const QString &parameterName )
{
ChildParameterSource src;
src.mSource = ModelParameter;
src.mParameterName = parameterName;
return src;
}
QgsProcessingModelAlgorithm::ChildParameterSource QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( const QString &childId, const QString &outputName )
{
ChildParameterSource src;
src.mSource = ChildOutput;
src.mChildId = childId;
src.mOutputName = outputName;
return src;
}
QgsProcessingModelAlgorithm::ChildParameterSource::Source QgsProcessingModelAlgorithm::ChildParameterSource::source() const
{
return mSource;
}
QgsProcessingModelAlgorithm::ModelOutput::ModelOutput( const QString &description )
: QgsProcessingModelAlgorithm::Component( description )
{}
QgsProcessingModelAlgorithm::ModelParameter::ModelParameter( const QString &parameterName )
: QgsProcessingModelAlgorithm::Component()
, mParameterName( parameterName )
{
}

View File

@ -0,0 +1,622 @@
/***************************************************************************
qgsprocessingmodelalgorithm.h
-----------------------------
begin : June 2017
copyright : (C) 2017 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 QGSPROCESSINGMODELALGORITHM_H
#define QGSPROCESSINGMODELALGORITHM_H
#include "qgis_core.h"
#include "qgis.h"
#include "qgsprocessingalgorithm.h"
/**
* \class QgsProcessingModelAlgorithm
* \ingroup core
* Model based algorithm with processing.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
{
public:
/**
* Source for the value of a parameter for a child algorithm within a model.
* \since QGIS 3.0
* \ingroup core
*/
class CORE_EXPORT ChildParameterSource
{
public:
//! Possible parameter value sources
enum Source
{
ModelParameter, //!< Parameter value is taken from a parent model parameter
ChildOutput, //!< Parameter value is taken from an output generated by a child algorithm
StaticValue, //!< Parameter value is a static value
};
/**
* Constructor for ChildParameterSource. It is recommended that the static methods
* fromStaticValue(), fromModelParameter() and fromChildOutput() are used instead.
*/
ChildParameterSource() = default;
bool operator==( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const;
bool operator!=( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const
{
return !operator==( other );
}
/**
* Returns a new ChildParameterSource which takes its value from a static \a value.
* \see fromModelParameter()
* \see fromChildOutput()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromStaticValue( const QVariant &value );
/**
* Returns a new ChildParameterSource which takes its value from a parent model parameter.
* \see fromStaticValue()
* \see fromChildOutput()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromModelParameter( const QString &parameterName );
/**
* Returns a new ChildParameterSource which takes its value from an output generated by a child algorithm.
* \see fromStaticValue()
* \see fromModelParameter()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromChildOutput( const QString &childId, const QString &outputName );
/**
* Returns the parameter value's source.
*/
Source source() const;
/**
* Returns the source's static value. This is only used when the source() is StaticValue.
* \see setStaticValue()
*/
QVariant staticValue() const { return mStaticValue; }
/**
* Sets the source's static value. Calling this will also change the source() to StaticValue.
* \see staticValue()
*/
void setStaticValue( const QVariant &value ) { mStaticValue = value; mSource = StaticValue; }
/**
* Returns the source's model parameter name. This is only used when the source() is ModelParameter.
* \see setParameterName()
*/
QString parameterName() const { return mParameterName; }
/**
* Sets the source's model parameter \a name. Calling this will also change the source() to ModelParameter.
* \see parameterName()
*/
void setParameterName( const QString &name ) { mParameterName = name; mSource = ModelParameter; }
/**
* Returns the source's child algorithm ID from which the output value will be taken. This is only used when the source() is ChildOutput.
* \see setOutputChildId()
* \see outputName()
*/
QString outputChildId() const { return mChildId; }
/**
* Sets the source's child algorithm \a id from which the output value will be taken. Calling this will also change the source() to ChildOutput.
* \see parameterName()
* \see setOutputName()
*/
void setOutputChildId( const QString &id ) { mChildId = id; mSource = ChildOutput; }
/**
* Returns the source's child algorithm output name from which the output value will be taken. This is only used when the source() is ChildOutput.
* \see setOutputName()
* \see outputChildId()
*/
QString outputName() const { return mOutputName; }
/**
* Sets the source's child algorithm output \a name from which the output value will be taken. Calling this will also change the source() to ChildOutput.
* \see outputName()
* \see setOutputChildId()
*/
void setOutputName( const QString &name ) { mOutputName = name; mSource = ChildOutput; }
private:
Source mSource = StaticValue;
QVariant mStaticValue;
QString mParameterName;
QString mChildId;
QString mOutputName;
};
/**
* Represents a component of a model algorithm.
* \since QGIS 3.0
* \ingroup core
*/
class CORE_EXPORT Component
{
public:
/**
* Returns the friendly description text for the component.
* \see setDescription()
*/
QString description() const;
/**
* Sets the friendly \a description text for the component.
* \see description()
*/
void setDescription( const QString &description );
/**
* Returns the position of the model component within the graphical modeler.
* \see setPosition()
*/
QPointF position() const;
/**
* Sets the \a position of the model component within the graphical modeler.
* \see position()
*/
void setPosition( const QPointF &position );
protected:
//! Only subclasses can be created
Component( const QString &description = QString() );
//! Copies are protected to avoid slicing
Component( const QgsProcessingModelAlgorithm::Component &other ) = default;
//! Copies are protected to avoid slicing
Component &operator=( const QgsProcessingModelAlgorithm::Component &other ) = default;
private:
//! Position of component within model
QPointF mPosition;
QString mDescription;
};
/**
* Represents an input parameter used by the model.
* \since QGIS 3.0
* \ingroup core
*/
class CORE_EXPORT ModelParameter : public QgsProcessingModelAlgorithm::Component
{
public:
/**
* Constructor for ModelParameter. The parameter name should match one of the
* parameters from the parent model.
*/
ModelParameter( const QString &parameterName = QString() );
/**
* Returns the associated parameter name. The parameter name should match one of the
* parameters from the parent model.
* \see parameterName()
*/
QString parameterName() const { return mParameterName; }
/**
* Sets the associated parameter name. The parameter name should match one of the
* parameters from the parent model.
* \see parameterName()
*/
void setParameterName( const QString &name ) { mParameterName = name; }
private:
QString mParameterName;
};
/**
* Represents a final output created by the model.
* \since QGIS 3.0
* \ingroup core
*/
class CORE_EXPORT ModelOutput : public QgsProcessingModelAlgorithm::Component
{
public:
/**
* Constructor for ModelOutput with the specified \a description.
*/
ModelOutput( const QString &description = QString() );
/**
* Returns the child algorithm ID from which this output is generated.
* \see setChildId()
*/
QString childId() const { return mChildId; }
/**
* Sets the child algorithm \a id from which this output is generated.
* \see childId()
*/
void setChildId( const QString &id ) { mChildId = id; }
/**
* Returns the child algorithm output name from which this output is generated.
* \see setOutputName()
*/
QString outputName() const { return mOutputName; }
/**
* Sets the child algorithm output \a name from which this output is generated.
* \see outputName()
*/
void setOutputName( const QString &name ) { mOutputName = name; }
private:
QString mChildId;
QString mOutputName;
};
/**
* Child algorithm representing a single component of a QgsProcessingModelAlgorithm.
* \since QGIS 3.0
* \ingroup core
*/
class CORE_EXPORT ChildAlgorithm : public QgsProcessingModelAlgorithm::Component
{
public:
/**
* Constructor for ChildAlgorithm. The \a algorithmId parameter
* should be set to a QgsProcessingAlgorithm algorithm ID.
*/
ChildAlgorithm( const QString &algorithmId = QString() );
/**
* Returns the child algorithm's unique ID string, used the identify
* this child algorithm within its parent model.
* \see setChildId()
* \see generateChildId()
*/
QString childId() const;
/**
* Sets the child algorithm's unique \a id string, used the identify
* this child algorithm within its parent model.
* \see childId()
* \see generateChildId()
*/
void setChildId( const QString &id );
/**
* Automatically generates a unique childId() for the algorithm,
* avoiding child IDs which are already present in \a model.
* \see childId()
* \see setChildId()
*/
void generateChildId( const QgsProcessingModelAlgorithm &model );
/**
* Returns the underlying child algorithm's ID.
* \see algorithm()
* \see setAlgorithmId()
*/
QString algorithmId() const;
/**
* Sets the underlying child algorithm's ID. This
* should be set to an existing QgsProcessingAlgorithm algorithm ID.
* \see algorithm()
* \see algorithmId()
*/
void setAlgorithmId( const QString &algorithmId );
/**
* Returns the underlying child algorithm, or a nullptr
* if a matching algorithm is not available.
* \see algorithmId()
*/
const QgsProcessingAlgorithm *algorithm() const;
/**
* Returns a map of parameter sources. The keys are the child algorithm
* parameter names, the values are the source for that parameter.
* \see setParameterSources()
* \see addParameterSource()
*/
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > parameterSources() const;
/**
* Sets the map of parameter \a sources. The keys are the child algorithm
* parameter names, the values are the source for that parameter.
* \see parameterSources()
* \see addParameterSource()
*/
void setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &sources );
/**
* Adds a parameter source. The \a name argument should match
* one of the child algorithm's parameter names, and the \a source
* argument is used to set the source for that parameter.
*
* Any existing parameter source with matching name will be replaced.
* \see parameterSources()
* \see setParameterSources()
*/
void addParameterSource( const QString &name, const QgsProcessingModelAlgorithm::ChildParameterSource &source );
/**
* Returns true if the child algorithm is active.
* \see setActive()
*/
bool isActive() const;
/**
* Sets whether the child algorithm is active.
* \see isActive()
*/
void setActive( bool active );
/**
* Returns the list of child algorithms from the parent model on which this
* algorithm is dependent. The returned list contains the id() of the
* dependent algorithms.
* \see setDependencies()
*/
QStringList dependencies() const;
/**
* Sets the list of child algorithms from the parent model on which this
* algorithm is dependent. The list should contain the id() of the
* dependent algorithms.
* \see dependencies()
*/
void setDependencies( const QStringList &dependencies );
/**
* Returns true if the list of parameters for this algorithm should be collapsed
* in the graphical modeller.
* \see setParametersCollapsed()
* \see outputsCollapsed()
*/
bool parametersCollapsed() const;
/**
* Sets whether the list of parameters for this algorithm should be collapsed
* in the graphical modeller.
* \see parametersCollapsed()
* \see setOutputsCollapsed()
*/
void setParametersCollapsed( bool collapsed );
/**
* Returns true if the list of outputs for this algorithm should be collapsed
* in the graphical modeller.
* \see setParametersCollapsed()
* \see parametersCollapsed()
*/
bool outputsCollapsed() const;
/**
* Sets whether the list of outputs for this algorithm should be collapsed
* in the graphical modeller.
* \see outputsCollapsed()
* \see setParametersCollapsed()
*/
void setOutputsCollapsed( bool collapsed );
/**
* Returns the map of final model outputs which are generated by this child algorithm.
* The keys are the output names from this child algorithm. Only outputs which are
* part of the final outputs from the model are included in this map.
* \see setModelOutputs()
* \see modelOutput()
*/
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> modelOutputs() const;
/**
* Returns the final model output with matching \a name. If no output
* exists with the name, a new one will be created and returned.
* \see modelOutputs()
* \see setModelOutputs()
*/
QgsProcessingModelAlgorithm::ModelOutput &modelOutput( const QString &name );
/**
* Sets the map of final model \a outputs which are generated by this child algorithm.
* The keys are the output names from this child algorithm. Only outputs which are
* part of the final outputs from the model should be included in this map.
* \see modelOutputs()
*/
void setModelOutputs( const QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> &outputs );
private:
QString mId;
QString mAlgorithmId;
//! A map of parameter sources. Keys are algorithm parameter names.
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > mParams;
//! A map of ModelOutput for final model outputs generated by this child algorithm. Keys are output names from the child algorithm.
QMap< QString, QgsProcessingModelAlgorithm::ModelOutput > mModelOutputs;
bool mActive = true;
//! List of child algorithms from the parent model on which this algorithm is dependent
QStringList mDependencies;
//! Whether list of parameters should be collapsed in the graphical modeller
bool mParametersCollapsed = true;
//! Whether list of outputs should be collapsed in the graphical modeller
bool mOutputsCollapsed = true;
};
/**
* Constructor for QgsProcessingModelAlgorithm.
*/
QgsProcessingModelAlgorithm( const QString &name = QString(), const QString &group = QString() );
QString name() const override;
QString displayName() const override;
QString group() const override;
QIcon icon() const override;
QString svgIconPath() const override;
bool canExecute( QString *errorMessage SIP_OUT = nullptr ) const override;
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
/**
* Returns the map of child algorithms contained in the model. The keys
* are the child algorithm ids (see QgsProcessingModelAlgorithm::ChildAlgorithm::childId()).
* \see childAlgorithm()
* \see setChildAlgorithms()
* \see addChildAlgorithm()
*/
QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> childAlgorithms() const;
/**
* Sets the map of child algorithms contained in the model. The keys
* are the child algorithm ids (see QgsProcessingModelAlgorithm::ChildAlgorithm::childId()).
* All existing child algorithms will be replaced.
* \see childAlgorithms()
* \see childAlgorithm()
* \see setChildAlgorithm()
* \see addChildAlgorithm()
*/
void setChildAlgorithms( const QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> &childAlgorithms );
/**
* Sets the child \a algorithm within the model. If a child algorithm already
* exists in the model with the same child ID then that algorithm will be replaced.
* \see addChildAlgorithm()
* \see setChildAlgorithms()
*/
void setChildAlgorithm( const QgsProcessingModelAlgorithm::ChildAlgorithm &algorithm );
/**
* Adds a new child \a algorithm to the model. If a child algorithm already exists
* in the model with the same child ID then \a algorithm will be assigned a new
* autogenerated unique ID.
* The assigned child ID will be returned.
* \see childAlgorithms()
* \see childAlgorithm()
* \see setChildAlgorithm()
* \see setChildAlgorithms()
*/
QString addChildAlgorithm( QgsProcessingModelAlgorithm::ChildAlgorithm &algorithm );
/**
* Returns the child algorithm with matching \a id. If no child algorithm exists with
* this ID a new algorithm will be added to the model and returned.
* \see addChildAlgorithm()
* \see childAlgorithms()
*/
QgsProcessingModelAlgorithm::ChildAlgorithm &childAlgorithm( const QString &id );
/**
* Adds a new parameter to the model, with the specified \a definition and graphical \a component.
* Ownership of \a definition is transferred to the model.
* \see updateModelParameter()
* \see removeModelParameter()
*/
void addModelParameter( QgsProcessingParameterDefinition *definition SIP_TRANSFER, const QgsProcessingModelAlgorithm::ModelParameter &component );
/**
* Replaces the definition of an existing parameter (by parameter name) with a new \a definition. Ownership of
* \a definition is transferred to the model, and any existing parameter is deleted.
* \see addModelParameter()
* \see removeModelParameter()
*/
void updateModelParameter( QgsProcessingParameterDefinition *definition SIP_TRANSFER );
/**
* Removes an existing model parameter by \a name. The definition of the matching parameter
* is deleted.
* \see addModelParameter()
* \see updateModelParameter()
*/
void removeModelParameter( const QString &name );
/**
* Returns the map of parameter components used by the model. The keys
* should match the algorithm's parameter names (see parameterDefinitions() ).
* \see setParameterComponent()
* \see parameterComponent()
*/
QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> parameterComponents() const;
/**
* Sets the map of parameter components used by the model. The keys
* should match the algorithm's parameter names (see parameterDefinitions() ).
* All existing parameter components will be replaced.
* \see parameterComponents()
* \see setParameterComponent()
* \see parameterComponent()
*/
void setParameterComponents( const QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> &parameterComponents );
/**
* Sets a parameter \a component for the model. If a parameter component already
* exists in the model with the same parameter name then that component will be replaced.
* \see parameterComponents()
* \see setParameterComponents()
* \see parameterComponent()
*/
void setParameterComponent( const QgsProcessingModelAlgorithm::ModelParameter &component );
/**
* Returns the parameter component with matching \a name. If no parameter component exists with
* this name a new component will be added to the model and returned.
* \see parameterComponents()
* \see setParameterComponents()
* \see setParameterComponent()
*/
QgsProcessingModelAlgorithm::ModelParameter &parameterComponent( const QString &name );
QStringList dependentChildAlgorithms( const QString &childId ) const;
private:
QString mModelName;
QString mModelGroup;
QMap< QString, ChildAlgorithm > mChildAlgorithms;
//! Map of parameter name to model parameter component
QMap< QString, ModelParameter > mParameterComponents;
};
#endif // QGSPROCESSINGMODELALGORITHM_H

View File

@ -20,6 +20,7 @@
#include "qgsprocessingutils.h"
#include "qgsprocessingalgorithm.h"
#include "qgsprocessingcontext.h"
#include "qgsprocessingmodelalgorithm.h"
#include <QObject>
#include <QtTest/QSignalSpy>
#include "qgis.h"
@ -103,6 +104,13 @@ class DummyAlgorithm : public QgsProcessingAlgorithm
QgsProcessingParameterFeatureSink *p6 = new QgsProcessingParameterFeatureSink( "p6" );
QVERIFY( addParameter( p6 ) );
QCOMPARE( destinationParameterDefinitions(), QgsProcessingParameterDefinitions() << p5 << p6 );
// remove parameter
removeParameter( "non existent" );
removeParameter( "p6" );
QCOMPARE( destinationParameterDefinitions(), QgsProcessingParameterDefinitions() << p5 );
removeParameter( "p5" );
QVERIFY( destinationParameterDefinitions().isEmpty() );
}
void runOutputChecks()
@ -318,6 +326,7 @@ class TestQgsProcessing: public QObject
void validateInputCrs();
void generateIteratingDestination();
void asPythonCommand();
void modelerAlgorithm();
private:
@ -2918,5 +2927,250 @@ void TestQgsProcessing::asPythonCommand()
alg.runAsPythonCommandChecks();
}
void TestQgsProcessing::modelerAlgorithm()
{
//static value source
QgsProcessingModelAlgorithm::ChildParameterSource svSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 );
QCOMPARE( svSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
QCOMPARE( svSource.staticValue().toInt(), 5 );
svSource.setStaticValue( 7 );
QCOMPARE( svSource.staticValue().toInt(), 7 );
svSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "a" );
// check that calling setStaticValue flips source to StaticValue
QCOMPARE( svSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ModelParameter );
svSource.setStaticValue( 7 );
QCOMPARE( svSource.staticValue().toInt(), 7 );
QCOMPARE( svSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
// model parameter source
QgsProcessingModelAlgorithm::ChildParameterSource mpSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "a" );
QCOMPARE( mpSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ModelParameter );
QCOMPARE( mpSource.parameterName(), QStringLiteral( "a" ) );
mpSource.setParameterName( "b" );
QCOMPARE( mpSource.parameterName(), QStringLiteral( "b" ) );
mpSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 );
// check that calling setParameterName flips source to ModelParameter
QCOMPARE( mpSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
mpSource.setParameterName( "c" );
QCOMPARE( mpSource.parameterName(), QStringLiteral( "c" ) );
QCOMPARE( mpSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ModelParameter );
// child alg output source
QgsProcessingModelAlgorithm::ChildParameterSource oSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( "a", "b" );
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );
QCOMPARE( oSource.outputChildId(), QStringLiteral( "a" ) );
QCOMPARE( oSource.outputName(), QStringLiteral( "b" ) );
oSource.setOutputChildId( "c" );
QCOMPARE( oSource.outputChildId(), QStringLiteral( "c" ) );
oSource.setOutputName( "d" );
QCOMPARE( oSource.outputName(), QStringLiteral( "d" ) );
oSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 );
// check that calling setOutputChildId flips source to ChildOutput
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
oSource.setOutputChildId( "c" );
QCOMPARE( oSource.outputChildId(), QStringLiteral( "c" ) );
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );
oSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 );
// check that calling setOutputName flips source to ChildOutput
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
oSource.setOutputName( "d" );
QCOMPARE( oSource.outputName(), QStringLiteral( "d" ) );
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );
// source equality operator
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) ==
QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 7 ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "a" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "a" ) ) ==
QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "a" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "a" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "b" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( QStringLiteral( "a" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) ==
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg2" ), QStringLiteral( "out" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out2" ) ) );
QgsProcessingModelAlgorithm::ChildAlgorithm child( QStringLiteral( "some_id" ) );
QCOMPARE( child.algorithmId(), QStringLiteral( "some_id" ) );
QVERIFY( !child.algorithm() );
child.setAlgorithmId( QStringLiteral( "native:centroids" ) );
QVERIFY( child.algorithm() );
QCOMPARE( child.algorithm()->id(), QStringLiteral( "native:centroids" ) );
child.setDescription( QStringLiteral( "desc" ) );
QCOMPARE( child.description(), QStringLiteral( "desc" ) );
QVERIFY( child.isActive() );
child.setActive( false );
QVERIFY( !child.isActive() );
child.setPosition( QPointF( 1, 2 ) );
QCOMPARE( child.position(), QPointF( 1, 2 ) );
QVERIFY( child.parametersCollapsed() );
child.setParametersCollapsed( false );
QVERIFY( !child.parametersCollapsed() );
QVERIFY( child.outputsCollapsed() );
child.setOutputsCollapsed( false );
QVERIFY( !child.outputsCollapsed() );
child.setChildId( QStringLiteral( "my_id" ) );
QCOMPARE( child.childId(), QStringLiteral( "my_id" ) );
child.setDependencies( QStringList() << "a" << "b" );
QCOMPARE( child.dependencies(), QStringList() << "a" << "b" );
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > sources;
sources.insert( QStringLiteral( "a" ), QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) );
child.setParameterSources( sources );
QCOMPARE( child.parameterSources().value( QStringLiteral( "a" ) ).staticValue().toInt(), 5 );
child.addParameterSource( QStringLiteral( "b" ), QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 7 ) );
QCOMPARE( child.parameterSources().value( QStringLiteral( "a" ) ).staticValue().toInt(), 5 );
QCOMPARE( child.parameterSources().value( QStringLiteral( "b" ) ).staticValue().toInt(), 7 );
QgsProcessingModelAlgorithm::ModelOutput testModelOut;
testModelOut.setChildId( QStringLiteral( "my_id" ) );
QCOMPARE( testModelOut.childId(), QStringLiteral( "my_id" ) );
testModelOut.setOutputName( QStringLiteral( "my_output" ) );
QCOMPARE( testModelOut.outputName(), QStringLiteral( "my_output" ) );
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> outputs;
QgsProcessingModelAlgorithm::ModelOutput out1;
out1.setDescription( QStringLiteral( "my output" ) );
outputs.insert( QStringLiteral( "a" ), out1 );
child.setModelOutputs( outputs );
QCOMPARE( child.modelOutputs().count(), 1 );
QCOMPARE( child.modelOutputs().value( QStringLiteral( "a" ) ).description(), QStringLiteral( "my output" ) );
QCOMPARE( child.modelOutput( "a" ).description(), QStringLiteral( "my output" ) );
child.modelOutput( "a" ).setDescription( QStringLiteral( "my output 2" ) );
QCOMPARE( child.modelOutput( "a" ).description(), QStringLiteral( "my output 2" ) );
// no existent
child.modelOutput( "b" ).setDescription( QStringLiteral( "my output 3" ) );
QCOMPARE( child.modelOutput( "b" ).description(), QStringLiteral( "my output 3" ) );
QCOMPARE( child.modelOutputs().count(), 2 );
// model algorithm tests
QgsProcessingModelAlgorithm alg( "test", "testGroup" );
QCOMPARE( alg.name(), QStringLiteral( "test" ) );
QCOMPARE( alg.displayName(), QStringLiteral( "test" ) );
QCOMPARE( alg.group(), QStringLiteral( "testGroup" ) );
// child algorithms
QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> algs;
QgsProcessingModelAlgorithm::ChildAlgorithm a1;
a1.setDescription( QStringLiteral( "alg1" ) );
QgsProcessingModelAlgorithm::ChildAlgorithm a2;
a2.setDescription( QStringLiteral( "alg2" ) );
algs.insert( QStringLiteral( "a" ), a1 );
algs.insert( QStringLiteral( "b" ), a2 );
alg.setChildAlgorithms( algs );
QCOMPARE( alg.childAlgorithms().count(), 2 );
QCOMPARE( alg.childAlgorithms().value( QStringLiteral( "a" ) ).description(), QStringLiteral( "alg1" ) );
QCOMPARE( alg.childAlgorithms().value( QStringLiteral( "b" ) ).description(), QStringLiteral( "alg2" ) );
QgsProcessingModelAlgorithm::ChildAlgorithm a3;
a3.setChildId( QStringLiteral( "c" ) );
a3.setDescription( QStringLiteral( "alg3" ) );
QCOMPARE( alg.addChildAlgorithm( a3 ), QStringLiteral( "c" ) );
QCOMPARE( alg.childAlgorithms().count(), 3 );
QCOMPARE( alg.childAlgorithms().value( QStringLiteral( "a" ) ).description(), QStringLiteral( "alg1" ) );
QCOMPARE( alg.childAlgorithms().value( QStringLiteral( "b" ) ).description(), QStringLiteral( "alg2" ) );
QCOMPARE( alg.childAlgorithms().value( QStringLiteral( "c" ) ).description(), QStringLiteral( "alg3" ) );
QCOMPARE( alg.childAlgorithm( "a" ).description(), QStringLiteral( "alg1" ) );
QCOMPARE( alg.childAlgorithm( "b" ).description(), QStringLiteral( "alg2" ) );
QCOMPARE( alg.childAlgorithm( "c" ).description(), QStringLiteral( "alg3" ) );
// initially non-existent
QVERIFY( alg.childAlgorithm( "d" ).description().isEmpty() );
alg.childAlgorithm( "d" ).setDescription( QStringLiteral( "alg4" ) );
QCOMPARE( alg.childAlgorithm( "d" ).description(), QStringLiteral( "alg4" ) );
// overwrite existing
QgsProcessingModelAlgorithm::ChildAlgorithm a4a;
a4a.setChildId( "d" );
a4a.setDescription( "new" );
alg.setChildAlgorithm( a4a );
QCOMPARE( alg.childAlgorithm( "d" ).description(), QStringLiteral( "new" ) );
// generating child ids
QgsProcessingModelAlgorithm::ChildAlgorithm c1;
c1.setAlgorithmId( QStringLiteral( "buffer" ) );
c1.generateChildId( alg );
QCOMPARE( c1.childId(), QStringLiteral( "buffer_1" ) );
QCOMPARE( alg.addChildAlgorithm( c1 ), QStringLiteral( "buffer_1" ) );
QgsProcessingModelAlgorithm::ChildAlgorithm c2;
c2.setAlgorithmId( QStringLiteral( "buffer" ) );
c2.generateChildId( alg );
QCOMPARE( c2.childId(), QStringLiteral( "buffer_2" ) );
QCOMPARE( alg.addChildAlgorithm( c2 ), QStringLiteral( "buffer_2" ) );
QgsProcessingModelAlgorithm::ChildAlgorithm c3;
c3.setAlgorithmId( QStringLiteral( "centroid" ) );
c3.generateChildId( alg );
QCOMPARE( c3.childId(), QStringLiteral( "centroid_1" ) );
QCOMPARE( alg.addChildAlgorithm( c3 ), QStringLiteral( "centroid_1" ) );
QgsProcessingModelAlgorithm::ChildAlgorithm c4;
c4.setAlgorithmId( QStringLiteral( "centroid" ) );
c4.setChildId( QStringLiteral( "centroid_1" ) );// dupe id
QCOMPARE( alg.addChildAlgorithm( c4 ), QStringLiteral( "centroid_2" ) );
QCOMPARE( alg.childAlgorithm( QStringLiteral( "centroid_2" ) ).childId(), QStringLiteral( "centroid_2" ) );
// parameter components
QMap<QString, QgsProcessingModelAlgorithm::ModelParameter> pComponents;
QgsProcessingModelAlgorithm::ModelParameter pc1;
pc1.setParameterName( QStringLiteral( "my_param" ) );
QCOMPARE( pc1.parameterName(), QStringLiteral( "my_param" ) );
pComponents.insert( QStringLiteral( "my_param" ), pc1 );
alg.setParameterComponents( pComponents );
QCOMPARE( alg.parameterComponents().count(), 1 );
QCOMPARE( alg.parameterComponents().value( QStringLiteral( "my_param" ) ).parameterName(), QStringLiteral( "my_param" ) );
QCOMPARE( alg.parameterComponent( "my_param" ).parameterName(), QStringLiteral( "my_param" ) );
alg.parameterComponent( "my_param" ).setDescription( QStringLiteral( "my param 2" ) );
QCOMPARE( alg.parameterComponent( "my_param" ).description(), QStringLiteral( "my param 2" ) );
// no existent
alg.parameterComponent( "b" ).setDescription( QStringLiteral( "my param 3" ) );
QCOMPARE( alg.parameterComponent( "b" ).description(), QStringLiteral( "my param 3" ) );
QCOMPARE( alg.parameterComponent( "b" ).parameterName(), QStringLiteral( "b" ) );
QCOMPARE( alg.parameterComponents().count(), 2 );
// parameter definitions
QgsProcessingModelAlgorithm alg1a( "test", "testGroup" );
QgsProcessingModelAlgorithm::ModelParameter bool1;
bool1.setPosition( QPointF( 1, 2 ) );
alg1a.addModelParameter( new QgsProcessingParameterBoolean( "p1", "desc" ), bool1 );
QCOMPARE( alg1a.parameterDefinitions().count(), 1 );
QCOMPARE( alg1a.parameterDefinition( "p1" )->type(), QStringLiteral( "boolean" ) );
QCOMPARE( alg1a.parameterComponent( "p1" ).position().x(), 1.0 );
QCOMPARE( alg1a.parameterComponent( "p1" ).position().y(), 2.0 );
alg1a.updateModelParameter( new QgsProcessingParameterBoolean( "p1", "descx" ) );
QCOMPARE( alg1a.parameterDefinition( "p1" )->description(), QStringLiteral( "descx" ) );
alg1a.removeModelParameter( "bad" );
QCOMPARE( alg1a.parameterDefinitions().count(), 1 );
alg1a.removeModelParameter( "p1" );
QVERIFY( alg1a.parameterDefinitions().isEmpty() );
QVERIFY( alg1a.parameterComponents().isEmpty() );
// test canExecute
QgsProcessingModelAlgorithm alg2( "test", "testGroup" );
QVERIFY( alg2.canExecute() );
QgsProcessingModelAlgorithm::ChildAlgorithm c5;
c5.setAlgorithmId( "native:centroids" );
alg2.addChildAlgorithm( c5 );
QVERIFY( alg2.canExecute() );
// non-existing alg
QgsProcessingModelAlgorithm::ChildAlgorithm c6;
c6.setAlgorithmId( "i'm not an alg" );
alg2.addChildAlgorithm( c6 );
QVERIFY( !alg2.canExecute() );
}
QGSTEST_MAIN( TestQgsProcessing )
#include "testqgsprocessing.moc"