From 36abbc427ce63f08e8193a9a490fcba203b18783 Mon Sep 17 00:00:00 2001 From: volaya Date: Fri, 16 Sep 2016 12:04:12 +0200 Subject: [PATCH] [processing] allow multiple values in ParameterSelection --- python/plugins/processing/core/parameters.py | 39 +++++++-- python/plugins/processing/gui/wrappers.py | 87 +++++++++++--------- 2 files changed, 79 insertions(+), 47 deletions(-) diff --git a/python/plugins/processing/core/parameters.py b/python/plugins/processing/core/parameters.py index d9c8337978d..3936b8eaa16 100644 --- a/python/plugins/processing/core/parameters.py +++ b/python/plugins/processing/core/parameters.py @@ -1052,8 +1052,9 @@ class ParameterSelection(Parameter): def __init__(self, name='', description='', options=[], default=None, isSource=False, - optional=False): + multiple=False, optional=False): Parameter.__init__(self, name, description, default, optional) + self.multiple = multiple isSource = parseBool(isSource) self.options = options if isSource: @@ -1077,19 +1078,34 @@ class ParameterSelection(Parameter): self.default = 0 self.value = self.default - def setValue(self, n): - if n is None: + def setValue(self, value): + if value is None: if not self.optional: return False self.value = 0 return True - try: - n = int(n) - self.value = n + if isinstance(value, list): + if not self.multiple: + return False + values = [] + for v in value: + try: + n = int(v) + values.append(n) + except: + return False + if not self.optional and len(values) == 0: + return False + self.value = values return True - except: - return False + else: + try: + n = int(value) + self.value = n + return True + except: + return False @classmethod def fromScriptCode(self, line): @@ -1101,6 +1117,13 @@ class ParameterSelection(Parameter): elif definition.lower().strip().startswith('selection'): options = definition.strip()[len('selection '):].split(';') return ParameterSelection(name, descName, options, optional=isOptional) + elif definition.lower().strip().startswith('multipleselectionfromfile'): + options = definition.strip()[len('multipleselectionfromfile '):].split(';') + return ParameterSelection(name, descName, options, isSource=True, + multiple=True, optional=isOptional) + elif definition.lower().strip().startswith('multipleselection'): + options = definition.strip()[len('multipleselection '):].split(';') + return ParameterSelection(name, descName, options, multiple=True, optional=isOptional) class ParameterEvaluationException(Exception): diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py index 3605e61bc8c..0e05052ee61 100644 --- a/python/plugins/processing/gui/wrappers.py +++ b/python/plugins/processing/gui/wrappers.py @@ -2,7 +2,7 @@ """ *************************************************************************** - BooleanWidget.py + wrappers.py --------------------- Date : May 2016 Copyright : (C) 2016 by Arnaud Morvan, Victor Olaya @@ -43,7 +43,7 @@ from processing.core.parameters import (ParameterBoolean, ParameterPoint, Parame ParameterTableField, ParameterExtent, ParameterFixedTable, ParameterCrs) from processing.core.ProcessingConfig import ProcessingConfig from processing.gui.FileSelectionPanel import FileSelectionPanel -from processing.core.outputs import (OutputFile, OutputRaster, OutputVector, OutputNumber, +from processing.core.outputs import (OutputFile, OutputRaster, OutputVector, OutputNumber, OutputString, OutputTable, OutputExtent) from processing.tools import dataobjects from processing.gui.MultipleInputPanel import MultipleInputPanel @@ -122,13 +122,13 @@ class WidgetWrapper(QObject): def value(self): pass - + def anotherParameterWidgetHasChanged(self, wrapper): pass - + def postInitialize(self, wrappers): pass - + def refresh(self): pass @@ -136,7 +136,7 @@ class BasicWidgetWrapper(WidgetWrapper): def createWidget(self): return QLineEdit() - + def setValue(self, value): self.widget.setText(value) @@ -200,7 +200,7 @@ class CrsWidgetWrapper(WidgetWrapper): for r in raster: widget.addItem("Crs of layer " + self.dialog.resolveValueDescription(r), r) for v in vector: - widget.addItem("Crs of layer " + self.dialog.resolveValueDescription(v), v) + widget.addItem("Crs of layer " + self.dialog.resolveValueDescription(v), v) if not self.param.default: widget.setEditText(self.param.default) return widget @@ -226,7 +226,7 @@ class CrsWidgetWrapper(WidgetWrapper): class ExtentWidgetWrapper(WidgetWrapper): USE_MIN_COVERING_EXTENT = "[Use min covering extent]" - + def createWidget(self): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): return ExtentSelectionPanel(self.dialog, self.param) @@ -247,7 +247,7 @@ class ExtentWidgetWrapper(WidgetWrapper): if not self.param.default: widget.setEditText(self.param.default) return widget - + def setValue(self, value): if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): self.widget.setExtentFromString(value) @@ -364,7 +364,7 @@ class FixedTableWidgetWrapper(WidgetWrapper): return ParameterFixedTable.tableToString(table) else: return self.widget.table - + class MultipleInputWidgetWrapper(WidgetWrapper): @@ -404,7 +404,7 @@ class MultipleInputWidgetWrapper(WidgetWrapper): else: options = [self.dialog.resolveValueDescription(opt) for opt in self._getOptions()] return MultipleInputPanel(options) - + def refresh(self): if self.param.datatype != dataobjects.TYPE_FILE: if self.param.datatype == dataobjects.TYPE_RASTER: @@ -461,7 +461,7 @@ class NumberWidgetWrapper(WidgetWrapper): def setValue(self, value): self.widget.setValue(value) - + def value(self): return self.widget.getValue() @@ -496,7 +496,7 @@ class RasterWidgetWrapper(WidgetWrapper): self.widget.cmbText.addItem(self.NOT_SELECTED, None) for layer in layers: self.widget.cmbText.addItem(getExtendedLayerName(layer), layer) - + def setValue(self, value): if self.dialogType == DIALOG_STANDARD: pass # TODO @@ -519,17 +519,26 @@ class RasterWidgetWrapper(WidgetWrapper): class SelectionWidgetWrapper(WidgetWrapper): def createWidget(self): - widget = QComboBox() - widget.addItems(self.param.options) - if self.param.default: - widget.setCurrentIndex(self.param.default) - return widget + if self.param.multiple: + return MultipleInputPanel(options=self.param.options) + else: + widget = QComboBox() + widget.addItems(self.param.options) + if self.param.default: + widget.setCurrentIndex(self.param.default) + return widget def setValue(self, value): - self.widget.setCurrentIndex(int(value)) + if self.param.multiple: + self.widget.setSelectedItems(value) + else: + self.widget.setCurrentIndex(int(value)) def value(self): - return self.widget.currentIndex() + if self.param.multiple: + return self.widget.selectedoptions + else: + return self.widget.currentIndex() class VectorWidgetWrapper(WidgetWrapper): @@ -551,7 +560,7 @@ class VectorWidgetWrapper(WidgetWrapper): for layer in layers: widget.addItem(self.dialog.resolveValueDescription(layer), layer) return widget - + def _populate(self, widget): widget.clear() layers = dataobjects.getVectorLayers(self.param.datatype) @@ -562,10 +571,10 @@ class VectorWidgetWrapper(WidgetWrapper): widget.addItem(getExtendedLayerName(layer), layer) widget.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) widget.name = self.param.name - + def refresh(self): self._populate(self.widget) - + def setValue(self, value): if self.dialogType == DIALOG_STANDARD: pass # TODO @@ -719,8 +728,8 @@ class TableFieldWidgetWrapper(WidgetWrapper): if self.dialogType == DIALOG_STANDARD: return MultipleInputPanel(options=[]) else: - return QLineEdit() - else: + return QLineEdit() + else: if self.dialogType == DIALOG_STANDARD: widget = QComboBox() return widget @@ -746,13 +755,13 @@ class TableFieldWidgetWrapper(WidgetWrapper): fields = self.getFields(layer, wrapper.param.datatype) if self.param.multiple: self.widget.updateForOptions(fields) - else: + else: self.widget.clear() if self.param.optional: self.widget.addItem(self.tr(self.NOT_SET)) self.widget.addItems(fields) break - + def getFields(self, layer, datatype): fieldTypes = [] if datatype == ParameterTableField.DATA_TYPE_STRING: @@ -766,7 +775,7 @@ class TableFieldWidgetWrapper(WidgetWrapper): if not fieldTypes or field.type() in fieldTypes: fieldNames.add(unicode(field.name())) return sorted(list(fieldNames), cmp=locale.strcoll) - + def setValue(self, value): if self.param.multiple: if self.dialogType == DIALOG_STANDARD: @@ -778,7 +787,7 @@ class TableFieldWidgetWrapper(WidgetWrapper): self.widget.setSelectedItems(selected) else: self.widget.setText(value) - else: + else: if self.dialogType == DIALOG_STANDARD: pass # TODO elif self.dialogType == DIALOG_BATCH: @@ -794,11 +803,11 @@ class TableFieldWidgetWrapper(WidgetWrapper): elif self.dialogType == DIALOG_BATCH: return self.widget.text() else: - text = self.widget.text() + text = self.widget.text() if not bool(text) and not self.param.optional: raise InvalidParameterValue() return text - else: + else: if self.dialogType == DIALOG_STANDARD: if self.param.optional and self.widget.currentIndex() == 0: return None @@ -808,9 +817,9 @@ class TableFieldWidgetWrapper(WidgetWrapper): else: def validator(v): return bool(v) or self.param.optional - return self.comboValue(validator) - - def anotherParameterWidgetHasChanged(self,wrapper): + return self.comboValue(validator) + + def anotherParameterWidgetHasChanged(self, wrapper): if wrapper.param.name == self.param.parent: layer = wrapper.value() if layer is not None: @@ -822,15 +831,15 @@ class TableFieldWidgetWrapper(WidgetWrapper): if self.param.optional: self.widget.addItem(self.tr(self.NOT_SET)) self.widget.addItems(fields) - + def GeometryPredicateWidgetWrapper(WidgetWrapper): - + def createWidget(self): return GeometryPredicateSelectionPanel() - + def setValue(self, value): self.widget.setValue(value) - + def value(self): - return self.widget.value() \ No newline at end of file + return self.widget.value()