Skip to content

Commit

Permalink
Move declaration of algorithm parameters/outputs to a new virtual
Browse files Browse the repository at this point in the history
initAlgorithm() method

This allows 2 benefits:
- algorithms can be subclassed and have subclasses add additional
parameters/outputs to the algorithm. With the previous approach
of declaring parameters/outputs in the constructor, it's not
possible to call virtual methods to add additional parameters/
outputs (since you can't call virtual methods from a constructor).

- initAlgorithm takes a variant map argument, allowing the algorithm
to dynamically adjust its declared parameters and outputs according
to this configuration map. This potentially allows model algorithms which
can be configured to have variable numbers of parameters and
outputs at run time. E.g. a "router" algorithm which directs
features to one of any number of output sinks depending on some
user configured criteria.
  • Loading branch information
nyalldawson committed Jul 10, 2017
1 parent fc221a6 commit 1e13d73
Show file tree
Hide file tree
Showing 161 changed files with 409 additions and 58 deletions.
8 changes: 6 additions & 2 deletions python/core/processing/models/qgsprocessingmodelalgorithm.sip
Expand Up @@ -27,6 +27,9 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
Constructor for QgsProcessingModelAlgorithm.
%End

virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() ); //#spellok


virtual QString name() const;

virtual QString displayName() const;
Expand All @@ -46,8 +49,6 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm

virtual QString asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const;

virtual QgsProcessingModelAlgorithm *createInstance() const /Factory/;


void setName( const QString &name );
%Docstring
Expand Down Expand Up @@ -364,6 +365,9 @@ Translated description of variable

protected:

virtual QgsProcessingAlgorithm *createInstance() const /Factory/;


virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );


Expand Down
37 changes: 37 additions & 0 deletions python/core/processing/qgsprocessingalgorithm.sip
Expand Up @@ -38,6 +38,10 @@ class QgsProcessingAlgorithm
QgsProcessingAlgorithm();
%Docstring
Constructor for QgsProcessingAlgorithm.

initAlgorithm() should be called after creating an algorithm to ensure it can correctly configure
its parameterDefinitions() and outputDefinitions(). Alternatively, calling create() will return
a pre-initialized copy of the algorithm.
%End

virtual ~QgsProcessingAlgorithm();
Expand All @@ -46,6 +50,11 @@ class QgsProcessingAlgorithm
QgsProcessingAlgorithm *create() const /Factory/;
%Docstring
Creates a copy of the algorithm, ready for execution.

This method returns a new, preinitialized copy of the algorithm, ready for
executing.

.. seealso:: initAlgorithm()
:rtype: QgsProcessingAlgorithm
%End

Expand Down Expand Up @@ -345,11 +354,35 @@ class QgsProcessingAlgorithm
sipTransferTo( resObj, Py_None );
%End

virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) = 0;
%Docstring
Initializes the algorithm using the specified ``configuration``.

This should be called directly after creating algorithms and before retrieving
any parameterDefinitions() or outputDefinitions().

Subclasses should use their implementations to add all required input parameter and output
definitions (which can be dynamically adjusted according to ``configuration``).

Dynamic configuration can be used by algorithms which alter their behavior
when used inside processing models. For instance, a "feature router" type
algorithm which sends input features to one of any number of outputs sinks
based on some preconfigured filter parameters can use the init method to
create these outputs based on the specified ``configuration``.

.. seealso:: addParameter()
.. seealso:: addOutput()
%End

bool addParameter( QgsProcessingParameterDefinition *parameterDefinition /Transfer/ );
%Docstring
Adds a parameter ``definition`` to the algorithm. Ownership of the definition is transferred to the algorithm.
Returns true if parameter could be successfully added, or false if the parameter could not be added (e.g.
as a result of a duplicate name).

This should usually be called from a subclass' initAlgorithm() implementation.

.. seealso:: initAlgorithm()
.. seealso:: addOutput()
:rtype: bool
%End
Expand All @@ -365,7 +398,11 @@ class QgsProcessingAlgorithm
Adds an output ``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.
as a result of a duplicate name).

This should usually be called from a subclass' initAlgorithm() implementation.

