Skip to content

Commit

Permalink
Merge pull request #4954 from alexbruy/processing-band
Browse files Browse the repository at this point in the history
[FEATURE][needs-docs][processing] add parameter representing raster band
  • Loading branch information
alexbruy committed Aug 4, 2017
2 parents b20f4c6 + 9fe326d commit f964428
Show file tree
Hide file tree
Showing 9 changed files with 452 additions and 67 deletions.
78 changes: 70 additions & 8 deletions python/core/processing/qgsprocessingparameters.sip
Expand Up @@ -189,6 +189,8 @@ class QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterFileDestination;
else if ( sipCpp->type() == QgsProcessingParameterFolderDestination::typeName() )
sipType = sipType_QgsProcessingParameterFolderDestination;
else if ( sipCpp->type() == QgsProcessingParameterBand::typeName() )
sipType = sipType_QgsProcessingParameterBand;
%End
public:

Expand Down Expand Up @@ -1356,17 +1358,17 @@ class QgsProcessingParameterExpression : QgsProcessingParameterDefinition
virtual QStringList dependsOnOtherParameters() const;


QString parentLayerParameter() const;
QString parentLayerParameterName() const;
%Docstring
Returns the name of the parent layer parameter, or an empty string if this is not set.
.. seealso:: setParentLayerParameter()
.. seealso:: setParentLayerParameterName()
:rtype: str
%End

void setParentLayerParameter( const QString &parentLayerParameter );
void setParentLayerParameterName( const QString &parentLayerParameterName );
%Docstring
Sets the name of the parent layer parameter. Use an empty string if this is not required.
.. seealso:: parentLayerParameter()
.. seealso:: parentLayerParameterName()
%End

virtual QVariantMap toVariantMap() const;
Expand Down Expand Up @@ -1485,17 +1487,17 @@ class QgsProcessingParameterField : QgsProcessingParameterDefinition
virtual QStringList dependsOnOtherParameters() const;


QString parentLayerParameter() const;
QString parentLayerParameterName() const;
%Docstring
Returns the name of the parent layer parameter, or an empty string if this is not set.
.. seealso:: setParentLayerParameter()
.. seealso:: setParentLayerParameterName()
:rtype: str
%End

void setParentLayerParameter( const QString &parentLayerParameter );
void setParentLayerParameterName( const QString &parentLayerParameterName );
%Docstring
Sets the name of the parent layer parameter. Use an empty string if this is not required.
.. seealso:: parentLayerParameter()
.. seealso:: parentLayerParameterName()
%End

DataType dataType() const;
Expand Down Expand Up @@ -1970,6 +1972,66 @@ class QgsProcessingParameterFolderDestination : QgsProcessingDestinationParamete

};

class QgsProcessingParameterBand : QgsProcessingParameterDefinition
{
%Docstring
A raster band parameter for Processing algorithms.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsprocessingparameters.h"
%End
public:

QgsProcessingParameterBand( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
const QString &parentLayerParameterName = QString(),
bool optional = false );
%Docstring
Constructor for QgsProcessingParameterBand.
%End

static QString typeName();
%Docstring
Returns the type name for the parameter class.
:rtype: str
%End
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;

virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;

virtual QString asScriptCode() const;

virtual QStringList dependsOnOtherParameters() const;


QString parentLayerParameterName() const;
%Docstring
Returns the name of the parent layer parameter, or an empty string if this is not set.
.. seealso:: setParentLayerParameterName()
:rtype: str
%End

void setParentLayerParameterName( const QString &parentLayerParameterName );
%Docstring
Sets the name of the parent layer parameter. Use an empty string if this is not required.
.. seealso:: parentLayerParameterName()
%End

virtual QVariantMap toVariantMap() const;

virtual bool fromVariantMap( const QVariantMap &map );


static QgsProcessingParameterBand *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) /Factory/;
%Docstring
Creates a new parameter using the definition from a script code.
:rtype: QgsProcessingParameterBand
%End

};



