Skip to content
Permalink
Browse files

[processing] add parameter representing raster band

  • Loading branch information
alexbruy committed Aug 4, 2017
1 parent 3c58599 commit 49bfe69823943ca546a784c64b905c4f849e6038
@@ -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:

@@ -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 parentLayerParameter() const;
%Docstring
Returns the name of the parent layer parameter, or an empty string if this is not set.
.. seealso:: setParentLayerParameter()
:rtype: str
%End

void setParentLayerParameter( const QString &parentLayerParameter );
%Docstring
Sets the name of the parent layer parameter. Use an empty string if this is not required.
.. seealso:: parentLayerParameter()
%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

};



/************************************************************************
@@ -62,6 +62,7 @@
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand,
QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputRasterLayer,
QgsProcessingOutputVectorLayer,
@@ -89,6 +90,7 @@
QgsProjectionSelectionDialog,
QgsMapLayerComboBox,
QgsProjectionSelectionWidget,
QgsRasterBandComboBox,
)
from qgis.PyQt.QtCore import pyqtSignal, QObject, QVariant, Qt
from qgis.utils import iface
@@ -1257,6 +1259,72 @@ 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):
print(self.param)
print(self.param.parentLayerParameter)
for wrapper in wrappers:
if wrapper.param.name() == self.param.parentLayerParameter():
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:

"""
@@ -1292,6 +1360,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
@@ -1321,6 +1390,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)
@@ -48,7 +48,8 @@
QgsProcessingParameterExpression,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource)
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand)
from qgis.PyQt.QtCore import (Qt,
QByteArray)
from qgis.PyQt.QtWidgets import (QDialog,
@@ -76,6 +77,7 @@ class ModelerParameterDefinitionDialog(QDialog):
PARAMETER_POINT = 'Point'
PARAMETER_CRS = 'CRS'
PARAMETER_MULTIPLE = 'Multiple Input'
PARAMETER_BAND = 'Raster band'

paramTypes = [
PARAMETER_BOOLEAN,
@@ -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):
@@ -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.parentLayerParameter() == 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')))
@@ -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(
@@ -787,6 +787,8 @@ QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromVariantM
def.reset( new QgsProcessingParameterFileDestination( name ) );
else if ( type == QgsProcessingParameterFolderDestination::typeName() )
def.reset( new QgsProcessingParameterFolderDestination( name ) );
else if ( type == QgsProcessingParameterBand::typeName() )
def.reset( new QgsProcessingParameterBand( name ) );

if ( !def )
return nullptr;
@@ -859,6 +861,8 @@ QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromScriptCo
return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
else if ( type == QStringLiteral( "folderdestination" ) )
return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
else if ( type == QStringLiteral( "band" ) )
return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );

return nullptr;
}
@@ -3145,3 +3149,103 @@ QgsProcessingParameterVectorDestination *QgsProcessingParameterVectorDestination

return new QgsProcessingParameterVectorDestination( name, description, type, definition, isOptional );
}

QgsProcessingParameterBand::QgsProcessingParameterBand( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mParentLayerParameter( parentLayerParameterName )
{

}

bool QgsProcessingParameterBand::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
{
if ( !input.isValid() )
return mFlags & FlagOptional;

if ( input.canConvert<QgsProperty>() )
{
return true;
}

bool ok = false;
double res = input.toInt( &ok );
Q_UNUSED( res );
if ( !ok )
return mFlags & FlagOptional;

return true;
}

QString QgsProcessingParameterBand::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );

return value.toString();
}

QString QgsProcessingParameterBand::asScriptCode() const
{
QString code = QStringLiteral( "##%1=" ).arg( mName );
if ( mFlags & FlagOptional )
code += QStringLiteral( "optional " );
code += QStringLiteral( "band " );

code += mParentLayerParameter + ' ';

code += mDefault.toString();
return code.trimmed();
}

QStringList QgsProcessingParameterBand::dependsOnOtherParameters() const
{
QStringList depends;
if ( !mParentLayerParameter.isEmpty() )
depends << mParentLayerParameter;
return depends;
}

QString QgsProcessingParameterBand::parentLayerParameter() const
{
return mParentLayerParameter;
}

void QgsProcessingParameterBand::setParentLayerParameter( const QString &parentLayerParameter )
{
mParentLayerParameter = parentLayerParameter;
}

QVariantMap QgsProcessingParameterBand::toVariantMap() const
{
QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameter );
return map;
}

bool QgsProcessingParameterBand::fromVariantMap( const QVariantMap &map )
{
QgsProcessingParameterDefinition::fromVariantMap( map );
mParentLayerParameter = map.value( QStringLiteral( "parent_layer" ) ).toString();
return true;
}

QgsProcessingParameterBand *QgsProcessingParameterBand::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
{
QString parent;
QString def = definition;

QRegularExpression re( "(.*?)\\s+(.*)$" );
QRegularExpressionMatch m = re.match( def );
if ( m.hasMatch() )
{
parent = m.captured( 1 ).trimmed();
def = m.captured( 2 );
}
else
{
parent = def;
def.clear();
}

return new QgsProcessingParameterBand( name, description, def.isEmpty() ? QVariant() : def, parent, isOptional );
}

0 comments on commit 49bfe69

Please sign in to comment.
You can’t perform that action at this time.