Skip to content
Permalink
Browse files

[Processing] Optional parameters for script and model

In processing core every parameters can be optional but in scripts there is no way to define a parameter as optional and in modeler only layers can be optional.

For script, I propose a notation like output, if a parameter token starts with optional the parameter is optional.

For model, I propose to add the required combobox to all parameters.

This proposition does not change the value setter.

This proposition can fix the issue http://hub.qgis.org/issues/5488.
  • Loading branch information
rldhont authored and volaya committed Nov 4, 2015
1 parent f7a7a78 commit 55e75addcecdcfe7d8f611506ad7ab1fc7970ec0
@@ -92,6 +92,9 @@ def setupUi(self):
self.horizontalLayout3 = QHBoxLayout(self)
self.horizontalLayout3.setSpacing(2)
self.horizontalLayout3.setMargin(0)
self.horizontalLayout4 = QHBoxLayout(self)
self.horizontalLayout4.setSpacing(2)
self.horizontalLayout4.setMargin(0)

if isinstance(self.param, Parameter):
self.nameTextBox.setText(self.param.description)
@@ -103,11 +106,11 @@ def setupUi(self):
self.state.setChecked(False)
if self.param is not None:
self.state.setChecked(True if self.param.value else False)
self.horizontalLayout2.addWidget(self.state)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.horizontalLayout3.addWidget(self.state)
self.verticalLayout.addLayout(self.horizontalLayout3)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or \
isinstance(self.param, ParameterTableField):
self.horizontalLayout2.addWidget(QLabel(self.tr('Parent layer')))
self.horizontalLayout3.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
idx = 0
for param in self.alg.inputs.values():
@@ -117,57 +120,22 @@ def setupUi(self):
if self.param.parent == param.param.name:
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.horizontalLayout2.addWidget(self.parentCombo)
self.verticalLayout.addLayout(self.horizontalLayout2)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_RASTER or \
isinstance(self.param, ParameterRaster):
self.horizontalLayout2.addWidget(QLabel(self.tr('Required')))
self.yesNoCombo = QComboBox()
self.yesNoCombo.addItem(self.tr('Yes'))
self.yesNoCombo.addItem(self.tr('No'))
if self.param is not None:
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.horizontalLayout2.addWidget(self.yesNoCombo)
self.verticalLayout.addLayout(self.horizontalLayout2)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE or \
isinstance(self.param, ParameterTable):
self.horizontalLayout2.addWidget(QLabel(self.tr('Required')))
self.yesNoCombo = QComboBox()
self.yesNoCombo.addItem(self.tr('Yes'))
self.yesNoCombo.addItem(self.tr('No'))
if self.param is not None:
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.horizontalLayout2.addWidget(self.yesNoCombo)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.horizontalLayout3.addWidget(self.parentCombo)
self.verticalLayout.addLayout(self.horizontalLayout3)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or \
isinstance(self.param, ParameterVector):
self.horizontalLayout2.addWidget(QLabel(self.tr('Required')))
self.yesNoCombo = QComboBox()
self.yesNoCombo.addItem(self.tr('Yes'))
self.yesNoCombo.addItem(self.tr('No'))
self.horizontalLayout2.addWidget(self.yesNoCombo)
self.horizontalLayout3.addWidget(QLabel(self.tr('Shape type')))
self.shapetypeCombo = QComboBox()
self.shapetypeCombo.addItem(self.tr('Any'))
self.shapetypeCombo.addItem(self.tr('Point'))
self.shapetypeCombo.addItem(self.tr('Line'))
self.shapetypeCombo.addItem(self.tr('Polygon'))
if self.param is not None:
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.shapetypeCombo.setCurrentIndex(self.param.shapetype[0] + 1)
self.horizontalLayout3.addWidget(self.shapetypeCombo)
self.verticalLayout.addLayout(self.horizontalLayout3)
self.verticalLayout.addLayout(self.horizontalLayout2)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_MULTIPLE or \
isinstance(self.param, ParameterMultipleInput):
self.horizontalLayout2.addWidget(QLabel(self.tr('Mandatory')))
self.yesNoCombo = QComboBox()
self.yesNoCombo.addItem(self.tr('Yes'))
self.yesNoCombo.addItem(self.tr('No'))
self.horizontalLayout2.addWidget(self.yesNoCombo)
self.horizontalLayout3.addWidget(QLabel(self.tr('Data type')))
self.datatypeCombo = QComboBox()
self.datatypeCombo.addItem(self.tr('Vector (any)'))
@@ -177,53 +145,60 @@ def setupUi(self):
self.datatypeCombo.addItem(self.tr('Raster'))
self.datatypeCombo.addItem(self.tr('Table'))
if self.param is not None:
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.datatypeCombo.setCurrentIndex(self.param.datatype + 1)
self.horizontalLayout3.addWidget(self.datatypeCombo)
self.verticalLayout.addLayout(self.horizontalLayout3)
self.verticalLayout.addLayout(self.horizontalLayout2)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_NUMBER or \
isinstance(self.param, ParameterNumber):
self.horizontalLayout2.addWidget(QLabel(self.tr('Min/Max values')))
self.horizontalLayout3.addWidget(QLabel(self.tr('Min/Max values')))
self.minTextBox = QLineEdit()
self.maxTextBox = QLineEdit()
if self.param is not None:
self.minTextBox.setText(unicode(self.param.min))
self.maxTextBox.setText(unicode(self.param.max))
self.horizontalLayout2.addWidget(self.minTextBox)
self.horizontalLayout2.addWidget(self.maxTextBox)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.horizontalLayout3.addWidget(QLabel(self.tr('Default value')))
self.horizontalLayout3.addWidget(self.minTextBox)
self.horizontalLayout3.addWidget(self.maxTextBox)
self.verticalLayout.addLayout(self.horizontalLayout3)
self.horizontalLayout4.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
self.defaultTextBox.setText(self.tr('0'))
if self.param is not None:
default = self.param.default
if self.param.isInteger:
default = int(math.floor(default))
self.defaultTextBox.setText(unicode(default))
self.horizontalLayout3.addWidget(self.defaultTextBox)
self.verticalLayout.addLayout(self.horizontalLayout3)
self.horizontalLayout4.addWidget(self.defaultTextBox)
self.verticalLayout.addLayout(self.horizontalLayout4)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_STRING or \
isinstance(self.param, ParameterString):
self.horizontalLayout2.addWidget(QLabel(self.tr('Default value')))
self.horizontalLayout3.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
if self.param is not None:
self.defaultTextBox.setText(self.param.default)
self.horizontalLayout2.addWidget(self.defaultTextBox)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.horizontalLayout3.addWidget(self.defaultTextBox)
self.verticalLayout.addLayout(self.horizontalLayout3)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_FILE or \
isinstance(self.param, ParameterFile):
self.horizontalLayout2.addWidget(QLabel(self.tr('Type')))
self.horizontalLayout3.addWidget(QLabel(self.tr('Type')))
self.fileFolderCombo = QComboBox()
self.fileFolderCombo.addItem(self.tr('File'))
self.fileFolderCombo.addItem(self.tr('Folder'))
if self.param is not None:
self.fileFolderCombo.setCurrentIndex(
1 if self.param.isFolder else 0)
self.horizontalLayout2.addWidget(self.fileFolderCombo)
self.verticalLayout.addLayout(self.horizontalLayout2)
self.horizontalLayout3.addWidget(self.fileFolderCombo)
self.verticalLayout.addLayout(self.horizontalLayout3)