/************************************************************************
Expand Down
10 changes: 5 additions & 5 deletions python/plugins/processing/algs/qgis/RasterLayerStatistics.py
Expand Up @@ -30,7 +30,7 @@
from qgis.core import (QgsRectangle,
QgsRasterBandStats,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterNumber,
QgsProcessingParameterBand,
QgsProcessingParameterFileDestination,
QgsProcessingOutputHtml,
QgsProcessingOutputNumber)
Expand Down Expand Up @@ -60,10 +60,10 @@ def __init__(self):
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterNumber(self.BAND,
self.tr('Band number'),
QgsProcessingParameterNumber.Integer,
1, False, 1, 999))
self.addParameter(QgsProcessingParameterBand(self.BAND,
self.tr('Band number'),
1,
self.INPUT))
self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT_HTML_FILE, self.tr('Statistics'), self.tr('HTML files (*.html)'), None, True))
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Statistics')))

Expand Down
9 changes: 5 additions & 4 deletions python/plugins/processing/algs/qgis/ZonalStatistics.py
Expand Up @@ -35,7 +35,7 @@
QgsProcessingParameterVectorLayer,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsProcessingParameterBand,
QgsProcessingParameterEnum,
QgsProcessingOutputVectorLayer)

Expand Down Expand Up @@ -78,9 +78,10 @@ def initAlgorithm(self, config=None):

self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_RASTER,
self.tr('Raster layer')))
self.addParameter(QgsProcessingParameterNumber(self.RASTER_BAND,
self.tr('Raster band'),
minValue=1, maxValue=999, defaultValue=1))
self.addParameter(QgsProcessingParameterBand(self.RASTER_BAND,
self.tr('Raster band'),
1,
self.INPUT_RASTER))
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT_VECTOR,
self.tr('Vector layer containing zones'),
[QgsProcessing.TypeVectorPolygon]))
Expand Down
75 changes: 72 additions & 3 deletions python/plugins/processing/gui/wrappers.py
Expand Up @@ -62,6 +62,7 @@
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand,
QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputRasterLayer,
QgsProcessingOutputVectorLayer,
Expand Down Expand Up @@ -89,6 +90,7 @@
QgsProjectionSelectionDialog,
QgsMapLayerComboBox,
QgsProjectionSelectionWidget,
QgsRasterBandComboBox,
)
from qgis.PyQt.QtCore import pyqtSignal, QObject, QVariant, Qt
from qgis.utils import iface
Expand Down Expand Up @@ -990,7 +992,7 @@ class ExpressionWidgetWrapper(WidgetWrapper):

def createWidget(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
if self.param.parentLayerParameter():
if self.param.parentLayerParameterName():
widget = QgsFieldExpressionWidget()
else:
widget = QgsExpressionLineEdit()
Expand All @@ -1008,7 +1010,7 @@ def createWidget(self):

def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name() == self.param.parentLayerParameter():
if wrapper.param.name() == self.param.parentLayerParameterName():
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.value())
wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
Expand Down Expand Up @@ -1185,7 +1187,7 @@ def createWidget(self):

def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name() == self.param.parentLayerParameter():
if wrapper.param.name() == self.param.parentLayerParameterName():
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.value())
wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
Expand Down Expand Up @@ -1257,6 +1259,70 @@ def validator(v):
return self.comboValue(validator)


class BandWidgetWrapper(WidgetWrapper):

NOT_SET = '[Not set]'

def createWidget(self):
self._layer = None

if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
widget = QgsRasterBandComboBox()
widget.setShowNotSetOption(self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
widget.bandChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
widget = QComboBox()
widget.setEditable(True)
fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterBand, QgsProcessingParameterNumber], [QgsProcessingOutputNumber])
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
widget.addItem(self.NOT_SET, None)
for f in fields:
widget.addItem(self.dialog.resolveValueDescription(f), f)
return widget

def postInitialize(self, wrappers):
for wrapper in wrappers:
if wrapper.param.name() == self.param.parentLayerParameterName():
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.setLayer(wrapper.value())
wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
break

def parentValueChanged(self, wrapper):
self.setLayer(wrapper.value())

def setLayer(self, layer):
context = dataobjects.createContext()
if isinstance(layer, QgsProcessingParameterRasterLayer):
layer, ok = layer.source.valueAsString(context.expressionContext())
if isinstance(layer, str):
layer = QgsProcessingUtils.mapLayerFromString(layer, context)
self._layer = layer
self.refreshItems()

def refreshItems(self):
self.widget.setLayer(self._layer)
self.widget.setCurrentIndex(0)

def setValue(self, value):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
self.widget.setBand(value)
else:
self.setComboValue(value)

def value(self):
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
f = self.widget.currentBand()
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional and not f:
return None
return f
else:
def validator(v):
return bool(v) or self.param.flags() & QgsProcessingParameterDefinition.FlagOptional
return self.comboValue(validator)


class WidgetWrapperFactory:

"""
Expand Down Expand Up @@ -1292,6 +1358,7 @@ def create_wrapper_from_metadata(param, dialog, row=0, col=0):

@staticmethod
def create_wrapper_from_class(param, dialog, row=0, col=0):
print("PARAM", param, param.name(), param.type())
wrapper = None
if param.type() == 'boolean':
wrapper = BooleanWidgetWrapper
Expand Down Expand Up @@ -1321,6 +1388,8 @@ def create_wrapper_from_class(param, dialog, row=0, col=0):
wrapper = TableFieldWidgetWrapper
elif param.type() == 'source':
wrapper = VectorWidgetWrapper
elif param.type() == 'band':
wrapper = BandWidgetWrapper
else:
assert False, param.type()
return wrapper(param, dialog, row, col)
Expand Up @@ -48,7 +48,8 @@
QgsProcessingParameterExpression,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource)
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand)
from qgis.PyQt.QtCore import (Qt,
QByteArray)
from qgis.PyQt.QtWidgets import (QDialog,
Expand Down Expand Up @@ -76,6 +77,7 @@ class ModelerParameterDefinitionDialog(QDialog):
PARAMETER_POINT = 'Point'
PARAMETER_CRS = 'CRS'
PARAMETER_MULTIPLE = 'Multiple Input'
PARAMETER_BAND = 'Raster band'

paramTypes = [
PARAMETER_BOOLEAN,
Expand All @@ -90,7 +92,8 @@ class ModelerParameterDefinitionDialog(QDialog):
PARAMETER_VECTOR,
PARAMETER_POINT,
PARAMETER_CRS,
PARAMETER_MULTIPLE
PARAMETER_MULTIPLE,
PARAMETER_BAND
]

def __init__(self, alg, paramType=None, param=None):
Expand Down Expand Up @@ -141,7 +144,7 @@ def setupUi(self):
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == definition.name():
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
Expand All @@ -167,7 +170,20 @@ def setupUi(self):
if self.param is not None:
self.multipleCheck.setChecked(self.param.allowMultiple())
self.verticalLayout.addWidget(self.multipleCheck)

elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_BAND or \
isinstance(self.param, QgsProcessingParameterBand):
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, (QgsProcessingParameterRasterLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or
isinstance(self.param, QgsProcessingParameterFeatureSource)):
self.verticalLayout.addWidget(QLabel(self.tr('Shape type')))
Expand Down Expand Up @@ -230,7 +246,7 @@ def setupUi(self):
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameter() == definition.name():
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
Expand Down Expand Up @@ -318,6 +334,14 @@ def okPressed(self):
parent = self.parentCombo.currentData()
datatype = self.datatypeCombo.currentData()
self.param = QgsProcessingParameterField(name, description, None, parent, datatype, self.multipleCheck.isChecked())
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_BAND or
isinstance(self.param, QgsProcessingParameterBand)):
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()
self.param = QgsProcessingParameterBand(name, description, None, parent)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_RASTER or
isinstance(self.param, QgsProcessingParameterRasterLayer)):
self.param = QgsProcessingParameterRasterLayer(
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/modeler/ModelerScene.py
Expand Up @@ -103,8 +103,8 @@ def paintModel(self, model, controls=True):
for input_name in list(model.parameterComponents().keys()):
idx = 0
parameter_def = model.parameterDefinition(input_name)
if hasattr(parameter_def, 'parentLayerParameter') and parameter_def.parentLayerParameter():
parent_name = parameter_def.parentLayerParameter()
if hasattr(parameter_def, 'parentLayerParameterName') and parameter_def.parentLayerParameterName():
parent_name = parameter_def.parentLayerParameterName()
if input_name in self.paramItems and parent_name in self.paramItems:
input_item = self.paramItems[input_name]
parent_item = self.paramItems[parent_name]
Expand Down

0 comments on commit f964428

Please sign in to comment.