.. seealso:: addParameter()
.. seealso:: initAlgorithm()
:rtype: bool
%End

Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/AddTableField.py
Expand Up @@ -60,6 +60,7 @@ def __init__(self):
self.tr('Float'),
self.tr('String')]

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/Aspect.py
Expand Up @@ -60,6 +60,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.tr('Elevation layer')))
self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR,
Expand Down
Expand Up @@ -45,6 +45,7 @@ class AutoincrementalField(QgisAlgorithm):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))

Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/BarPlot.py
Expand Up @@ -53,6 +53,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/BasicStatistics.py
Expand Up @@ -88,6 +88,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
self.tr('Input layer')))

Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Boundary.py
Expand Up @@ -55,6 +55,8 @@ class Boundary(QgisAlgorithm):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Boundaries")))
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/BoundingBox.py
Expand Up @@ -63,6 +63,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Bounds'), QgsProcessing.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Bounds")))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/BoxPlot.py
Expand Up @@ -52,6 +52,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterTable(self.INPUT, self.tr('Input table')))
self.addParameter(ParameterTableField(self.NAME_FIELD,
self.tr('Category name field'),
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/CheckValidity.py
Expand Up @@ -73,6 +73,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.methods = [self.tr('The one selected in digitizing settings'),
'QGIS',
'GEOS']
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/ConcaveHull.py
Expand Up @@ -61,6 +61,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input point layer'), [QgsProcessing.TypeVectorPoint]))
self.addParameter(QgsProcessingParameterNumber(self.ALPHA,
self.tr('Threshold (0-1, where 1 is equivalent with Convex Hull)'),
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ConvexHull.py
Expand Up @@ -65,6 +65,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.methods = [self.tr('Create single minimum convex hull'),
self.tr('Create convex hulls based on field')]

Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/CreateAttributeIndex.py
Expand Up @@ -47,6 +47,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Input Layer')))
self.addParameter(QgsProcessingParameterField(self.FIELD,
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/CreateConstantRaster.py
Expand Up @@ -47,6 +47,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterRaster(self.INPUT,
self.tr('Reference layer')))
self.addParameter(ParameterNumber(self.NUMBER,
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Datasources2Vrt.py
Expand Up @@ -53,6 +53,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterMultipleInput(self.DATASOURCES,
self.tr('Input datasources'),
dataobjects.TYPE_TABLE))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/DefineProjection.py
Expand Up @@ -52,6 +52,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input Layer')))
self.addParameter(ParameterCrs(self.CRS, 'Output CRS'))
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/Delaunay.py
Expand Up @@ -68,6 +68,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessing.TypeVectorPoint]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Delaunay triangulation'), type=QgsProcessing.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Delaunay triangulation"), type=QgsProcessing.TypeVectorPolygon))
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/DeleteColumn.py
Expand Up @@ -50,6 +50,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterField(self.COLUMNS,
self.tr('Fields to drop'),
Expand Down
Expand Up @@ -44,6 +44,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer')))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Cleaned')))
Expand Down
14 changes: 8 additions & 6 deletions python/plugins/processing/algs/qgis/DeleteHoles.py
Expand Up @@ -42,14 +42,10 @@ class DeleteHoles(QgisAlgorithm):
MIN_AREA = 'MIN_AREA'
OUTPUT = 'OUTPUT'

def tags(self):
return self.tr('remove,delete,drop,holes,rings,fill').split(',')

def group(self):
return self.tr('Vector geometry tools')

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterNumber(self.MIN_AREA,
Expand All @@ -59,6 +55,12 @@ def __init__(self):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessing.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessing.TypeVectorPolygon))

def tags(self):
return self.tr('remove,delete,drop,holes,rings,fill').split(',')

def group(self):
return self.tr('Vector geometry tools')

def name(self):
return 'deleteholes'

Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/DensifyGeometries.py
Expand Up @@ -55,6 +55,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.VERTICES,
Expand Down
Expand Up @@ -53,6 +53,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.INTERVAL,
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Difference.py
Expand Up @@ -58,6 +58,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(Difference.INPUT,
self.tr('Input layer')))
self.addParameter(ParameterVector(Difference.OVERLAY,
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/DropGeometry.py
Expand Up @@ -52,6 +52,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessing.TypeVectorPoint, QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Dropped geometry")))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/EliminateSelection.py
Expand Up @@ -65,6 +65,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.modes = [self.tr('Largest area'),
self.tr('Smallest Area'),
self.tr('Largest common boundary')]
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/EquivalentNumField.py
Expand Up @@ -48,6 +48,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer')))
self.addParameter(ParameterTableField(self.FIELD,
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ExecuteSQL.py
Expand Up @@ -61,6 +61,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterMultipleInput(name=self.INPUT_DATASOURCES,
description=self.tr('Additional input datasources (called input1, .., inputN in the query)'),
optional=True))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Explode.py
Expand Up @@ -48,6 +48,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[dataobjects.TYPE_VECTOR_LINE]))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ExportGeometryInfo.py
Expand Up @@ -59,6 +59,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.calc_methods = [self.tr('Layer CRS'),
self.tr('Project CRS'),
self.tr('Ellipsoidal')]
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ExtendLines.py
Expand Up @@ -47,6 +47,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.START_DISTANCE,
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/algs/qgis/ExtentFromLayer.py
Expand Up @@ -73,6 +73,7 @@ def group(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterBoolean(self.BY_FEATURE,
self.tr('Calculate extent for each feature separately'), False))
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ExtractByLocation.py
Expand Up @@ -53,6 +53,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.predicates = (
('intersects', self.tr('intersects')),
('contains', self.tr('contains')),
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/ExtractNodes.py
Expand Up @@ -54,6 +54,8 @@ def group(self):

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[dataobjects.TYPE_VECTOR_POLYGON,
Expand Down

0 comments on commit 1e13d73

Please sign in to comment.