diff --git a/python/core/processing/qgsprocessingparameters.sip b/python/core/processing/qgsprocessingparameters.sip
index edf161ae970..247b5147101 100644
--- a/python/core/processing/qgsprocessingparameters.sip
+++ b/python/core/processing/qgsprocessingparameters.sip
@@ -163,14 +163,16 @@ class QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterString;
else if ( sipCpp->type() == "expression" )
sipType = sipType_QgsProcessingParameterExpression;
- else if ( sipCpp->type() == "table" )
- sipType = sipType_QgsProcessingParameterTable;
+ else if ( sipCpp->type() == "vector" )
+ sipType = sipType_QgsProcessingParameterVectorLayer;
else if ( sipCpp->type() == "field" )
- sipType = sipType_QgsProcessingParameterTableField;
+ sipType = sipType_QgsProcessingParameterField;
else if ( sipCpp->type() == "source" )
sipType = sipType_QgsProcessingParameterFeatureSource;
else if ( sipCpp->type() == "sink" )
sipType = sipType_QgsProcessingParameterFeatureSink;
+ else if ( sipCpp->type() == "vectorOut" )
+ sipType = sipType_QgsProcessingParameterVectorOutput;
else if ( sipCpp->type() == "rasterOut" )
sipType = sipType_QgsProcessingParameterRasterOutput;
else if ( sipCpp->type() == "fileOut" )
@@ -1153,10 +1155,11 @@ class QgsProcessingParameterExpression : QgsProcessingParameterDefinition
};
-class QgsProcessingParameterTable : QgsProcessingParameterDefinition
+class QgsProcessingParameterVectorLayer : QgsProcessingParameterDefinition
{
%Docstring
- A table (i.e. vector layers with or without geometry) parameter for processing algorithms.
+ A vector layer (with or without geometry) parameter for processing algorithms. Consider using
+ the more versatile QgsProcessingParameterFeatureSource wherever possible.
.. versionadded:: 3.0
%End
@@ -1165,20 +1168,24 @@ class QgsProcessingParameterTable : QgsProcessingParameterDefinition
%End
public:
- QgsProcessingParameterTable( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
- bool optional = false );
+ QgsProcessingParameterVectorLayer( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
+ bool optional = false );
%Docstring
- Constructor for QgsProcessingParameterTable.
+ Constructor for QgsProcessingParameterVectorLayer.
%End
virtual QString type() const;
+ virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
+
+ virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
+
};
-class QgsProcessingParameterTableField : QgsProcessingParameterDefinition
+class QgsProcessingParameterField : QgsProcessingParameterDefinition
{
%Docstring
- A table field parameter for processing algorithms.
+ A vector layer or feature source field parameter for processing algorithms.
.. versionadded:: 3.0
%End
@@ -1195,13 +1202,13 @@ class QgsProcessingParameterTableField : QgsProcessingParameterDefinition
DateTime
};
- QgsProcessingParameterTableField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
- const QString &parentLayerParameterName = QString(),
- DataType type = Any,
- bool allowMultiple = false,
- bool optional = false );
+ QgsProcessingParameterField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
+ const QString &parentLayerParameterName = QString(),
+ DataType type = Any,
+ bool allowMultiple = false,
+ bool optional = false );
%Docstring
- Constructor for QgsProcessingParameterTableField.
+ Constructor for QgsProcessingParameterField.
%End
virtual QString type() const;
@@ -1354,6 +1361,60 @@ class QgsProcessingParameterFeatureSink : QgsProcessingParameterDefinition
virtual bool fromVariantMap( const QVariantMap &map );
+};
+
+
+class QgsProcessingParameterVectorOutput : QgsProcessingParameterDefinition
+{
+%Docstring
+ A vector layer output parameter. Consider using the more flexible QgsProcessingParameterFeatureSink wherever
+ possible.
+.. versionadded:: 3.0
+%End
+
+%TypeHeaderCode
+#include "qgsprocessingparameters.h"
+%End
+ public:
+
+ QgsProcessingParameterVectorOutput( const QString &name, const QString &description = QString(), QgsProcessingParameterDefinition::LayerType type = QgsProcessingParameterDefinition::TypeVectorAny, const QVariant &defaultValue = QVariant(),
+ bool optional = false );
+%Docstring
+ Constructor for QgsProcessingParameterVectorOutput.
+%End
+
+ virtual QString type() const;
+ virtual bool isDestination() const;
+ virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
+
+ virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
+
+
+ QgsProcessingParameterDefinition::LayerType dataType() const;
+%Docstring
+ Returns the layer type for layers associated with the parameter.
+.. seealso:: setDataType()
+ :rtype: QgsProcessingParameterDefinition.LayerType
+%End
+
+ bool hasGeometry() const;
+%Docstring
+ Returns true if the layer is likely to include geometries. In cases were presence of geometry
+ cannot be reliably determined in advance, this method will default to returning true.
+ :rtype: bool
+%End
+
+ void setDataType( QgsProcessingParameterDefinition::LayerType type );
+%Docstring
+ Sets the layer ``type`` for the layers associated with the parameter.
+.. seealso:: dataType()
+%End
+
+ virtual QVariantMap toVariantMap() const;
+
+ virtual bool fromVariantMap( const QVariantMap &map );
+
+
};
class QgsProcessingParameterRasterOutput : QgsProcessingParameterDefinition
diff --git a/python/plugins/processing/algs/qgis/BarPlot.py b/python/plugins/processing/algs/qgis/BarPlot.py
index f4d6f6098f4..70ff00275f3 100644
--- a/python/plugins/processing/algs/qgis/BarPlot.py
+++ b/python/plugins/processing/algs/qgis/BarPlot.py
@@ -32,7 +32,7 @@ import plotly.graph_objs as go
from qgis.core import (QgsApplication,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterField,
QgsProcessingParameterFileOutput,
QgsProcessingOutputHtml)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -60,12 +60,12 @@ class BarPlot(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterTableField(self.NAME_FIELD,
- self.tr('Category name field'),
- None, self.INPUT, QgsProcessingParameterTableField.Any))
- self.addParameter(QgsProcessingParameterTableField(self.VALUE_FIELD,
- self.tr('Value field'),
- None, self.INPUT, QgsProcessingParameterTableField.Numeric))
+ self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
+ self.tr('Category name field'),
+ None, self.INPUT, QgsProcessingParameterField.Any))
+ self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
+ self.tr('Value field'),
+ None, self.INPUT, QgsProcessingParameterField.Numeric))
self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT, self.tr('Added'), self.tr('HTML files (*.html)')))
diff --git a/python/plugins/processing/algs/qgis/BasicStatistics.py b/python/plugins/processing/algs/qgis/BasicStatistics.py
index 645dc4f259a..cfc579bc853 100644
--- a/python/plugins/processing/algs/qgis/BasicStatistics.py
+++ b/python/plugins/processing/algs/qgis/BasicStatistics.py
@@ -37,7 +37,7 @@ from qgis.core import (QgsStatisticalSummary,
QgsFeatureRequest,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterField,
QgsProcessingParameterFileOutput,
QgsProcessingOutputHtml,
QgsProcessingOutputNumber)
@@ -90,9 +90,9 @@ class BasicStatisticsForField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterTableField(self.FIELD_NAME,
- self.tr('Field to calculate statistics on'),
- None, self.INPUT_LAYER, QgsProcessingParameterTableField.Any))
+ self.addParameter(QgsProcessingParameterField(self.FIELD_NAME,
+ self.tr('Field to calculate statistics on'),
+ None, self.INPUT_LAYER, QgsProcessingParameterField.Any))
self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT_HTML_FILE, self.tr('Statistics'), self.tr('HTML files (*.html)'), None, True))
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Statistics')))
diff --git a/python/plugins/processing/algs/qgis/CreateAttributeIndex.py b/python/plugins/processing/algs/qgis/CreateAttributeIndex.py
index 80b9dfffaba..4f7d320ddcd 100644
--- a/python/plugins/processing/algs/qgis/CreateAttributeIndex.py
+++ b/python/plugins/processing/algs/qgis/CreateAttributeIndex.py
@@ -28,12 +28,12 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsVectorDataProvider,
QgsFields,
QgsApplication,
- QgsProcessingUtils)
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
+ QgsProcessingParameterDefinition,
+ QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.parameters import ParameterTable
-from processing.core.parameters import ParameterTableField
-from processing.core.outputs import OutputVector
class CreateAttributeIndex(QgisAlgorithm):
@@ -53,12 +53,11 @@ class CreateAttributeIndex(QgisAlgorithm):
def __init__(self):
super().__init__()
- self.addParameter(ParameterTable(self.INPUT,
- self.tr('Input Layer')))
- self.addParameter(ParameterTableField(self.FIELD,
- self.tr('Attribute to index'), self.INPUT))
- self.addOutput(OutputVector(self.OUTPUT,
- self.tr('Indexed layer'), True))
+ self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
+ self.tr('Input Layer')))
+ self.addParameter(QgsProcessingParameterField(self.FIELD,
+ self.tr('Attribute to index'), None, self.INPUT))
+ self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))
def name(self):
return 'createattributeindex'
@@ -67,9 +66,8 @@ class CreateAttributeIndex(QgisAlgorithm):
return self.tr('Create attribute index')
def processAlgorithm(self, parameters, context, feedback):
- file_name = self.getParameterValue(self.INPUT)
- layer = QgsProcessingUtils.mapLayerFromString(file_name, context)
- field = self.getParameterValue(self.FIELD)
+ layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
+ field = self.parameterAsString(parameters, self.FIELD, context)
provider = layer.dataProvider()
field_index = layer.fields().lookupField(field)
@@ -84,4 +82,4 @@ class CreateAttributeIndex(QgisAlgorithm):
feedback.pushInfo(self.tr("Layer's data provider does not support "
"creating attribute indexes"))
- self.setOutputValue(self.OUTPUT, file_name)
+ return {self.OUTPUT: layer.id()}
diff --git a/python/plugins/processing/algs/qgis/DeleteColumn.py b/python/plugins/processing/algs/qgis/DeleteColumn.py
index 49f93028d2b..5056e200ef7 100644
--- a/python/plugins/processing/algs/qgis/DeleteColumn.py
+++ b/python/plugins/processing/algs/qgis/DeleteColumn.py
@@ -29,7 +29,7 @@ from qgis.core import (QgsApplication,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterField,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -56,9 +56,9 @@ class DeleteColumn(QgisAlgorithm):
super().__init__()
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
- self.addParameter(QgsProcessingParameterTableField(self.COLUMNS,
- self.tr('Fields to delete'),
- None, self.INPUT, QgsProcessingParameterTableField.Any, True))
+ self.addParameter(QgsProcessingParameterField(self.COLUMNS,
+ self.tr('Fields to delete'),
+ None, self.INPUT, QgsProcessingParameterField.Any, True))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer")))
diff --git a/python/plugins/processing/algs/qgis/DeleteHoles.py b/python/plugins/processing/algs/qgis/DeleteHoles.py
index 1d994851d3a..1aecf4f5324 100644
--- a/python/plugins/processing/algs/qgis/DeleteHoles.py
+++ b/python/plugins/processing/algs/qgis/DeleteHoles.py
@@ -25,12 +25,13 @@ __copyright__ = '(C) 2015, Etienne Trimaille'
__revision__ = '$Format:%H$'
from qgis.core import (QgsApplication,
- QgsProcessingUtils)
+ QgsProcessingUtils,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.parameters import (ParameterVector,
- ParameterNumber)
-from processing.core.outputs import OutputVector
-from processing.tools import dataobjects
class DeleteHoles(QgisAlgorithm):
@@ -53,12 +54,14 @@ class DeleteHoles(QgisAlgorithm):
def __init__(self):
super().__init__()
- self.addParameter(ParameterVector(self.INPUT,
- self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON]))
- self.addParameter(ParameterNumber(self.MIN_AREA,
- self.tr('Remove holes with area less than'), 0, 10000000.0, default=0.0, optional=True))
+ self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
+ self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon]))
+ self.addParameter(QgsProcessingParameterNumber(self.MIN_AREA,
+ self.tr('Remove holes with area less than'), QgsProcessingParameterNumber.Double,
+ 0, True, 0.0, 10000000.0))
- self.addOutput(OutputVector(self.OUTPUT, self.tr('Cleaned'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
+ self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
+ self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
def name(self):
return 'deleteholes'
@@ -67,29 +70,24 @@ class DeleteHoles(QgisAlgorithm):
return self.tr('Delete holes')
def processAlgorithm(self, parameters, context, feedback):
- layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
- min_area = self.getParameterValue(self.MIN_AREA)
- if min_area is not None:
- try:
- min_area = float(min_area)
- except:
- pass
+ source = self.parameterAsSource(parameters, self.INPUT, context)
+ min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
if min_area == 0.0:
min_area = -1.0
- writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(),
- context)
+ (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
+ source.fields(), source.wkbType(), source.sourceCrs())
- features = QgsProcessingUtils.getFeatures(layer, context)
- total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
+ features = source.getFeatures()
+ total = 100.0 / source.featureCount()
for current, f in enumerate(features):
+ if feedback.isCanceled():
+ break
+
if f.hasGeometry():
- if min_area is not None:
- f.setGeometry(f.geometry().removeInteriorRings(min_area))
- else:
- f.setGeometry(f.geometry().removeInteriorRings())
- writer.addFeature(f)
+ f.setGeometry(f.geometry().removeInteriorRings(min_area))
+ sink.addFeature(f)
feedback.setProgress(int(current * total))
- del writer
+ return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/DensifyGeometries.py b/python/plugins/processing/algs/qgis/DensifyGeometries.py
index 3f2122cb8d6..223ede5510c 100644
--- a/python/plugins/processing/algs/qgis/DensifyGeometries.py
+++ b/python/plugins/processing/algs/qgis/DensifyGeometries.py
@@ -30,15 +30,12 @@ import os
from qgis.core import (QgsWkbTypes,
QgsApplication,
- QgsProcessingUtils)
-
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.parameters import ParameterVector
-from processing.core.parameters import ParameterNumber
-from processing.core.outputs import OutputVector
-from processing.tools import dataobjects
-
-pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class DensifyGeometries(QgisAlgorithm):
@@ -61,14 +58,15 @@ class DensifyGeometries(QgisAlgorithm):
def __init__(self):
super().__init__()
- self.addParameter(ParameterVector(self.INPUT,
- self.tr('Input layer'),
- [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_LINE]))
- self.addParameter(ParameterNumber(self.VERTICES,
- self.tr('Vertices to add'), 1, 10000000, 1))
- self.addOutput(OutputVector(self.OUTPUT,
- self.tr('Densified')))
+ self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
+ self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon, QgsProcessingParameterDefinition.TypeVectorLine]))
+ self.addParameter(QgsProcessingParameterNumber(self.VERTICES,
+ self.tr('Vertices to add'), QgsProcessingParameterNumber.Integer,
+ 1, False, 1, 10000000))
+
+ self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
+ self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
def name(self):
return 'densifygeometries'
@@ -77,22 +75,24 @@ class DensifyGeometries(QgisAlgorithm):
return self.tr('Densify geometries')
def processAlgorithm(self, parameters, context, feedback):
- layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
- vertices = self.getParameterValue(self.VERTICES)
+ source = self.parameterAsSource(parameters, self.INPUT, context)
+ vertices = self.parameterAsInt(parameters, self.VERTICES, context)
- isPolygon = layer.geometryType() == QgsWkbTypes.PolygonGeometry
+ (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
+ source.fields(), source.wkbType(), source.sourceCrs())
- writer = self.getOutputFromName(
- self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
+ features = source.getFeatures()
+ total = 100.0 / source.featureCount()
- features = QgsProcessingUtils.getFeatures(layer, context)
- total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
for current, f in enumerate(features):
+ if feedback.isCanceled():
+ break
+
feature = f
if feature.hasGeometry():
- new_geometry = feature.geometry().densifyByCount(int(vertices))
+ new_geometry = feature.geometry().densifyByCount(vertices)
feature.setGeometry(new_geometry)
- writer.addFeature(feature)
+ sink.addFeature(feature)
feedback.setProgress(int(current * total))
- del writer
+ return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
index 6e860c023dd..f328c8eb6e6 100644
--- a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
+++ b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
@@ -31,13 +31,12 @@ from math import sqrt
from qgis.core import (QgsWkbTypes,
QgsApplication,
- QgsProcessingUtils)
-
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterNumber,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer,
+ QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.parameters import ParameterVector
-from processing.core.parameters import ParameterNumber
-from processing.core.outputs import OutputVector
-from processing.tools import dataobjects
class DensifyGeometriesInterval(QgisAlgorithm):
@@ -57,13 +56,15 @@ class DensifyGeometriesInterval(QgisAlgorithm):
def __init__(self):
super().__init__()
- self.addParameter(ParameterVector(self.INPUT,
- self.tr('Input layer'),
- [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_LINE]))
- self.addParameter(ParameterNumber(self.INTERVAL,
- self.tr('Interval between vertices to add'), 0.0, 10000000.0, 1.0))
- self.addOutput(OutputVector(self.OUTPUT, self.tr('Densified')))
+ self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
+ self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon, QgsProcessingParameterDefinition.TypeVectorLine]))
+ self.addParameter(QgsProcessingParameterNumber(self.INTERVAL,
+ self.tr('Interval between vertices to add'), QgsProcessingParameterNumber.Double,
+ 1, False, 0, 10000000))
+
+ self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
+ self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
def name(self):
return 'densifygeometriesgivenaninterval'
@@ -72,23 +73,24 @@ class DensifyGeometriesInterval(QgisAlgorithm):
return self.tr('Densify geometries given an interval')
def processAlgorithm(self, parameters, context, feedback):
- layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
- interval = self.getParameterValue(self.INTERVAL)
+ source = self.parameterAsSource(parameters, self.INPUT, context)
+ interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
- isPolygon = layer.geometryType() == QgsWkbTypes.PolygonGeometry
+ (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
+ source.fields(), source.wkbType(), source.sourceCrs())
- writer = self.getOutputFromName(
- self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
-
- features = QgsProcessingUtils.getFeatures(layer, context)
- total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
+ features = source.getFeatures()
+ total = 100.0 / source.featureCount()
for current, f in enumerate(features):
+ if feedback.isCanceled():
+ break
+
feature = f
if feature.hasGeometry():
- new_geometry = feature.geometry().densifyByCount(float(interval))
+ new_geometry = feature.geometry().densifyByDistance(float(interval))
feature.setGeometry(new_geometry)
- writer.addFeature(feature)
+ sink.addFeature(feature)
feedback.setProgress(int(current * total))
- del writer
+ return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/DropGeometry.py b/python/plugins/processing/algs/qgis/DropGeometry.py
index 1c68e076350..46171d9d4de 100644
--- a/python/plugins/processing/algs/qgis/DropGeometry.py
+++ b/python/plugins/processing/algs/qgis/DropGeometry.py
@@ -29,11 +29,11 @@ from qgis.core import (QgsFeatureRequest,
QgsWkbTypes,
QgsCoordinateReferenceSystem,
QgsApplication,
- QgsProcessingUtils)
+ QgsProcessingParameterDefinition,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.parameters import ParameterVector
-from processing.core.outputs import OutputVector
-from processing.tools import dataobjects
class DropGeometry(QgisAlgorithm):
@@ -55,11 +55,10 @@ class DropGeometry(QgisAlgorithm):
def __init__(self):
super().__init__()
- self.addParameter(ParameterVector(self.INPUT_LAYER,
- self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POINT,
- dataobjects.TYPE_VECTOR_LINE,
- dataobjects.TYPE_VECTOR_POLYGON]))
- self.addOutput(OutputVector(self.OUTPUT_TABLE, self.tr('Dropped geometry')))
+
+ self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPoint, QgsProcessingParameterDefinition.TypeVectorLine, QgsProcessingParameterDefinition.TypeVectorPolygon]))
+ self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, self.tr('Dropped geometry')))
+ self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_TABLE, self.tr("Dropped geometry")))
def name(self):
return 'dropgeometries'
@@ -68,17 +67,20 @@ class DropGeometry(QgisAlgorithm):
return self.tr('Drop geometries')
def processAlgorithm(self, parameters, context, feedback):
- layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
- writer = self.getOutputFromName(
- self.OUTPUT_TABLE).getVectorWriter(layer.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem(),
- context)
+ source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
+ (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context,
+ source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
- features = QgsProcessingUtils.getFeatures(layer, context, request)
- total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
+ features = source.getFeatures(request)
+ total = 100.0 / source.featureCount()
for current, input_feature in enumerate(features):
- writer.addFeature(input_feature)
+ if feedback.isCanceled():
+ break
+
+ input_feature.clearGeometry()
+ sink.addFeature(input_feature)
feedback.setProgress(int(current * total))
- del writer
+ return {self.OUTPUT_TABLE: dest_id}
diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
index abd5a94d0f0..2fe26a26bc5 100755
--- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
+++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
@@ -65,7 +65,8 @@ from .ExtractByExpression import ExtractByExpression
# from .Centroids import Centroids
# from .Delaunay import Delaunay
# from .VoronoiPolygons import VoronoiPolygons
-# from .DensifyGeometries import DensifyGeometries
+from .DensifyGeometries import DensifyGeometries
+from .DensifyGeometriesInterval import DensifyGeometriesInterval
from .MultipartToSingleparts import MultipartToSingleparts
# from .SimplifyGeometries import SimplifyGeometries
# from .LinesToPolygons import LinesToPolygons
@@ -84,10 +85,9 @@ from .ExtentFromLayer import ExtentFromLayer
# from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
# from .SelectByLocation import SelectByLocation
# from .Union import Union
-# from .DensifyGeometriesInterval import DensifyGeometriesInterval
# from .SpatialJoin import SpatialJoin
from .DeleteColumn import DeleteColumn
-# from .DeleteHoles import DeleteHoles
+from .DeleteHoles import DeleteHoles
# from .DeleteDuplicateGeometries import DeleteDuplicateGeometries
# from .TextToFloat import TextToFloat
# from .ExtractByAttribute import ExtractByAttribute
@@ -168,8 +168,8 @@ from .Aspect import Aspect
# from .SnapGeometries import SnapGeometriesToLayer
# from .PoleOfInaccessibility import PoleOfInaccessibility
# from .RasterCalculator import RasterCalculator
-# from .CreateAttributeIndex import CreateAttributeIndex
-# from .DropGeometry import DropGeometry
+from .CreateAttributeIndex import CreateAttributeIndex
+from .DropGeometry import DropGeometry
from .BasicStatistics import BasicStatisticsForField
# from .Heatmap import Heatmap
# from .Orthogonalize import Orthogonalize
@@ -205,14 +205,13 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# LinesIntersection(), UniqueValues(), PointDistance(),
# ReprojectLayer(), ExportGeometryInfo(), Centroids(),
# Delaunay(), VoronoiPolygons(), SimplifyGeometries(),
- # DensifyGeometries(), DensifyGeometriesInterval(),
# , SinglePartsToMultiparts(),
# PolygonsToLines(), LinesToPolygons(), ExtractNodes(),
# ConvexHull(), FixedDistanceBuffer(),
# VariableDistanceBuffer(), Dissolve(), Difference(),
# Intersection(), Union(),
# RandomSelection(), RandomSelectionWithinSubsets(),
- # SelectByLocation(), RandomExtract(), DeleteHoles(),
+ # SelectByLocation(), RandomExtract(),
# RandomExtractWithinSubsets(), ExtractByLocation(),
# SpatialJoin(), RegularPoints(), SymmetricalDifference(),
# VectorSplit(), VectorGridLines(), VectorGridPolygons(),
@@ -250,8 +249,8 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# RemoveNullGeometry(),
# ExtendLines(), ExtractSpecificNodes(),
# GeometryByExpression(), SnapGeometriesToLayer(),
- # PoleOfInaccessibility(), CreateAttributeIndex(),
- # DropGeometry(),
+ # PoleOfInaccessibility(),
+ #
# RasterCalculator(), Heatmap(), Orthogonalize(),
# ShortestPathPointToPoint(), ShortestPathPointToLayer(),
# ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
@@ -267,7 +266,12 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
BoundingBox(),
CheckValidity(),
Clip(),
+ CreateAttributeIndex(),
DeleteColumn(),
+ DeleteHoles(),
+ DensifyGeometries(),
+ DensifyGeometriesInterval(),
+ DropGeometry(),
ExtentFromLayer(),
ExtractByExpression(),
GridPolygon(),
diff --git a/python/plugins/processing/gui/BatchInputSelectionPanel.py b/python/plugins/processing/gui/BatchInputSelectionPanel.py
index 26d5c996999..46f21802465 100644
--- a/python/plugins/processing/gui/BatchInputSelectionPanel.py
+++ b/python/plugins/processing/gui/BatchInputSelectionPanel.py
@@ -40,7 +40,7 @@ from qgis.core import (QgsMapLayer,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterDefinition,
- QgsProcessingParameterTable,
+ QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSource)
from processing.gui.MultipleInputDialog import MultipleInputDialog
@@ -105,7 +105,7 @@ class BatchInputSelectionPanel(QWidget):
(isinstance(self.param, QgsProcessingParameterMultipleLayers) and
self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster)):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
- elif isinstance(self.param, QgsProcessingParameterTable):
+ elif isinstance(self.param, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
else:
datatypes = [QgsProcessingParameterDefinition.TypeVectorAny]
diff --git a/python/plugins/processing/gui/BatchOutputSelectionPanel.py b/python/plugins/processing/gui/BatchOutputSelectionPanel.py
index 9b7e9bebabd..588afcbeb8a 100644
--- a/python/plugins/processing/gui/BatchOutputSelectionPanel.py
+++ b/python/plugins/processing/gui/BatchOutputSelectionPanel.py
@@ -36,7 +36,7 @@ from qgis.core import (QgsMapLayer,
QgsProcessingParameterFolderOutput,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSource,
- QgsProcessingParameterTable,
+ QgsProcessingParameterVectorLayer,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterBoolean,
QgsProcessingParameterEnum,
@@ -114,7 +114,7 @@ class BatchOutputSelectionPanel(QWidget):
param = self.alg.parameterDefinitions()[dlg.param_index]
if isinstance(param, (QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSource,
- QgsProcessingParameterTable,
+ QgsProcessingParameterVectorLayer,
QgsProcessingParameterMultipleLayers)):
v = widget.value()
if isinstance(v, QgsMapLayer):
diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py
index e531415c8f9..9efb9ab4058 100644
--- a/python/plugins/processing/gui/wrappers.py
+++ b/python/plugins/processing/gui/wrappers.py
@@ -58,8 +58,8 @@ from qgis.core import (
QgsProcessingParameterEnum,
QgsProcessingParameterString,
QgsProcessingParameterExpression,
- QgsProcessingParameterTable,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputRasterLayer,
@@ -531,7 +531,7 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
elif self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)
elif self.param.layerType() == QgsProcessingParameterDefinition.TypeTable:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterTable, OutputTable)
+ options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterVectorLayer, OutputTable)
else:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, OutputFile)
options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt))
@@ -907,7 +907,7 @@ class StringWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
else:
# strings, numbers, files and table fields are all allowed input types
strings = self.dialog.getAvailableValuesOfType([QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile,
- QgsProcessingParameterTableField, QgsProcessingParameterExpression], QgsProcessingOutputString)
+ QgsProcessingParameterField, QgsProcessingParameterExpression], QgsProcessingOutputString)
options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
if self.param.multiLine():
widget = MultilineTextPanel(options)
@@ -1079,7 +1079,7 @@ class TableWidgetWrapper(WidgetWrapper):
self.combo = QComboBox()
layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)
self.combo.setEditable(True)
- tables = self.dialog.getAvailableValuesOfType(QgsProcessingParameterTable, OutputTable)
+ tables = self.dialog.getAvailableValuesOfType(QgsProcessingParameterVectorLayer, OutputTable)
layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer)
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
self.combo.addItem(self.NOT_SELECTED, None)
@@ -1154,17 +1154,17 @@ class TableFieldWidgetWrapper(WidgetWrapper):
widget = QgsFieldComboBox()
widget.setAllowEmptyFieldName(self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
- if self.param.dataType() == QgsProcessingParameterTableField.Numeric:
+ if self.param.dataType() == QgsProcessingParameterField.Numeric:
widget.setFilters(QgsFieldProxyModel.Numeric)
- elif self.param.dataType() == QgsProcessingParameterTableField.String:
+ elif self.param.dataType() == QgsProcessingParameterField.String:
widget.setFilters(QgsFieldProxyModel.String)
- elif self.param.dataType() == QgsProcessingParameterTableField.DateTime:
+ elif self.param.dataType() == QgsProcessingParameterField.DateTime:
widget.setFilters(QgsFieldProxyModel.Date | QgsFieldProxyModel.Time)
return widget
else:
widget = QComboBox()
widget.setEditable(True)
- fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterTableField, QgsProcessingParameterString], [QgsProcessingOutputString])
+ fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterField, QgsProcessingParameterString], [QgsProcessingOutputString])
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
widget.addItem(self.NOT_SET, None)
for f in fields:
@@ -1202,12 +1202,12 @@ class TableFieldWidgetWrapper(WidgetWrapper):
if self._layer is None:
return []
fieldTypes = []
- if self.param.dataType() == QgsProcessingParameterTableField.String:
+ if self.param.dataType() == QgsProcessingParameterField.String:
fieldTypes = [QVariant.String]
- elif self.param.dataType() == QgsProcessingParameterTableField.Numeric:
+ elif self.param.dataType() == QgsProcessingParameterField.Numeric:
fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong,
QVariant.UInt, QVariant.ULongLong]
- elif self.param.dataType() == QgsProcessingParameterTableField.DateTime:
+ elif self.param.dataType() == QgsProcessingParameterField.DateTime:
fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime]
fieldNames = set()
@@ -1303,7 +1303,7 @@ class WidgetWrapperFactory:
wrapper = StringWidgetWrapper
elif param.type() == 'expression':
wrapper = ExpressionWidgetWrapper
- elif param.type() == 'table':
+ elif param.type() == 'vector':
wrapper = TableWidgetWrapper
elif param.type() == 'field':
wrapper = TableFieldWidgetWrapper
diff --git a/python/plugins/processing/modeler/ModelerAlgorithm.py b/python/plugins/processing/modeler/ModelerAlgorithm.py
index e12c40ba712..ba7be9b802a 100644
--- a/python/plugins/processing/modeler/ModelerAlgorithm.py
+++ b/python/plugins/processing/modeler/ModelerAlgorithm.py
@@ -52,8 +52,8 @@ from qgis.core import (QgsApplication,
QgsProcessingParameterEnum,
QgsProcessingParameterString,
QgsProcessingParameterExpression,
- QgsProcessingParameterTable,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingModelAlgorithm)
from qgis.gui import QgsMessageBar
diff --git a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
index f9ecc84f349..05055506093 100644
--- a/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
+++ b/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py
@@ -45,8 +45,8 @@ from qgis.core import (QgsCoordinateReferenceSystem,
QgsProcessingParameterEnum,
QgsProcessingParameterString,
QgsProcessingParameterExpression,
- QgsProcessingParameterTable,
- QgsProcessingParameterTableField,
+ QgsProcessingParameterVectorLayer,
+ QgsProcessingParameterField,
QgsProcessingParameterFeatureSource)
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (QDialog,
@@ -123,13 +123,13 @@ class ModelerParameterDefinitionDialog(QDialog):
self.state.setChecked(bool(self.param.defaultValue()))
self.verticalLayout.addWidget(self.state)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or \
- isinstance(self.param, QgsProcessingParameterTableField):
+ isinstance(self.param, QgsProcessingParameterField):
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
idx = 0
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
- if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
+ if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == definition.name():
@@ -218,7 +218,7 @@ class ModelerParameterDefinitionDialog(QDialog):
idx = 1
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
- if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)):
+ if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == definition.name():
@@ -301,21 +301,21 @@ class ModelerParameterDefinitionDialog(QDialog):
isinstance(self.param, QgsProcessingParameterBoolean)):
self.param = QgsProcessingParameterBoolean(name, description, self.state.isChecked())
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or
- isinstance(self.param, QgsProcessingParameterTableField)):
+ isinstance(self.param, QgsProcessingParameterField)):
if self.parentCombo.currentIndex() < 0:
QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Wrong or missing parameter values'))
return
parent = self.parentCombo.currentData()
datatype = self.datatypeCombo.currentData()
- self.param = QgsProcessingParameterTableField(name, description, None, parent, datatype, self.multipleCheck.isChecked())
+ self.param = QgsProcessingParameterField(name, description, None, parent, datatype, self.multipleCheck.isChecked())
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_RASTER or
isinstance(self.param, QgsProcessingParameterRasterLayer)):
self.param = QgsProcessingParameterRasterLayer(
name, description)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE or
- isinstance(self.param, QgsProcessingParameterTable)):
- self.param = QgsProcessingParameterTable(
+ isinstance(self.param, QgsProcessingParameterVectorLayer)):
+ self.param = QgsProcessingParameterVectorLayer(
name, description)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or
isinstance(self.param, QgsProcessingParameterFeatureSource)):
diff --git a/python/plugins/processing/tests/AlgorithmsTestBase.py b/python/plugins/processing/tests/AlgorithmsTestBase.py
index 5b4a706d131..1799640ac72 100644
--- a/python/plugins/processing/tests/AlgorithmsTestBase.py
+++ b/python/plugins/processing/tests/AlgorithmsTestBase.py
@@ -50,7 +50,7 @@ from processing.script.ScriptAlgorithm import ScriptAlgorithm # NOQA
from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider # NOQA
from processing.algs.qgis.QGISAlgorithmProvider import QGISAlgorithmProvider # NOQA
-from processing.algs.grass7.Grass7AlgorithmProvider import Grass7AlgorithmProvider # NOQA
+#from processing.algs.grass7.Grass7AlgorithmProvider import Grass7AlgorithmProvider # NOQA
from processing.algs.gdal.GdalAlgorithmProvider import GdalAlgorithmProvider # NOQA
from processing.algs.saga.SagaAlgorithmProvider import SagaAlgorithmProvider # NOQA
from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider # NOQA
diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
index deedd9fb0b3..aa9797da44c 100644
--- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
+++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
@@ -15,16 +15,16 @@ tests:
# geometry:
# precision: 7
#
-# - name: Delete Holes
-# algorithm: qgis:deleteholes
-# params:
-# - name: polys.gml
-# type: vector
-# results:
-# OUTPUT:
-# name: expected/polys_deleteholes.gml
-# type: vector
-#
+ - name: Delete Holes
+ algorithm: qgis:deleteholes
+ params:
+ - name: polys.gml
+ type: vector
+ results:
+ OUTPUT:
+ name: expected/polys_deleteholes.gml
+ type: vector
+
- algorithm: qgis:clip
name: Clip lines by polygons
params:
@@ -128,18 +128,18 @@ tests:
# name: expected/intersection_collection_fallback.shp
# type: vector
#
-# - name: Densify geometries
-# algorithm: qgis:densifygeometries
-# params:
-# INPUT:
-# name: multipolys.gml
-# type: vector
-# VERTICES: 4
-# results:
-# OUTPUT:
-# name: expected/multipolys_densify.gml
-# type: vector
-#
+ - name: Densify geometries
+ algorithm: qgis:densifygeometries
+ params:
+ INPUT:
+ name: multipolys.gml
+ type: vector
+ VERTICES: 4
+ results:
+ OUTPUT:
+ name: expected/multipolys_densify.gml
+ type: vector
+
# - name: Polygons to Lines
# algorithm: qgis:polygonstolines
# params:
@@ -1258,7 +1258,7 @@ tests:
# name: expected/remove_null_polys.gml
# type: vector
#
- - algorithm: qgis:extractbyexpression
+ - algorithm: native:extractbyexpression
name: Extract by Expression
params:
EXPRESSION: left( "Name",1)='A'
@@ -1484,88 +1484,88 @@ tests:
# geometry:
# precision: 7
#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (is null)
-# params:
-# FIELD: intval
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '8'
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_null.gml
-# type: vector
-#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (is not null)
-# params:
-# FIELD: intval
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '9'
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_not_null.gml
-# type: vector
-#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (starts with)
-# params:
-# FIELD: name
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '6'
-# VALUE: A
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_startswith.gml
-# type: vector
-#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (contains)
-# params:
-# FIELD: name
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '7'
-# VALUE: aaa
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_contains.gml
-# type: vector
-#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (does not contain)
-# params:
-# FIELD: name
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '10'
-# VALUE: a
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_does_not_contain.gml
-# type: vector
-#
-# - algorithm: qgis:extractbyattribute
-# name: Extract by attribute (greater)
-# params:
-# FIELD: floatval
-# INPUT:
-# name: polys.gml
-# type: vector
-# OPERATOR: '2'
-# VALUE: '1'
-# results:
-# OUTPUT:
-# name: expected/extract_by_attribute_greater.gml
-# type: vector
-#
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (is null)
+ params:
+ FIELD: intval
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '8'
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_null.gml
+ type: vector
+
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (is not null)
+ params:
+ FIELD: intval
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '9'
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_not_null.gml
+ type: vector
+
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (starts with)
+ params:
+ FIELD: name
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '6'
+ VALUE: A
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_startswith.gml
+ type: vector
+
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (contains)
+ params:
+ FIELD: name
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '7'
+ VALUE: aaa
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_contains.gml
+ type: vector
+
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (does not contain)
+ params:
+ FIELD: name
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '10'
+ VALUE: a
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_does_not_contain.gml
+ type: vector
+
+ - algorithm: native:extractbyattribute
+ name: Extract by attribute (greater)
+ params:
+ FIELD: floatval
+ INPUT:
+ name: polys.gml
+ type: vector
+ OPERATOR: '2'
+ VALUE: '1'
+ results:
+ OUTPUT:
+ name: expected/extract_by_attribute_greater.gml
+ type: vector
+
# - algorithm: qgis:createattributeindex
# name: Create Attribute Index (only tests for python errors, does not check result)
# params:
@@ -1665,18 +1665,18 @@ tests:
# compare:
# geometry:
# precision: 7
-#
-# - algorithm: qgis:dropgeometries
-# name: Drop geometries
-# params:
-# INPUT_LAYER:
-# name: polys.gml
-# type: vector
-# results:
-# OUTPUT_TABLE:
-# name: expected/dropped_geometry.csv
-# type: vector
-#
+
+ - algorithm: qgis:dropgeometries
+ name: Drop geometries
+ params:
+ INPUT_LAYER:
+ name: polys.gml
+ type: vector
+ results:
+ OUTPUT_TABLE:
+ name: expected/dropped_geometry.csv
+ type: vector
+
# - algorithm: qgis:creategridlines
# name: Create grid (lines)
# params:
@@ -1808,30 +1808,30 @@ tests:
geometry:
precision: 7
-# - algorithm: qgis:deleteholes
-# name: Delete holes (no min)
-# params:
-# INPUT:
-# name: custom/remove_holes.gml
-# type: vector
-# MIN_AREA: 0.0
-# results:
-# OUTPUT:
-# name: expected/removed_holes.gml
-# type: vector
-#
-# - algorithm: qgis:deleteholes
-# name: Delete holes (with min)
-# params:
-# INPUT:
-# name: custom/remove_holes.gml
-# type: vector
-# MIN_AREA: 5.0
-# results:
-# OUTPUT:
-# name: expected/removed_holes_min_area.gml
-# type: vector
-#
+ - algorithm: qgis:deleteholes
+ name: Delete holes (no min)
+ params:
+ INPUT:
+ name: custom/remove_holes.gml
+ type: vector
+ MIN_AREA: 0.0
+ results:
+ OUTPUT:
+ name: expected/removed_holes.gml
+ type: vector
+
+ - algorithm: qgis:deleteholes
+ name: Delete holes (with min)
+ params:
+ INPUT:
+ name: custom/remove_holes.gml
+ type: vector
+ MIN_AREA: 5.0
+ results:
+ OUTPUT:
+ name: expected/removed_holes_min_area.gml
+ type: vector
+
- algorithm: qgis:basicstatisticsforfields
name: Basic stats datetime
params:
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 5073bb61280..ebb05d6a16c 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -3620,7 +3620,7 @@ void QgisApp::updateRecentProjectPaths()
{
QAction *action = mRecentProjectsMenu->addAction( QStringLiteral( "%1 (%2)" ).arg( recentProject.title != recentProject.path ? recentProject.title : QFileInfo( recentProject.path ).baseName(),
QDir::toNativeSeparators( recentProject.path ) ) );
- action->setEnabled( QFile::exists( ( recentProject.path ) ) );
+ //action->setEnabled( QFile::exists( ( recentProject.path ) ) );
action->setData( recentProject.path );
}
diff --git a/src/core/processing/qgsnativealgorithms.cpp b/src/core/processing/qgsnativealgorithms.cpp
index 2a6d6a479cc..9871f4d9b50 100644
--- a/src/core/processing/qgsnativealgorithms.cpp
+++ b/src/core/processing/qgsnativealgorithms.cpp
@@ -58,12 +58,15 @@ bool QgsNativeAlgorithms::supportsNonFileBasedOutput() const
void QgsNativeAlgorithms::loadAlgorithms()
{
- addAlgorithm( new QgsCentroidAlgorithm() );
addAlgorithm( new QgsBufferAlgorithm() );
- addAlgorithm( new QgsDissolveAlgorithm() );
+ addAlgorithm( new QgsCentroidAlgorithm() );
addAlgorithm( new QgsClipAlgorithm() );
- addAlgorithm( new QgsTransformAlgorithm() );
+ addAlgorithm( new QgsDissolveAlgorithm() );
+ addAlgorithm( new QgsExtractByAttributeAlgorithm() );
+ addAlgorithm( new QgsExtractByExpressionAlgorithm() );
+ addAlgorithm( new QgsMultipartToSinglepartAlgorithm() );
addAlgorithm( new QgsSubdivideAlgorithm() );
+ addAlgorithm( new QgsTransformAlgorithm() );
}
@@ -244,8 +247,8 @@ QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap ¶meters,
QgsDissolveAlgorithm::QgsDissolveAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
- addParameter( new QgsProcessingParameterTableField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID fields" ), QVariant(),
- QStringLiteral( "INPUT" ), QgsProcessingParameterTableField::Any, true, true ) );
+ addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID fields" ), QVariant(),
+ QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true, true ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
@@ -664,6 +667,380 @@ QVariantMap QgsSubdivideAlgorithm::processAlgorithm( const QVariantMap ¶mete
return outputs;
}
+
+
+QgsMultipartToSinglepartAlgorithm::QgsMultipartToSinglepartAlgorithm()
+{
+ addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
+
+ addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Single parts" ) ) );
+ addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Single parts" ) ) );
+}
+
+QString QgsMultipartToSinglepartAlgorithm::shortHelpString() const
+{
+ return QObject::tr( "This algorithm takes a vector layer with multipart geometries and generates a new one in which all geometries contain "
+ "a single part. Features with multipart geometries are divided in as many different features as parts the geometry "
+ "contain, and the same attributes are used for each of them." );
+}
+
+QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
+{
+ std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
+ if ( !source )
+ return QVariantMap();
+
+ QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( source->wkbType() );
+
+ QString dest;
+ std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
+ sinkType, source->sourceCrs(), dest ) );
+ if ( !sink )
+ return QVariantMap();
+
+ long count = source->featureCount();
+ if ( count <= 0 )
+ return QVariantMap();
+
+ QgsFeature f;
+ QgsFeatureIterator it = source->getFeatures();
+
+ double step = 100.0 / count;
+ int current = 0;
+ while ( it.nextFeature( f ) )
+ {
+ if ( feedback->isCanceled() )
+ {
+ break;
+ }
+
+ QgsFeature out = f;
+ if ( out.hasGeometry() )
+ {
+ QgsGeometry inputGeometry = f.geometry();
+ if ( inputGeometry.isMultipart() )
+ {
+ Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() )
+ {
+ out.setGeometry( g );
+ sink->addFeature( out );
+ }
+ }
+ else
+ {
+ sink->addFeature( out );
+ }
+ }
+ else
+ {
+ // feature with null geometry
+ sink->addFeature( out );
+ }
+
+ feedback->setProgress( current * step );
+ current++;
+ }
+
+ QVariantMap outputs;
+ outputs.insert( QStringLiteral( "OUTPUT" ), dest );
+ return outputs;
+}
+
+
+QgsExtractByExpressionAlgorithm::QgsExtractByExpressionAlgorithm()
+{
+ addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
+ addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "INPUT" ) ) );
+
+ addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching features" ) ) );
+ addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching (expression)" ) ) );
+ addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching" ),
+ QgsProcessingParameterDefinition::TypeVectorAny, QVariant(), true ) );
+ addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching (expression)" ) ) );
+}
+
+QString QgsExtractByExpressionAlgorithm::shortHelpString() const
+{
+ return QObject::tr( "This algorithm creates a new vector layer that only contains matching features from an input layer. "
+ "The criteria for adding features to the resulting layer is based on a QGIS expression.\n\n"
+ "For more information about expressions see the user manual" );
+}
+
+QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
+{
+ std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
+ if ( !source )
+ return QVariantMap();
+
+ QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
+
+ QString matchingSinkId;
+ std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
+ source->wkbType(), source->sourceCrs(), matchingSinkId ) );
+ if ( !matchingSink )
+ return QVariantMap();
+
+ QString nonMatchingSinkId;
+ std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, source->fields(),
+ source->wkbType(), source->sourceCrs(), nonMatchingSinkId ) );
+
+ QgsExpression expression( expressionString );
+ if ( expression.hasParserError() )
+ {
+ // raise GeoAlgorithmExecutionException(expression.parserErrorString())
+ return QVariantMap();
+ }
+
+ QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
+
+ long count = source->featureCount();
+ if ( count <= 0 )
+ return QVariantMap();
+
+ double step = 100.0 / count;
+ int current = 0;
+
+ if ( !nonMatchingSink )
+ {
+ // not saving failing features - so only fetch good features
+ QgsFeatureRequest req;
+ req.setFilterExpression( expressionString );
+ req.setExpressionContext( expressionContext );
+
+ QgsFeatureIterator it = source->getFeatures( req );
+ QgsFeature f;
+ while ( it.nextFeature( f ) )
+ {
+ if ( feedback->isCanceled() )
+ {
+ break;
+ }
+
+ matchingSink->addFeature( f );
+
+ feedback->setProgress( current * step );
+ current++;
+ }
+ }
+ else
+ {
+ // saving non-matching features, so we need EVERYTHING
+ expressionContext.setFields( source->fields() );
+ expression.prepare( &expressionContext );
+
+ QgsFeatureIterator it = source->getFeatures();
+ QgsFeature f;
+ while ( it.nextFeature( f ) )
+ {
+ if ( feedback->isCanceled() )
+ {
+ break;
+ }
+
+ expressionContext.setFeature( f );
+ if ( expression.evaluate( &expressionContext ).toBool() )
+ {
+ matchingSink->addFeature( f );
+ }
+ else
+ {
+ nonMatchingSink->addFeature( f );
+ }
+
+ feedback->setProgress( current * step );
+ current++;
+ }
+ }
+
+
+ QVariantMap outputs;
+ outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
+ if ( nonMatchingSink )
+ outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
+ return outputs;
+}
+
+
+QgsExtractByAttributeAlgorithm::QgsExtractByAttributeAlgorithm()
+{
+ addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
+ addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Selection attribute" ), QVariant(), QStringLiteral( "INPUT" ) ) );
+ addParameter( new QgsProcessingParameterEnum( QStringLiteral( "OPERATOR" ), QObject::tr( "Operator" ), QStringList()
+ << QObject::tr( "=" )
+ << QObject::trUtf8( "≠" )
+ << QObject::tr( ">" )
+ << QObject::tr( ">=" )
+ << QObject::tr( "<" )
+ << QObject::tr( "<=" )
+ << QObject::tr( "begins with" )
+ << QObject::tr( "contains" )
+ << QObject::tr( "is null" )
+ << QObject::tr( "is not null" )
+ << QObject::tr( "does not contain" ) ) );
+ addParameter( new QgsProcessingParameterString( QStringLiteral( "VALUE" ), QObject::tr( "Value" ), QVariant(), false, true ) );
+
+ addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Extracted (attribute)" ) ) );
+ addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching (attribute)" ) ) );
+ addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Extracted (non-matching)" ),
+ QgsProcessingParameterDefinition::TypeVectorAny, QVariant(), true ) );
+ addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching (attribute)" ) ) );
+}
+
+QString QgsExtractByAttributeAlgorithm::shortHelpString() const
+{
+ return QObject::tr( " This algorithm creates a new vector layer that only contains matching features from an input layer. "
+ "The criteria for adding features to the resulting layer is defined based on the values "
+ "of an attribute from the input layer." );
+}
+
+QVariantMap QgsExtractByAttributeAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
+{
+ std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
+ if ( !source )
+ return QVariantMap();
+
+ QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
+ Operation op = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) );
+ QString value = parameterAsString( parameters, QStringLiteral( "VALUE" ), context );
+
+ QString matchingSinkId;
+ std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
+ source->wkbType(), source->sourceCrs(), matchingSinkId ) );
+ if ( !matchingSink )
+ return QVariantMap();
+
+ QString nonMatchingSinkId;
+ std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, source->fields(),
+ source->wkbType(), source->sourceCrs(), nonMatchingSinkId ) );
+
+
+ int idx = source->fields().lookupField( fieldName );
+ QVariant::Type fieldType = source->fields().at( idx ).type();
+
+ if ( fieldType != QVariant::String && ( op == BeginsWith || op == Contains || op == DoesNotContain ) )
+ {
+#if 0
+ op = ''.join( ['"%s", ' % o for o in self.STRING_OPERATORS] )
+ raise GeoAlgorithmExecutionException(
+ self.tr( 'Operators {0} can be used only with string fields.' ).format( op ) )
+#endif
+ return QVariantMap();
+ }
+
+ QString fieldRef = QgsExpression::quotedColumnRef( fieldName );
+ QString quotedVal = QgsExpression::quotedValue( value );
+ QString expr;
+ switch ( op )
+ {
+ case Equals:
+ expr = QStringLiteral( "%1 = %3" ).arg( fieldRef, quotedVal );
+ break;
+ case NotEquals:
+ expr = QStringLiteral( "%1 != %3" ).arg( fieldRef, quotedVal );
+ break;
+ case GreaterThan:
+ expr = QStringLiteral( "%1 > %3" ).arg( fieldRef, quotedVal );
+ break;
+ case GreaterThanEqualTo:
+ expr = QStringLiteral( "%1 >= %3" ).arg( fieldRef, quotedVal );
+ break;
+ case LessThan:
+ expr = QStringLiteral( "%1 < %3" ).arg( fieldRef, quotedVal );
+ break;
+ case LessThanEqualTo:
+ expr = QStringLiteral( "%1 <= %3" ).arg( fieldRef, quotedVal );
+ break;
+ case BeginsWith:
+ expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, value );
+ break;
+ case Contains:
+ expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, value );
+ break;
+ case IsNull:
+ expr = QStringLiteral( "%1 IS NULL" ).arg( fieldRef );
+ break;
+ case IsNotNull:
+ expr = QStringLiteral( "%1 IS NOT NULL" ).arg( fieldRef );
+ break;
+ case DoesNotContain:
+ expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, value );
+ break;
+ }
+
+ QgsExpression expression( expr );
+ if ( expression.hasParserError() )
+ {
+ // raise GeoAlgorithmExecutionException(expression.parserErrorString())
+ return QVariantMap();
+ }
+
+ QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
+
+ long count = source->featureCount();
+ if ( count <= 0 )
+ return QVariantMap();
+
+ double step = 100.0 / count;
+ int current = 0;
+
+ if ( !nonMatchingSink )
+ {
+ // not saving failing features - so only fetch good features
+ QgsFeatureRequest req;
+ req.setFilterExpression( expr );
+ req.setExpressionContext( expressionContext );
+
+ QgsFeatureIterator it = source->getFeatures( req );
+ QgsFeature f;
+ while ( it.nextFeature( f ) )
+ {
+ if ( feedback->isCanceled() )
+ {
+ break;
+ }
+
+ matchingSink->addFeature( f );
+
+ feedback->setProgress( current * step );
+ current++;
+ }
+ }
+ else
+ {
+ // saving non-matching features, so we need EVERYTHING
+ expressionContext.setFields( source->fields() );
+ expression.prepare( &expressionContext );
+
+ QgsFeatureIterator it = source->getFeatures();
+ QgsFeature f;
+ while ( it.nextFeature( f ) )
+ {
+ if ( feedback->isCanceled() )
+ {
+ break;
+ }
+
+ expressionContext.setFeature( f );
+ if ( expression.evaluate( &expressionContext ).toBool() )
+ {
+ matchingSink->addFeature( f );
+ }
+ else
+ {
+ nonMatchingSink->addFeature( f );
+ }
+
+ feedback->setProgress( current * step );
+ current++;
+ }
+ }
+
+
+ QVariantMap outputs;
+ outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
+ if ( nonMatchingSink )
+ outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
+ return outputs;
+}
+
///@endcond
-
-
diff --git a/src/core/processing/qgsnativealgorithms.h b/src/core/processing/qgsnativealgorithms.h
index 0b9de30f4f6..8669df80955 100644
--- a/src/core/processing/qgsnativealgorithms.h
+++ b/src/core/processing/qgsnativealgorithms.h
@@ -135,6 +135,67 @@ class QgsDissolveAlgorithm : public QgsProcessingAlgorithm
};
+/**
+ * Native extract by attribute algorithm.
+ */
+class QgsExtractByAttributeAlgorithm : public QgsProcessingAlgorithm
+{
+
+ public:
+
+ enum Operation
+ {
+ Equals,
+ NotEquals,
+ GreaterThan,
+ GreaterThanEqualTo,
+ LessThan,
+ LessThanEqualTo,
+ BeginsWith,
+ Contains,
+ IsNull,
+ IsNotNull,
+ DoesNotContain,
+ };
+
+ QgsExtractByAttributeAlgorithm();
+
+ QString name() const override { return QStringLiteral( "extractbyattribute" ); }
+ QString displayName() const override { return QObject::tr( "Extract by attribute" ); }
+ virtual QStringList tags() const override { return QObject::tr( "extract,filter,attribute,value,contains,null,field" ).split( ',' ); }
+ QString group() const override { return QObject::tr( "Vector selection tools" ); }
+ QString shortHelpString() const override;
+
+ protected:
+
+ virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
+ QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
+
+};
+
+/**
+ * Native extract by expression algorithm.
+ */
+class QgsExtractByExpressionAlgorithm : public QgsProcessingAlgorithm
+{
+
+ public:
+
+ QgsExtractByExpressionAlgorithm();
+
+ QString name() const override { return QStringLiteral( "extractbyexpression" ); }
+ QString displayName() const override { return QObject::tr( "Extract by expression" ); }
+ virtual QStringList tags() const override { return QObject::tr( "extract,filter,expression,field" ).split( ',' ); }
+ QString group() const override { return QObject::tr( "Vector selection tools" ); }
+ QString shortHelpString() const override;
+
+ protected:
+
+ virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
+ QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
+
+};
+
/**
* Native clip algorithm.
*/
@@ -182,6 +243,29 @@ class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
};
+/**
+ * Native multipart to singlepart algorithm.
+ */
+class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm
+{
+
+ public:
+
+ QgsMultipartToSinglepartAlgorithm();
+
+ QString name() const override { return QStringLiteral( "multiparttosingleparts" ); }
+ QString displayName() const override { return QObject::tr( "Multipart to singleparts" ); }
+ virtual QStringList tags() const override { return QObject::tr( "multi,single,multiple,split,dump" ).split( ',' ); }
+ QString group() const override { return QObject::tr( "Vector geometry tools" ); }
+ QString shortHelpString() const override;
+
+ protected:
+
+ virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
+ QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
+
+};
+
///@endcond PRIVATE
#endif // QGSNATIVEALGORITHMS_H
diff --git a/src/core/processing/qgsprocessingparameters.cpp b/src/core/processing/qgsprocessingparameters.cpp
index fa906a307a5..09eef8b0c73 100644
--- a/src/core/processing/qgsprocessingparameters.cpp
+++ b/src/core/processing/qgsprocessingparameters.cpp
@@ -744,14 +744,16 @@ QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromVariantM
def.reset( new QgsProcessingParameterString( name ) );
else if ( type == QStringLiteral( "expression" ) )
def.reset( new QgsProcessingParameterExpression( name ) );
- else if ( type == QStringLiteral( "table" ) )
- def.reset( new QgsProcessingParameterTable( name ) );
+ else if ( type == QStringLiteral( "vector" ) )
+ def.reset( new QgsProcessingParameterVectorLayer( name ) );
else if ( type == QStringLiteral( "field" ) )
- def.reset( new QgsProcessingParameterTableField( name ) );
+ def.reset( new QgsProcessingParameterField( name ) );
else if ( type == QStringLiteral( "source" ) )
def.reset( new QgsProcessingParameterFeatureSource( name ) );
else if ( type == QStringLiteral( "sink" ) )
def.reset( new QgsProcessingParameterFeatureSink( name ) );
+ else if ( type == QStringLiteral( "vectorOut" ) )
+ def.reset( new QgsProcessingParameterVectorOutput( name ) );
else if ( type == QStringLiteral( "rasterOut" ) )
def.reset( new QgsProcessingParameterRasterOutput( name ) );
else if ( type == QStringLiteral( "fileOut" ) )
@@ -1731,13 +1733,53 @@ bool QgsProcessingParameterExpression::fromVariantMap( const QVariantMap &map )
return true;
}
-QgsProcessingParameterTable::QgsProcessingParameterTable( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
+QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
}
-QgsProcessingParameterTableField::QgsProcessingParameterTableField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional )
+bool QgsProcessingParameterVectorLayer::checkValueIsAcceptable( const QVariant &var, QgsProcessingContext *context ) const
+{
+ if ( !var.isValid() )
+ return mFlags & FlagOptional;
+
+ if ( var.canConvert() )
+ {
+ return true;
+ }
+
+ if ( qobject_cast< QgsVectorLayer * >( qvariant_cast( var ) ) )
+ return true;
+
+ if ( var.type() != QVariant::String || var.toString().isEmpty() )
+ return mFlags & FlagOptional;
+
+ if ( !context )
+ {
+ // that's as far as we can get without a context
+ return true;
+ }
+
+ // try to load as layer
+ if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context ) )
+ return true;
+
+ return false;
+}
+
+QString QgsProcessingParameterVectorLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
+{
+ if ( val.canConvert() )
+ return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
+
+ QVariantMap p;
+ p.insert( name(), val );
+ QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( this, p, context );
+ return layer ? QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' ) : QString();
+}
+
+QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mParentLayerParameter( parentLayerParameterName )
, mDataType( type )
@@ -1746,7 +1788,7 @@ QgsProcessingParameterTableField::QgsProcessingParameterTableField( const QStrin
}
-bool QgsProcessingParameterTableField::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
+bool QgsProcessingParameterField::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
{
if ( !input.isValid() )
return mFlags & FlagOptional;
@@ -1778,7 +1820,7 @@ bool QgsProcessingParameterTableField::checkValueIsAcceptable( const QVariant &i
return true;
}
-QString QgsProcessingParameterTableField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
+QString QgsProcessingParameterField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
@@ -1805,37 +1847,37 @@ QString QgsProcessingParameterTableField::valueAsPythonString( const QVariant &v
return value.toString().prepend( '\'' ).append( '\'' );
}
-QString QgsProcessingParameterTableField::parentLayerParameter() const
+QString QgsProcessingParameterField::parentLayerParameter() const
{
return mParentLayerParameter;
}
-void QgsProcessingParameterTableField::setParentLayerParameter( const QString &parentLayerParameter )
+void QgsProcessingParameterField::setParentLayerParameter( const QString &parentLayerParameter )
{
mParentLayerParameter = parentLayerParameter;
}
-QgsProcessingParameterTableField::DataType QgsProcessingParameterTableField::dataType() const
+QgsProcessingParameterField::DataType QgsProcessingParameterField::dataType() const
{
return mDataType;
}
-void QgsProcessingParameterTableField::setDataType( const DataType &dataType )
+void QgsProcessingParameterField::setDataType( const DataType &dataType )
{
mDataType = dataType;
}
-bool QgsProcessingParameterTableField::allowMultiple() const
+bool QgsProcessingParameterField::allowMultiple() const
{
return mAllowMultiple;
}
-void QgsProcessingParameterTableField::setAllowMultiple( bool allowMultiple )
+void QgsProcessingParameterField::setAllowMultiple( bool allowMultiple )
{
mAllowMultiple = allowMultiple;
}
-QVariantMap QgsProcessingParameterTableField::toVariantMap() const
+QVariantMap QgsProcessingParameterField::toVariantMap() const
{
QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameter );
@@ -1844,7 +1886,7 @@ QVariantMap QgsProcessingParameterTableField::toVariantMap() const
return map;
}
-bool QgsProcessingParameterTableField::fromVariantMap( const QVariantMap &map )
+bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
{
QgsProcessingParameterDefinition::fromVariantMap( map );
mParentLayerParameter = map.value( QStringLiteral( "parent_layer" ) ).toString();
@@ -2208,3 +2250,100 @@ bool QgsProcessingParameterFolderOutput::checkValueIsAcceptable( const QVariant
return true;
}
+
+QgsProcessingParameterVectorOutput::QgsProcessingParameterVectorOutput( const QString &name, const QString &description, QgsProcessingParameterDefinition::LayerType type, const QVariant &defaultValue, bool optional )
+ : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
+ , mDataType( type )
+{
+
+}
+
+bool QgsProcessingParameterVectorOutput::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
+{
+ QVariant var = input;
+ if ( !var.isValid() )
+ return mFlags & FlagOptional;
+
+ if ( var.canConvert() )
+ {
+ QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( var );
+ var = fromVar.sink;
+ }
+
+ if ( var.canConvert() )
+ {
+ return true;
+ }
+
+ if ( var.type() != QVariant::String )
+ return false;
+
+ if ( var.toString().isEmpty() )
+ return mFlags & FlagOptional;
+
+ return true;
+}
+
+QString QgsProcessingParameterVectorOutput::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
+{
+ if ( value.canConvert() )
+ return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
+
+ if ( value.canConvert() )
+ {
+ QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( value );
+ if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
+ {
+ return QStringLiteral( "QgsProcessingOutputLayerDefinition('%1')" ).arg( fromVar.sink.staticValue().toString() );
+ }
+ else
+ {
+ return QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('%1'))" ).arg( fromVar.sink.asExpression() );
+ }
+ }
+
+ return value.toString().prepend( '\'' ).append( '\'' );
+}
+
+QgsProcessingParameterDefinition::LayerType QgsProcessingParameterVectorOutput::dataType() const
+{
+ return mDataType;
+}
+
+bool QgsProcessingParameterVectorOutput::hasGeometry() const
+{
+ switch ( mDataType )
+ {
+ case TypeAny:
+ case TypeVectorAny:
+ case TypeVectorPoint:
+ case TypeVectorLine:
+ case TypeVectorPolygon:
+ case TypeTable:
+ return true;
+
+ case TypeRaster:
+ case TypeFile:
+ return false;
+ }
+ return true;
+}
+
+void QgsProcessingParameterVectorOutput::setDataType( QgsProcessingParameterDefinition::LayerType type )
+{
+ mDataType = type;
+}
+
+QVariantMap QgsProcessingParameterVectorOutput::toVariantMap() const
+{
+ QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
+ map.insert( QStringLiteral( "data_type" ), mDataType );
+ return map;
+}
+
+bool QgsProcessingParameterVectorOutput::fromVariantMap( const QVariantMap &map )
+{
+ QgsProcessingParameterDefinition::fromVariantMap( map );
+ mDataType = static_cast< QgsProcessingParameterDefinition::LayerType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
+ return true;
+}
diff --git a/src/core/processing/qgsprocessingparameters.h b/src/core/processing/qgsprocessingparameters.h
index 97617caddb4..edcf74526b8 100644
--- a/src/core/processing/qgsprocessingparameters.h
+++ b/src/core/processing/qgsprocessingparameters.h
@@ -198,14 +198,16 @@ class CORE_EXPORT QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterString;
else if ( sipCpp->type() == "expression" )
sipType = sipType_QgsProcessingParameterExpression;
- else if ( sipCpp->type() == "table" )
- sipType = sipType_QgsProcessingParameterTable;
+ else if ( sipCpp->type() == "vector" )
+ sipType = sipType_QgsProcessingParameterVectorLayer;
else if ( sipCpp->type() == "field" )
- sipType = sipType_QgsProcessingParameterTableField;
+ sipType = sipType_QgsProcessingParameterField;
else if ( sipCpp->type() == "source" )
sipType = sipType_QgsProcessingParameterFeatureSource;
else if ( sipCpp->type() == "sink" )
sipType = sipType_QgsProcessingParameterFeatureSink;
+ else if ( sipCpp->type() == "vectorOut" )
+ sipType = sipType_QgsProcessingParameterVectorOutput;
else if ( sipCpp->type() == "rasterOut" )
sipType = sipType_QgsProcessingParameterRasterOutput;
else if ( sipCpp->type() == "fileOut" )
@@ -1121,32 +1123,35 @@ class CORE_EXPORT QgsProcessingParameterExpression : public QgsProcessingParamet
};
/**
- * \class QgsProcessingParameterTable
+ * \class QgsProcessingParameterVectorLayer
* \ingroup core
- * A table (i.e. vector layers with or without geometry) parameter for processing algorithms.
+ * A vector layer (with or without geometry) parameter for processing algorithms. Consider using
+ * the more versatile QgsProcessingParameterFeatureSource wherever possible.
* \since QGIS 3.0
*/
-class CORE_EXPORT QgsProcessingParameterTable : public QgsProcessingParameterDefinition
+class CORE_EXPORT QgsProcessingParameterVectorLayer : public QgsProcessingParameterDefinition
{
public:
/**
- * Constructor for QgsProcessingParameterTable.
+ * Constructor for QgsProcessingParameterVectorLayer.
*/
- QgsProcessingParameterTable( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
- bool optional = false );
+ QgsProcessingParameterVectorLayer( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
+ bool optional = false );
- QString type() const override { return QStringLiteral( "table" ); }
+ QString type() const override { return QStringLiteral( "vector" ); }
+ bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
+ QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
/**
- * \class QgsProcessingParameterTableField
+ * \class QgsProcessingParameterField
* \ingroup core
- * A table field parameter for processing algorithms.
+ * A vector layer or feature source field parameter for processing algorithms.
* \since QGIS 3.0
*/
-class CORE_EXPORT QgsProcessingParameterTableField : public QgsProcessingParameterDefinition
+class CORE_EXPORT QgsProcessingParameterField : public QgsProcessingParameterDefinition
{
public:
@@ -1160,13 +1165,13 @@ class CORE_EXPORT QgsProcessingParameterTableField : public QgsProcessingParamet
};
/**
- * Constructor for QgsProcessingParameterTableField.
+ * Constructor for QgsProcessingParameterField.
*/
- QgsProcessingParameterTableField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
- const QString &parentLayerParameterName = QString(),
- DataType type = Any,
- bool allowMultiple = false,
- bool optional = false );
+ QgsProcessingParameterField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
+ const QString &parentLayerParameterName = QString(),
+ DataType type = Any,
+ bool allowMultiple = false,
+ bool optional = false );
QString type() const override { return QStringLiteral( "field" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
@@ -1311,6 +1316,55 @@ class CORE_EXPORT QgsProcessingParameterFeatureSink : public QgsProcessingParame
QgsProcessingParameterDefinition::LayerType mDataType = QgsProcessingParameterDefinition::TypeVectorAny;
};
+
+/**
+ * \class QgsProcessingParameterVectorOutput
+ * \ingroup core
+ * A vector layer output parameter. Consider using the more flexible QgsProcessingParameterFeatureSink wherever
+ * possible.
+ * \since QGIS 3.0
+ */
+class CORE_EXPORT QgsProcessingParameterVectorOutput : public QgsProcessingParameterDefinition
+{
+ public:
+
+ /**
+ * Constructor for QgsProcessingParameterVectorOutput.
+ */
+ QgsProcessingParameterVectorOutput( const QString &name, const QString &description = QString(), QgsProcessingParameterDefinition::LayerType type = QgsProcessingParameterDefinition::TypeVectorAny, const QVariant &defaultValue = QVariant(),
+ bool optional = false );
+
+ QString type() const override { return QStringLiteral( "vectorOut" ); }
+ bool isDestination() const override { return true; }
+ bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
+ QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
+
+ /**
+ * Returns the layer type for layers associated with the parameter.
+ * \see setDataType()
+ */
+ QgsProcessingParameterDefinition::LayerType dataType() const;
+
+ /**
+ * Returns true if the layer is likely to include geometries. In cases were presence of geometry
+ * cannot be reliably determined in advance, this method will default to returning true.
+ */
+ bool hasGeometry() const;
+
+ /**
+ * Sets the layer \a type for the layers associated with the parameter.
+ * \see dataType()
+ */
+ void setDataType( QgsProcessingParameterDefinition::LayerType type );
+
+ QVariantMap toVariantMap() const override;
+ bool fromVariantMap( const QVariantMap &map ) override;
+
+ private:
+
+ QgsProcessingParameterDefinition::LayerType mDataType = QgsProcessingParameterDefinition::TypeVectorAny;
+};
+
/**
* \class QgsProcessingParameterRasterOutput
* \ingroup core
diff --git a/tests/src/core/testqgsprocessing.cpp b/tests/src/core/testqgsprocessing.cpp
index c491fd01840..71c4285e83e 100644
--- a/tests/src/core/testqgsprocessing.cpp
+++ b/tests/src/core/testqgsprocessing.cpp
@@ -314,8 +314,10 @@ class TestQgsProcessing: public QObject
void parameterString();
void parameterExpression();
void parameterField();
+ void parameterVectorLayer();
void parameterFeatureSource();
void parameterFeatureSink();
+ void parameterVectorOut();
void parameterRasterOut();
void parameterFileOut();
void parameterFolderOut();
@@ -2507,7 +2509,7 @@ void TestQgsProcessing::parameterField()
QgsProcessingContext context;
// not optional!
- std::unique_ptr< QgsProcessingParameterTableField > def( new QgsProcessingParameterTableField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterTableField::Any, false, false ) );
+ std::unique_ptr< QgsProcessingParameterField > def( new QgsProcessingParameterField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterField::Any, false, false ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@@ -2525,7 +2527,7 @@ void TestQgsProcessing::parameterField()
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// multiple
- def.reset( new QgsProcessingParameterTableField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterTableField::Any, true, false ) );
+ def.reset( new QgsProcessingParameterField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterField::Any, true, false ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@@ -2544,7 +2546,7 @@ void TestQgsProcessing::parameterField()
QCOMPARE( def->valueAsPythonString( QStringList() << "a" << "b", context ), QStringLiteral( "['a','b']" ) );
QVariantMap map = def->toVariantMap();
- QgsProcessingParameterTableField fromMap( "x" );
+ QgsProcessingParameterField fromMap( "x" );
QVERIFY( fromMap.fromVariantMap( map ) );
QCOMPARE( fromMap.name(), def->name() );
QCOMPARE( fromMap.description(), def->description() );
@@ -2553,11 +2555,11 @@ void TestQgsProcessing::parameterField()
QCOMPARE( fromMap.parentLayerParameter(), def->parentLayerParameter() );
QCOMPARE( fromMap.dataType(), def->dataType() );
QCOMPARE( fromMap.allowMultiple(), def->allowMultiple() );
- def.reset( dynamic_cast< QgsProcessingParameterTableField *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
- QVERIFY( dynamic_cast< QgsProcessingParameterTableField *>( def.get() ) );
+ def.reset( dynamic_cast< QgsProcessingParameterField *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
+ QVERIFY( dynamic_cast< QgsProcessingParameterField *>( def.get() ) );
// optional
- def.reset( new QgsProcessingParameterTableField( "optional", QString(), QString( "def" ), QString(), QgsProcessingParameterTableField::Any, false, true ) );
+ def.reset( new QgsProcessingParameterField( "optional", QString(), QString( "def" ), QString(), QgsProcessingParameterField::Any, false, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@@ -2570,13 +2572,13 @@ void TestQgsProcessing::parameterField()
QCOMPARE( fields, QStringList() << "def" );
// optional, no default
- def.reset( new QgsProcessingParameterTableField( "optional", QString(), QVariant(), QString(), QgsProcessingParameterTableField::Any, false, true ) );
+ def.reset( new QgsProcessingParameterField( "optional", QString(), QVariant(), QString(), QgsProcessingParameterField::Any, false, true ) );
params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QVERIFY( fields.isEmpty() );
//optional with multiples
- def.reset( new QgsProcessingParameterTableField( "optional", QString(), QString( "abc;def" ), QString(), QgsProcessingParameterTableField::Any, true, true ) );
+ def.reset( new QgsProcessingParameterField( "optional", QString(), QString( "abc;def" ), QString(), QgsProcessingParameterField::Any, true, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@@ -2587,12 +2589,102 @@ void TestQgsProcessing::parameterField()
params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "abc" << "def" );
- def.reset( new QgsProcessingParameterTableField( "optional", QString(), QVariantList() << "abc" << "def", QString(), QgsProcessingParameterTableField::Any, true, true ) );
+ def.reset( new QgsProcessingParameterField( "optional", QString(), QVariantList() << "abc" << "def", QString(), QgsProcessingParameterField::Any, true, true ) );
params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "abc" << "def" );
}
+void TestQgsProcessing::parameterVectorLayer()
+{
+ // setup a context
+ QgsProject p;
+ p.setCrs( QgsCoordinateReferenceSystem::fromEpsgId( 28353 ) );
+ QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
+ QString vector1 = testDataDir + "multipoint.shp";
+ QString raster = testDataDir + "landsat.tif";
+ QFileInfo fi1( raster );
+ QFileInfo fi2( vector1 );
+ QgsRasterLayer *r1 = new QgsRasterLayer( fi1.filePath(), "R1" );
+ QgsVectorLayer *v1 = new QgsVectorLayer( fi2.filePath(), "V4", "ogr" );
+ p.addMapLayers( QList() << v1 << r1 );
+ QgsProcessingContext context;
+ context.setProject( &p );
+
+ // not optional!
+ std::unique_ptr< QgsProcessingParameterVectorLayer > def( new QgsProcessingParameterVectorLayer( "non_optional", QString(), QString( "somelayer" ), false ) );
+ QVERIFY( !def->checkValueIsAcceptable( false ) );
+ QVERIFY( !def->checkValueIsAcceptable( true ) );
+ QVERIFY( !def->checkValueIsAcceptable( 5 ) );
+ QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
+ QVERIFY( !def->checkValueIsAcceptable( "" ) );
+ QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
+ QVERIFY( !def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( "layer1231123" ) ) );
+ QVERIFY( def->checkValueIsAcceptable( QVariant::fromValue( v1 ) ) );
+ QVERIFY( !def->checkValueIsAcceptable( QVariant::fromValue( r1 ) ) );
+
+ // should be OK
+ QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
+ // ... unless we use context, when the check that the layer actually exists is performed
+ QVERIFY( !def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp", &context ) );
+
+ // using existing map layer ID
+ QVariantMap params;
+ params.insert( "non_optional", v1->id() );
+ QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
+
+ // using existing layer
+ params.insert( "non_optional", QVariant::fromValue( v1 ) );
+ QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
+
+ // not vector layer
+ params.insert( "non_optional", r1->id() );
+ QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
+
+ // using existing non-vector layer
+ params.insert( "non_optional", QVariant::fromValue( r1 ) );
+ QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
+
+ // string representing a layer source
+ params.insert( "non_optional", vector1 );
+ QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->publicSource(), vector1 );
+
+ // nonsense string
+ params.insert( "non_optional", QString( "i'm not a layer, and nothing you can do will make me one" ) );
+ QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
+
+ QCOMPARE( def->valueAsPythonString( vector1, context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
+ QCOMPARE( def->valueAsPythonString( v1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( v1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
+ QVariantMap map = def->toVariantMap();
+ QgsProcessingParameterVectorLayer fromMap( "x" );
+ QVERIFY( fromMap.fromVariantMap( map ) );
+ QCOMPARE( fromMap.name(), def->name() );
+ QCOMPARE( fromMap.description(), def->description() );
+ QCOMPARE( fromMap.flags(), def->flags() );
+ QCOMPARE( fromMap.defaultValue(), def->defaultValue() );
+ def.reset( dynamic_cast< QgsProcessingParameterVectorLayer *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
+ QVERIFY( dynamic_cast< QgsProcessingParameterVectorLayer *>( def.get() ) );
+
+ // optional
+ def.reset( new QgsProcessingParameterVectorLayer( "optional", QString(), v1->id(), true ) );
+ params.insert( "optional", QVariant() );
+ QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
+ QVERIFY( def->checkValueIsAcceptable( false ) );
+ QVERIFY( def->checkValueIsAcceptable( true ) );
+ QVERIFY( def->checkValueIsAcceptable( 5 ) );
+ QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
+ QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
+ QVERIFY( def->checkValueIsAcceptable( "" ) );
+ QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
+ QVERIFY( def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( "layer1231123" ) ) );
+
+ //optional with direct layer default
+ def.reset( new QgsProcessingParameterVectorLayer( "optional", QString(), QVariant::fromValue( v1 ), true ) );
+ QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
+}
+
void TestQgsProcessing::parameterFeatureSource()
{
// setup a context
@@ -2747,6 +2839,68 @@ void TestQgsProcessing::parameterFeatureSink()
}
+void TestQgsProcessing::parameterVectorOut()
+{
+ // setup a context
+ QgsProject p;
+ p.setCrs( QgsCoordinateReferenceSystem::fromEpsgId( 28353 ) );
+ QgsProcessingContext context;
+ context.setProject( &p );
+
+ // not optional!
+ std::unique_ptr< QgsProcessingParameterVectorOutput > def( new QgsProcessingParameterVectorOutput( "non_optional", QString(), QgsProcessingParameterDefinition::TypeVectorAny, QString( "EPSG:3113" ), false ) );
+ QVERIFY( !def->checkValueIsAcceptable( false ) );
+ QVERIFY( !def->checkValueIsAcceptable( true ) );
+ QVERIFY( !def->checkValueIsAcceptable( 5 ) );
+ QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
+ QVERIFY( !def->checkValueIsAcceptable( "" ) );
+ QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
+ QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( "layer1231123" ) ) );
+
+ // should be OK with or without context - it's an output layer!
+ QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
+ QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp", &context ) );
+
+ QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( "abc" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) );
+ QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
+
+ QVariantMap map = def->toVariantMap();
+ QgsProcessingParameterVectorOutput fromMap( "x" );
+ QVERIFY( fromMap.fromVariantMap( map ) );
+ QCOMPARE( fromMap.name(), def->name() );
+ QCOMPARE( fromMap.description(), def->description() );
+ QCOMPARE( fromMap.flags(), def->flags() );
+ QCOMPARE( fromMap.defaultValue(), def->defaultValue() );
+ QCOMPARE( fromMap.dataType(), def->dataType() );
+ def.reset( dynamic_cast< QgsProcessingParameterVectorOutput *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
+ QVERIFY( dynamic_cast< QgsProcessingParameterVectorOutput *>( def.get() ) );
+
+ // optional
+ def.reset( new QgsProcessingParameterVectorOutput( "optional", QString(), QgsProcessingParameterDefinition::TypeVectorAny, QString(), true ) );
+ QVERIFY( !def->checkValueIsAcceptable( false ) );
+ QVERIFY( !def->checkValueIsAcceptable( true ) );
+ QVERIFY( !def->checkValueIsAcceptable( 5 ) );
+ QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
+ QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
+ QVERIFY( def->checkValueIsAcceptable( "" ) );
+ QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
+ QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( "layer1231123" ) ) );
+
+ // test hasGeometry
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeAny ).hasGeometry() );
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorAny ).hasGeometry() );
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorPoint ).hasGeometry() );
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorLine ).hasGeometry() );
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorPolygon ).hasGeometry() );
+ QVERIFY( !QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeRaster ).hasGeometry() );
+ QVERIFY( !QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeFile ).hasGeometry() );
+ QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeTable ).hasGeometry() );
+
+}
+
void TestQgsProcessing::parameterRasterOut()
{
// setup a context