self.horizontalLayout2.addWidget(QLabel(self.tr('Required')))
self.yesNoCombo = QComboBox()
self.yesNoCombo.addItem(self.tr('Yes'))
self.yesNoCombo.addItem(self.tr('No'))
self.horizontalLayout2.addWidget(self.yesNoCombo)
if self.param is not None:
self.yesNoCombo.setCurrentIndex(
1 if self.param.optional else 0)
self.verticalLayout.addLayout(self.horizontalLayout2)

self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
@@ -315,6 +290,7 @@ def okPressed(self):
isinstance(self.param, ParameterFile):
isFolder = self.fileFolderCombo.currentIndex() == 1
self.param = ParameterFile(name, description, isFolder=isFolder)
self.param.optional = self.yesNoCombo.currentIndex() == 1
self.close()

def cancelPressed(self):
@@ -145,98 +145,126 @@ def processParameterLine(self, line):
if tokens[1].lower().strip() == 'name':
self.name = self.i18n_name = tokens[0]
return
if tokens[1].lower().strip() == 'raster':
param = ParameterRaster(tokens[0], desc, False)
elif tokens[1].lower().strip() == 'vector':
param = ParameterVector(tokens[0], desc,

if tokens[1].lower().strip().startswith('output'):
outToken = tokens[1].strip()[len('output') + 1:]
out = self.processOutputParameterToken(outToken)

elif tokens[1].lower().strip().startswith('optional'):
optToken = tokens[1].strip()[len('optional') + 1:]
param = self.processInputParameterToken(optToken, tokens[0])
if param:
param.optional = True

else:
param = self.processInputParameterToken(tokens[1], tokens[0])


if param is not None:
self.addParameter(param)
elif out is not None:
out.name = tokens[0]
out.description = desc
self.addOutput(out)
else:
raise WrongScriptException(
self.tr('Could not load script: %s.\n'
'Problem with line "%s"', 'ScriptAlgorithm') % (self.descriptionFile or '', line))

def processInputParameterToken(self, token, name):
param = None

descName = self.createDescriptiveName(name)

if token.lower().strip() == 'raster':
param = ParameterRaster(name, descName, False)
elif token.lower().strip() == 'vector':
param = ParameterVector(name, descName,
[ParameterVector.VECTOR_TYPE_ANY])
elif tokens[1].lower().strip() == 'vector point':
param = ParameterVector(tokens[0], desc,
elif token.lower().strip() == 'vector point':
param = ParameterVector(name, descName,
[ParameterVector.VECTOR_TYPE_POINT])
elif tokens[1].lower().strip() == 'vector line':
param = ParameterVector(tokens[0], desc,
elif token.lower().strip() == 'vector line':
param = ParameterVector(name, descName,
[ParameterVector.VECTOR_TYPE_LINE])
elif tokens[1].lower().strip() == 'vector polygon':
param = ParameterVector(tokens[0], desc,
elif token.lower().strip() == 'vector polygon':
param = ParameterVector(name, descName,
[ParameterVector.VECTOR_TYPE_POLYGON])
elif tokens[1].lower().strip() == 'table':
param = ParameterTable(tokens[0], desc, False)
elif tokens[1].lower().strip() == 'multiple raster':
param = ParameterMultipleInput(tokens[0], desc,
elif token.lower().strip() == 'table':
param = ParameterTable(name, descName, False)
elif token.lower().strip() == 'multiple raster':
param = ParameterMultipleInput(name, descName,
ParameterMultipleInput.TYPE_RASTER)
param.optional = False
elif tokens[1].lower().strip() == 'multiple vector':
param = ParameterMultipleInput(tokens[0], desc,
elif token.lower().strip() == 'multiple vector':
param = ParameterMultipleInput(name, descName,
ParameterMultipleInput.TYPE_VECTOR_ANY)
param.optional = False
elif tokens[1].lower().strip().startswith('selectionfromfile'):
options = tokens[1].strip()[len('selectionfromfile '):].split(';')
param = ParameterSelection(tokens[0], desc, options, isSource=True)
elif tokens[1].lower().strip().startswith('selection'):
elif token.lower().strip().startswith('selectionfromfile'):
options = token.strip()[len('selectionfromfile '):].split(';')
param = ParameterSelection(name, descName, options, isSource=True)
elif token.lower().strip().startswith('selection'):
options = tokens[1].strip()[len('selection '):].split(';')
param = ParameterSelection(tokens[0], desc, options)
elif tokens[1].lower().strip().startswith('boolean'):
default = tokens[1].strip()[len('boolean') + 1:]
param = ParameterBoolean(tokens[0], desc, default)
elif tokens[1].lower().strip() == 'extent':
param = ParameterExtent(tokens[0], desc)
elif tokens[1].lower().strip() == 'file':
param = ParameterFile(tokens[0], desc, False)
elif tokens[1].lower().strip() == 'folder':
param = ParameterFile(tokens[0], desc, True)
elif tokens[1].lower().strip().startswith('number'):
default = tokens[1].strip()[len('number') + 1:]
param = ParameterNumber(tokens[0], desc, default=default)
elif tokens[1].lower().strip().startswith('field'):
field = tokens[1].strip()[len('field') + 1:]
param = ParameterSelection(name, descName, options)
elif token.lower().strip().startswith('boolean'):
default = token.strip()[len('boolean') + 1:]
param = ParameterBoolean(name, descName, default)
elif token.lower().strip() == 'extent':
param = ParameterExtent(name, descName)
elif token.lower().strip() == 'file':
param = ParameterFile(name, descName, False)
elif token.lower().strip() == 'folder':
param = ParameterFile(name, descName, True)
elif token.lower().strip().startswith('number'):
default = token.strip()[len('number') + 1:]
param = ParameterNumber(name, descName, default=default)
elif token.lower().strip().startswith('field'):
field = token.strip()[len('field') + 1:]
found = False
for p in self.parameters:
if p.name == field:
found = True
break
if found:
param = ParameterTableField(tokens[0], desc, field)
elif tokens[1].lower().strip().startswith('string'):
default = tokens[1].strip()[len('string') + 1:]
param = ParameterString(tokens[0], desc, default)
elif tokens[1].lower().strip().startswith('longstring'):
default = tokens[1].strip()[len('longstring') + 1:]
param = ParameterString(tokens[0], desc, default, multiline=True)
elif tokens[1].lower().strip().startswith('crs'):
default = tokens[1].strip()[len('crs') + 1:]
param = ParameterTableField(name, descName, field)
elif token.lower().strip().startswith('string'):
default = token.strip()[len('string') + 1:]
param = ParameterString(name, descName, default)
elif token.lower().strip().startswith('longstring'):
default = token.strip()[len('longstring') + 1:]
param = ParameterString(name, descName, default, multiline=True)
elif token.lower().strip().startswith('crs'):
default = token.strip()[len('crs') + 1:]
if not default:
default = 'EPSG:4326'
param = ParameterCrs(tokens[0], desc, default)
elif tokens[1].lower().strip().startswith('output raster'):
param = ParameterCrs(name, descName, default)

return param

def processOutputParameterToken(self, token):
out = None

if token.lower().strip().startswith('raster'):
out = OutputRaster()
elif tokens[1].lower().strip().startswith('output vector'):
elif token.lower().strip().startswith('vector'):
out = OutputVector()
elif tokens[1].lower().strip().startswith('output table'):
elif token.lower().strip().startswith('table'):
out = OutputTable()
elif tokens[1].lower().strip().startswith('output html'):
elif token.lower().strip().startswith('html'):
out = OutputHTML()
elif tokens[1].lower().strip().startswith('output file'):
elif token.lower().strip().startswith('file'):
out = OutputFile()
subtokens = tokens[1].split(' ')
subtokens = token.split(' ')
if len(subtokens) > 2:
out.ext = subtokens[2]
elif tokens[1].lower().strip().startswith('output directory'):
elif token.lower().strip().startswith('directory'):
out = OutputDirectory()
elif tokens[1].lower().strip().startswith('output number'):
elif token.lower().strip().startswith('number'):
out = OutputNumber()
elif tokens[1].lower().strip().startswith('output string'):
elif token.lower().strip().startswith('string'):
out = OutputString()

if param is not None:
self.addParameter(param)
elif out is not None:
out.name = tokens[0]
out.description = desc
self.addOutput(out)
else:
raise WrongScriptException(
self.tr('Could not load script: %s.\n'
'Problem with line "%s"', 'ScriptAlgorithm') % (self.descriptionFile or '', line))

return out

def processDescriptionParameterLine(self, line):
try:

0 comments on commit 55e75ad

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