From b298c76ee451e7a7941de54cca44724cc1b7fef0 Mon Sep 17 00:00:00 2001 From: volaya Date: Wed, 7 Sep 2016 14:30:20 +0200 Subject: [PATCH] [processing] implemented parameter widget wrappers Conflicts: python/plugins/processing/core/GeoAlgorithm.py python/plugins/processing/gui/ExtentSelectionPanel.py python/plugins/processing/modeler/ModelerParametersDialog.py --- .../plugins/processing/core/GeoAlgorithm.py | 104 +-- python/plugins/processing/core/parameters.py | 112 ++- .../plugins/processing/gui/AlgorithmDialog.py | 76 +- .../gui/BatchInputSelectionPanel.py | 23 +- python/plugins/processing/gui/BatchPanel.py | 94 +-- .../processing/gui/ExtentSelectionPanel.py | 20 +- .../processing/gui/NumberInputPanel.py | 7 +- .../plugins/processing/gui/ParametersPanel.py | 340 +-------- python/plugins/processing/gui/wrappers.py | 714 +++++++++++++++++- .../modeler/ModelerParametersDialog.py | 401 +--------- 10 files changed, 914 insertions(+), 977 deletions(-) diff --git a/python/plugins/processing/core/GeoAlgorithm.py b/python/plugins/processing/core/GeoAlgorithm.py index a993dbdd23c..3301b7ba307 100644 --- a/python/plugins/processing/core/GeoAlgorithm.py +++ b/python/plugins/processing/core/GeoAlgorithm.py @@ -42,8 +42,7 @@ from processing.core.ProcessingLog import ProcessingLog from processing.core.ProcessingConfig import ProcessingConfig from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException from processing.core.SilentProgress import SilentProgress -from processing.core.parameters import ParameterExtent -from processing.core.parameters import ParameterRaster, ParameterVector, ParameterMultipleInput, ParameterTable, Parameter +from processing.core.parameters import ParameterRaster, ParameterVector, ParameterMultipleInput, ParameterTable, Parameter, ParameterExtent from processing.core.outputs import OutputVector, OutputRaster, OutputTable, OutputHTML, Output from processing.algs.gdal.GdalUtils import GdalUtils from processing.tools import dataobjects, vector @@ -363,56 +362,6 @@ class GeoAlgorithm(object): if ext not in exts + ['dbf']: out.value = out.value + '.' + exts[0] - def resolveTemporaryOutputs(self): - """Sets temporary outputs (output.value = None) with a - temporary file instead. - """ - for out in self.outputs: - if not out.hidden and out.value is None: - setTempOutput(out, self) - - def setOutputCRS(self): - layers = dataobjects.getAllLayers() - for param in self.parameters: - if isinstance(param, (ParameterRaster, ParameterVector, ParameterMultipleInput)): - if param.value: - if isinstance(param, ParameterMultipleInput): - inputlayers = param.value.split(';') - else: - inputlayers = [param.value] - for inputlayer in inputlayers: - for layer in layers: - if layer.source() == inputlayer: - self.crs = layer.crs() - return - p = dataobjects.getObjectFromUri(inputlayer) - if p is not None: - self.crs = p.crs() - p = None - return - try: - from qgis.utils import iface - if iface is not None: - self.crs = iface.mapCanvas().mapSettings().destinationCrs() - except: - pass - - def resolveDataObjects(self): - layers = dataobjects.getAllLayers() - for param in self.parameters: - if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable, - ParameterMultipleInput)): - if param.value: - if isinstance(param, ParameterMultipleInput): - inputlayers = param.value.split(';') - else: - inputlayers = [param.value] - for i, inputlayer in enumerate(inputlayers): - for layer in layers: - if layer.name() == inputlayer: - inputlayers[i] = layer.source() - break - param.setValue(";".join(inputlayers)) def canUseAutoExtent(self): for param in self.parameters: @@ -468,6 +417,57 @@ class GeoAlgorithm(object): self.xmax = max(self.xmax, layer.extent().xMaximum()) self.ymin = min(self.ymin, layer.extent().yMinimum()) self.ymax = max(self.ymax, layer.extent().yMaximum()) + + def resolveTemporaryOutputs(self): + """Sets temporary outputs (output.value = None) with a + temporary file instead. + """ + for out in self.outputs: + if not out.hidden and out.value is None: + setTempOutput(out, self) + + def setOutputCRS(self): + layers = dataobjects.getAllLayers() + for param in self.parameters: + if isinstance(param, (ParameterRaster, ParameterVector, ParameterMultipleInput)): + if param.value: + if isinstance(param, ParameterMultipleInput): + inputlayers = param.value.split(';') + else: + inputlayers = [param.value] + for inputlayer in inputlayers: + for layer in layers: + if layer.source() == inputlayer: + self.crs = layer.crs() + return + p = dataobjects.getObjectFromUri(inputlayer) + if p is not None: + self.crs = p.crs() + p = None + return + try: + from qgis.utils import iface + if iface is not None: + self.crs = iface.mapCanvas().mapSettings().destinationCrs() + except: + pass + + def resolveDataObjects(self): + layers = dataobjects.getAllLayers() + for param in self.parameters: + if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable, + ParameterMultipleInput)): + if param.value: + if isinstance(param, ParameterMultipleInput): + inputlayers = param.value.split(';') + else: + inputlayers = [param.value] + for i, inputlayer in enumerate(inputlayers): + for layer in layers: + if layer.name() == inputlayer: + inputlayers[i] = layer.source() + break + param.setValue(";".join(inputlayers)) def checkInputCRS(self): """It checks that all input layers use the same CRS. If so, diff --git a/python/plugins/processing/core/parameters.py b/python/plugins/processing/core/parameters.py index b276411a573..45f02f9c5fd 100644 --- a/python/plugins/processing/core/parameters.py +++ b/python/plugins/processing/core/parameters.py @@ -30,7 +30,9 @@ __revision__ = '$Format:%H$' import sys import os -import inspect +from inspect import isclass +from copy import deepcopy + from qgis.PyQt.QtCore import QCoreApplication from qgis.core import QgsRasterLayer, QgsVectorLayer @@ -52,7 +54,7 @@ def _splitParameterOptions(line): isOptional = False definition = tokens[1] return isOptional, tokens[0], definition - + def _createDescriptiveName(s): return s.replace('_', ' ') @@ -82,8 +84,8 @@ class Parameter(object): self.optional = parseBool(optional) # TODO: make deep copy and deep update - self.metadata = self.default_metadata.copy() - self.metadata.update(metadata) + self.metadata = deepcopy(self.default_metadata) + self.metadata.update(deepcopy(metadata)) def setValue(self, obj): """ @@ -133,7 +135,20 @@ class Parameter(object): if context == '': context = 'Parameter' return QCoreApplication.translate(context, string) - + + def wrapper(self, dialog, row=0, col=0): + wrapper = self.metadata.get('widget_wrapper', None) + # wrapper metadata should be a class path + if isinstance(wrapper, basestring): + tokens = wrapper.split('.') + mod = __import__('.'.join(tokens[:-1]), fromlist=[tokens[-1]]) + wrapper = getattr(mod, tokens[-1]) + # or directly a class object + if isclass(wrapper): + wrapper = wrapper(self, dialog, row, col) + # or a wrapper instance + return wrapper + class ParameterBoolean(Parameter): default_metadata = { @@ -162,7 +177,7 @@ class ParameterBoolean(Parameter): param_type += 'optional ' param_type += 'boolean ' return '##' + self.name + '=' + param_type + str(self.default) - + @classmethod def fromScriptCode(self, line): isOptional, name, definition = _splitParameterOptions(line) @@ -175,7 +190,7 @@ class ParameterBoolean(Parameter): param = ParameterBoolean(name, descName) param.optional = isOptional return param - + class ParameterCrs(Parameter): @@ -236,9 +251,13 @@ class ParameterDataObject(Parameter): class ParameterExtent(Parameter): + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.ExtentWidgetWrapper' + } + USE_MIN_COVERING_EXTENT = 'USE_MIN_COVERING_EXTENT' - def __init__(self, name='', description='', default=None, optional=False): + def __init__(self, name='', description='', default=None, optional=True): Parameter.__init__(self, name, description, default, optional) # The value is a string in the form "xmin, xmax, ymin, ymax" @@ -271,7 +290,7 @@ class ParameterExtent(Parameter): param_type += 'optional ' param_type += 'extent' return '##' + self.name + '=' + param_type - + @classmethod def fromScriptCode(self, line): isOptional, name, definition = _splitParameterOptions(line) @@ -283,6 +302,10 @@ class ParameterExtent(Parameter): class ParameterPoint(Parameter): + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.PointWidgetWrapper' + } + def __init__(self, name='', description='', default=None, optional=False): Parameter.__init__(self, name, description, default, optional) # The value is a string in the form "x, y" @@ -326,6 +349,10 @@ class ParameterPoint(Parameter): class ParameterFile(Parameter): + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.FileWidgetWrapper' + } + def __init__(self, name='', description='', isFolder=False, optional=True, ext=None): Parameter.__init__(self, name, description, None, parseBool(optional)) self.ext = ext @@ -371,6 +398,7 @@ class ParameterFile(Parameter): class ParameterFixedTable(Parameter): + def __init__(self, name='', description='', numRows=3, cols=['value'], fixedNumOfRows=False, optional=False): @@ -423,6 +451,11 @@ class ParameterMultipleInput(ParameterDataObject): Its value is a string with substrings separated by semicolons, each of which represents the data source location of each element. """ + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.MultipleInputWidgetWrapper' + } + exported = None @@ -607,13 +640,18 @@ class ParameterMultipleInput(ParameterDataObject): descName = _createDescriptiveName(name) if definition.lower().strip() == 'multiple raster': return ParameterMultipleInput(name, descName, - dataobjects.TYPE_RASTER, isOptional) + dataobjects.TYPE_RASTER, isOptional) elif definition.lower().strip() == 'multiple vector': return ParameterMultipleInput(name, definition, dataobjects.TYPE_VECTOR_ANY, isOptional) - + class ParameterNumber(Parameter): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.NumberWidgetWrapper' + } + def __init__(self, name='', description='', minValue=None, maxValue=None, default=None, optional=False): @@ -716,6 +754,11 @@ class ParameterRange(Parameter): class ParameterRaster(ParameterDataObject): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.RasterWidgetWrapper' + } + def __init__(self, name='', description='', optional=False, showSublayersDialog=True): ParameterDataObject.__init__(self, name, description, None, optional) @@ -787,6 +830,11 @@ class ParameterRaster(ParameterDataObject): return ParameterRaster(name, descName, optional=isOptional) class ParameterSelection(Parameter): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.SelectionWidgetWrapper' + } + def __init__(self, name='', description='', options=[], default=None, isSource=False, optional=False): @@ -838,9 +886,14 @@ class ParameterSelection(Parameter): elif definition.lower().strip().startswith('selection'): options = definition.strip()[len('selection '):].split(';') return ParameterSelection(name, descName, options, optional=isOptional) - - + + class ParameterString(Parameter): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.StringWidgetWrapper' + } + NEWLINE = '\n' ESCAPED_NEWLINE = '\\n' @@ -894,6 +947,11 @@ class ParameterString(Parameter): return ParameterString(name, descName, multiline=True, optional=isOptional) class ParameterTable(ParameterDataObject): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.TableWidgetWrapper' + } + def __init__(self, name='', description='', optional=False): ParameterDataObject.__init__(self, name, description, None, optional) @@ -976,11 +1034,13 @@ class ParameterTableField(Parameter): """A parameter representing a table field. Its value is a string that represents the name of the field. - - In a script you can use it with - ##Field=[optional] field [number|string] Parentinput """ + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.TableFieldWidgetWrapper' + } + + DATA_TYPE_NUMBER = 0 DATA_TYPE_STRING = 1 DATA_TYPE_ANY = -1 @@ -1040,10 +1100,10 @@ class ParameterTableField(Parameter): else: parent = definition.strip()[len('field') + 1:] datatype = ParameterTableField.DATA_TYPE_ANY - + return ParameterTableField(name, descName, parent, datatype, isOptional) - - + + class ParameterTableMultipleField(Parameter): """A parameter representing several table fields. @@ -1129,6 +1189,11 @@ class ParameterTableMultipleField(Parameter): class ParameterVector(ParameterDataObject): + + default_metadata = { + 'widget_wrapper': 'processing.gui.wrappers.VectorWidgetWrapper' + } + def __init__(self, name='', description='', datatype=[-1], optional=False): @@ -1139,6 +1204,7 @@ class ParameterVector(ParameterDataObject): datatype = [int(t) for t in datatype.split(',')] self.datatype = datatype self.exported = None + self.allowOnlyOpenedLayers = False def setValue(self, obj): self.exported = None @@ -1260,20 +1326,20 @@ class ParameterGeometryPredicate(Parameter): return True -paramClasses = [c for c in sys.modules[__name__].__dict__.values() if inspect.isclass(c) and issubclass(c, Parameter)] +paramClasses = [c for c in sys.modules[__name__].__dict__.values() if isclass(c) and issubclass(c, Parameter)] def getParameterFromString(s): print s - #Try the parameter definitions used in description files + # Try the parameter definitions used in description files if '|' in s: tokens = s.split("|") params = [t if unicode(t) != unicode(None) else None for t in tokens[1:]] clazz = getattr(sys.modules[__name__], tokens[0]) return clazz(*params) - else: #try script syntax + else: # try script syntax for paramClass in paramClasses: try: - param = paramClass.fromScriptCode(s) + param = paramClass.fromScriptCode(s) if param is not None: return param except AttributeError: diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py index 1a0f0354f84..7ad7a0df4c2 100644 --- a/python/plugins/processing/gui/AlgorithmDialog.py +++ b/python/plugins/processing/gui/AlgorithmDialog.py @@ -85,8 +85,8 @@ class AlgorithmDialog(AlgorithmDialogBase): self.cornerWidget.setLayout(layout) self.tabWidget.setCornerWidget(self.cornerWidget) - QgsMapLayerRegistry.instance().layerWasAdded.connect(self.mainWidget.layerAdded) - QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self.mainWidget.layersWillBeRemoved) + QgsMapLayerRegistry.instance().layerWasAdded.connect(self.mainWidget.layerRegistryChanged) + QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self.mainWidget.layerRegistryChanged) def runAsBatch(self): self.close() @@ -101,17 +101,9 @@ class AlgorithmDialog(AlgorithmDialogBase): for param in params: if param.hidden: continue - if isinstance(param, ParameterExtent): - continue - wrapper = self.mainWidget.widget_wrappers[param.name] + wrapper = self.mainWidget.wrappers[param.name] if not self.setParamValue(param, wrapper): - raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper) - - for param in params: - if isinstance(param, ParameterExtent): - wrapper = self.mainWidget.widget_wrappers[param.name] - if not self.setParamValue(param, wrapper): - raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper) + raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget) for output in outputs: if output.hidden: @@ -135,61 +127,7 @@ class AlgorithmDialog(AlgorithmDialogBase): return result def setParamValue(self, param, wrapper, alg=None): - if wrapper.implemented: - return param.setValue(wrapper.value()) - - widget = wrapper.widget - if isinstance(param, ParameterRaster): - return param.setValue(widget.getValue()) - elif isinstance(param, (ParameterVector, ParameterTable)): - try: - return param.setValue(widget.itemData(widget.currentIndex())) - except: - return param.setValue(widget.getValue()) - elif isinstance(param, ParameterSelection): - return param.setValue(widget.currentIndex()) - elif isinstance(param, ParameterFixedTable): - return param.setValue(widget.table) - elif isinstance(param, ParameterRange): - return param.setValue(widget.getValue()) - elif isinstance(param, ParameterTableField): - if param.optional and widget.currentIndex() == 0: - return param.setValue(None) - return param.setValue(widget.currentText()) - elif isinstance(param, ParameterTableMultipleField): - if param.optional and len(list(widget.get_selected_items())) == 0: - return param.setValue(None) - return param.setValue(list(widget.get_selected_items())) - elif isinstance(param, ParameterMultipleInput): - if param.datatype == dataobjects.TYPE_FILE: - return param.setValue(widget.selectedoptions) - else: - if param.datatype == dataobjects.TYPE_RASTER: - options = dataobjects.getRasterLayers(sorting=False) - elif param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = dataobjects.getVectorLayers(sorting=False) - else: - options = dataobjects.getVectorLayers([param.datatype], sorting=False) - return param.setValue([options[i] for i in widget.selectedoptions]) - elif isinstance(param, (ParameterNumber, ParameterFile, - ParameterExtent, ParameterPoint)): - return param.setValue(widget.getValue()) - elif isinstance(param, ParameterString): - if param.multiline: - text = str(widget.toPlainText()) - else: - text = widget.text() - - if param.evaluateExpressions: - try: - text = self.evaluateExpression(text) - except: - pass - return param.setValue(text) - elif isinstance(param, ParameterGeometryPredicate): - return param.setValue(widget.value()) - else: - return param.setValue(str(widget.text())) + return param.setValue(wrapper.value()) def accept(self): self.settings.setValue("/Processing/dialogBase", self.saveGeometry()) @@ -289,6 +227,6 @@ class AlgorithmDialog(AlgorithmDialogBase): '\nOpen the results dialog to check it.')) def closeEvent(self, evt): - QgsMapLayerRegistry.instance().layerWasAdded.disconnect(self.mainWidget.layerAdded) - QgsMapLayerRegistry.instance().layersWillBeRemoved.disconnect(self.mainWidget.layersWillBeRemoved) + QgsMapLayerRegistry.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged) + QgsMapLayerRegistry.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged) super(AlgorithmDialog, self).closeEvent(evt) diff --git a/python/plugins/processing/gui/BatchInputSelectionPanel.py b/python/plugins/processing/gui/BatchInputSelectionPanel.py index ef96de3ddf5..21d40bbadc0 100644 --- a/python/plugins/processing/gui/BatchInputSelectionPanel.py +++ b/python/plugins/processing/gui/BatchInputSelectionPanel.py @@ -45,11 +45,10 @@ from processing.tools import dataobjects class BatchInputSelectionPanel(QWidget): - def __init__(self, param, row, col, panel): + def __init__(self, param, row, col, dialog): super(BatchInputSelectionPanel, self).__init__(None) self.param = param - self.panel = panel - self.table = self.panel.tblParameters + self.dialog = dialog self.row = row self.col = col self.horizontalLayout = QHBoxLayout(self) @@ -67,6 +66,12 @@ class BatchInputSelectionPanel(QWidget): self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout) + def _panel(self): + return self.dialog.mainDialog() + + def _table(self): + return self._panel().tblParameters + def showPopupMenu(self): popupmenu = QMenu() @@ -108,11 +113,11 @@ class BatchInputSelectionPanel(QWidget): if isinstance(self.param, ParameterMultipleInput): self.text.setText(';'.join(layers[idx].name() for idx in selected)) else: - rowdif = len(selected) - (self.table.rowCount() - self.row) + rowdif = len(selected) - (self._table().rowCount() - self.row) for i in range(rowdif): - self.panel.addRow() + self._panel().addRow() for i, layeridx in enumerate(selected): - self.table.cellWidget(i + self.row, + self._table().cellWidget(i + self.row, self.col).setText(layers[layeridx].name()) def showFileSelectionDialog(self): @@ -141,11 +146,11 @@ class BatchInputSelectionPanel(QWidget): if isinstance(self.param, ParameterMultipleInput): self.text.setText(';'.join(str(f) for f in files)) else: - rowdif = len(files) - (self.table.rowCount() - self.row) + rowdif = len(files) - (self._table().rowCount() - self.row) for i in range(rowdif): - self.panel.addRow() + self._panel().addRow() for i, f in enumerate(files): - self.table.cellWidget(i + self.row, + self._table().cellWidget(i + self.row, self.col).setText(f) def setText(self, text): diff --git a/python/plugins/processing/gui/BatchPanel.py b/python/plugins/processing/gui/BatchPanel.py index 927adef5136..58d8441c717 100644 --- a/python/plugins/processing/gui/BatchPanel.py +++ b/python/plugins/processing/gui/BatchPanel.py @@ -36,11 +36,7 @@ from qgis.PyQt.QtWidgets import QTableWidgetItem, QComboBox, QLineEdit, QHeaderV from qgis.core import QgsApplication -from processing.gui.wrappers import ( - DIALOG_BATCH, - wrapper_from_param, - NotYetImplementedWidgetWrapper, -) +from processing.gui.wrappers import NotYetImplementedWidgetWrapper from processing.gui.FileSelectionPanel import FileSelectionPanel from processing.gui.CrsSelectionPanel import CrsSelectionPanel @@ -77,7 +73,7 @@ class BatchPanel(BASE, WIDGET): super(BatchPanel, self).__init__(None) self.setupUi(self) - self.widget_wrappers = [] + self.wrappers = [] self.btnAdvanced.hide() @@ -148,45 +144,15 @@ class BatchPanel(BASE, WIDGET): self.tblParameters.horizontalHeader().setStretchLastSection(True) def getWidgetWrapperFromParameter(self, param, row, col): - wrapper = wrapper_from_param(param) # , DIALOG_BATCH) - if wrapper is not None: - return wrapper + return param.wrapper(self.parent, row, col) - widget = self.getWidgetFromParameter(param, row, col) - wrapper = NotYetImplementedWidgetWrapper(param, widget) - return wrapper def getWidgetFromParameter(self, param, row, col): - if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable, - ParameterMultipleInput)): - item = BatchInputSelectionPanel(param, row, col, self) - elif isinstance(param, ParameterSelection): - item = QComboBox() - item.addItems(param.options) - elif isinstance(param, ParameterFixedTable): - item = FixedTablePanel(param) - elif isinstance(param, ParameterExtent): - item = ExtentSelectionPanel(self.parent, self.alg, param.default) - elif isinstance(param, ParameterPoint): - item = PointSelectionPanel(self.parent, param.default) - elif isinstance(param, ParameterCrs): - item = CrsSelectionPanel(param.default) - elif isinstance(param, ParameterFile): - item = FileSelectionPanel(param.isFolder) - elif isinstance(param, ParameterGeometryPredicate): + if isinstance(param, ParameterGeometryPredicate): item = GeometryPredicateSelectionPanel(param.enabledPredicates, rows=1) width = max(self.tblParameters.columnWidth(col), item.sizeHint().width()) self.tblParameters.setColumnWidth(col, width) - else: - item = QLineEdit() - if param.default is not None: - try: - item.setText(str(param.default)) - except: - pass - - return item def load(self): filename, selected_filter = QFileDialog.getOpenFileName(self, @@ -211,8 +177,8 @@ class BatchPanel(BASE, WIDGET): continue if param.name in params: value = params[param.name] - wrapper = self.widget_wrappers[row][column] - self.setValueInWidgetWrapper(wrapper, value) + wrapper = self.wrappers[row][column] + wrapper.setValue(value) column += 1 for out in self.alg.outputs: @@ -221,7 +187,7 @@ class BatchPanel(BASE, WIDGET): if out.name in outputs: value = outputs[out.name] widget = self.tblParameters.cellWidget(row, column) - self.setValueInWidget(widget, value) + widget.setValue(value) column += 1 except TypeError: QMessageBox.critical( @@ -235,22 +201,14 @@ class BatchPanel(BASE, WIDGET): self.setValueInWidget(wrapper.widget, value) def setValueInWidget(self, widget, value): - if isinstance(widget, (BatchInputSelectionPanel, QLineEdit, FileSelectionPanel)): - widget.setText(str(value)) - elif isinstance(widget, (BatchOutputSelectionPanel, GeometryPredicateSelectionPanel)): - widget.setValue(str(value)) - - elif isinstance(widget, QComboBox): - idx = widget.findText(str(value)) - if idx != -1: - widget.setCurrentIndex(idx) + if isinstance(widget, (BatchOutputSelectionPanel, GeometryPredicateSelectionPanel)): + widget.setValue(unicode(value)) elif isinstance(widget, ExtentSelectionPanel): if value is not None: widget.setExtentFromString(value) else: widget.setExtentFromString('') - elif isinstance(widget, CrsSelectionPanel): - widget.setAuthId(value) + def save(self): toSave = [] @@ -265,7 +223,7 @@ class BatchPanel(BASE, WIDGET): if isinstance(param, ParameterExtent): col += 1 continue - wrapper = self.widget_wrappers[row][col] + wrapper = self.wrappers[row][col] if not self.setParamValue(param, wrapper, alg): self.parent.lblProgress.setText( self.tr('Missing parameter value: %s (row %d)') % (param.description, row + 1)) @@ -277,7 +235,7 @@ class BatchPanel(BASE, WIDGET): if param.hidden: continue if isinstance(param, ParameterExtent): - wrapper = self.widget_wrappers[row][col] + wrapper = self.wrappers[row][col] if not self.setParamValue(param, wrapper, alg): self.parent.lblProgress.setText( self.tr('Missing parameter value: %s (row %d)') % (param.description, row + 1)) @@ -313,29 +271,17 @@ class BatchPanel(BASE, WIDGET): return param.setValue(wrapper.value()) widget = wrapper.widget - if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable, - ParameterMultipleInput)): - value = widget.getText() - if str(value).strip() == '': - value = None - return param.setValue(value) - elif isinstance(param, ParameterSelection): - return param.setValue(widget.currentIndex()) - elif isinstance(param, ParameterFixedTable): - return param.setValue(widget.table) - elif isinstance(param, ParameterExtent): + if isinstance(param, ParameterExtent): if alg is not None: widget.useNewAlg(alg) return param.setValue(widget.getValue()) - elif isinstance(param, (ParameterCrs, ParameterFile)): - return param.setValue(widget.getValue()) elif isinstance(param, ParameterGeometryPredicate): return param.setValue(widget.value()) else: return param.setValue(widget.text()) def setCellWrapper(self, row, column, wrapper): - self.widget_wrappers[row][column] = wrapper + self.wrappers[row][column] = wrapper self.tblParameters.setCellWidget(row, column, wrapper.widget) def addRow(self): @@ -369,12 +315,12 @@ class BatchPanel(BASE, WIDGET): self.tblParameters.setCellWidget(row, column, item) def removeRows(self): - #~ self.tblParameters.setUpdatesEnabled(False) - #~ indexes = self.tblParameters.selectionModel().selectedIndexes() - #~ indexes.sort() - #~ for i in reversed(indexes): - #~ self.tblParameters.model().removeRow(i.row()) - #~ self.tblParameters.setUpdatesEnabled(True) + # ~ self.tblParameters.setUpdatesEnabled(False) + # ~ indexes = self.tblParameters.selectionModel().selectedIndexes() + # ~ indexes.sort() + # ~ for i in reversed(indexes): + # ~ self.tblParameters.model().removeRow(i.row()) + # ~ self.tblParameters.setUpdatesEnabled(True) if self.tblParameters.rowCount() > 2: self.widget_wrappers.pop() self.tblParameters.setRowCount(self.tblParameters.rowCount() - 1) diff --git a/python/plugins/processing/gui/ExtentSelectionPanel.py b/python/plugins/processing/gui/ExtentSelectionPanel.py index 89437637ea3..dce7080c9cd 100644 --- a/python/plugins/processing/gui/ExtentSelectionPanel.py +++ b/python/plugins/processing/gui/ExtentSelectionPanel.py @@ -50,13 +50,13 @@ WIDGET, BASE = uic.loadUiType( class ExtentSelectionPanel(BASE, WIDGET): - def __init__(self, dialog, alg, default=None): + def __init__(self, dialog, param): super(ExtentSelectionPanel, self).__init__(None) self.setupUi(self) self.dialog = dialog - self.alg = alg - if alg.canUseAutoExtent(): + self.param = param + if self.param.optional: if hasattr(self.leText, 'setPlaceholderText'): self.leText.setPlaceholderText( self.tr('[Leave blank to use min covering extent]')) @@ -68,18 +68,19 @@ class ExtentSelectionPanel(BASE, WIDGET): self.tool = RectangleMapTool(canvas) self.tool.rectangleCreated.connect(self.updateExtent) - if default: - tokens = str(default).split(',') + if param.default: + tokens = param.default.split(',') if len(tokens) == 4: try: float(tokens[0]) float(tokens[1]) float(tokens[2]) float(tokens[3]) - self.leText.setText(str(default)) + self.leText.setText(param.default) except: pass + def selectExtent(self): popupmenu = QMenu() useLayerExtentAction = QAction( @@ -93,7 +94,7 @@ class ExtentSelectionPanel(BASE, WIDGET): selectOnCanvasAction.triggered.connect(self.selectOnCanvas) useLayerExtentAction.triggered.connect(self.useLayerExtent) - if self.canUseAutoExtent(): + if self.param.optional: useMincoveringExtentAction = QAction( self.tr('Use min covering extent from input layers'), self.btnSelect) @@ -153,9 +154,10 @@ class ExtentSelectionPanel(BASE, WIDGET): self.dialog.activateWindow() def getValue(self): - if str(self.leText.text()).strip() == '': + if str(self.leText.text()).strip() != '': + return str(self.leText.text()) + else: return None - return str(self.leText.text()) def setExtentFromString(self, s): self.leText.setText(s) diff --git a/python/plugins/processing/gui/NumberInputPanel.py b/python/plugins/processing/gui/NumberInputPanel.py index e9dcc759a97..3c3c55a3472 100644 --- a/python/plugins/processing/gui/NumberInputPanel.py +++ b/python/plugins/processing/gui/NumberInputPanel.py @@ -62,7 +62,7 @@ class NumberInputPanel(BASE, WIDGET): if self.isInteger: self.spnValue.setDecimals(0) else: - #Guess reasonable step value + # Guess reasonable step value if (maximum == 0 or maximum) and (minimum == 0 or minimum): self.spnValue.setSingleStep(self.calculateStep(minimum, maximum)) @@ -75,7 +75,7 @@ class NumberInputPanel(BASE, WIDGET): else: self.spnValue.setMinimum(-99999999) - #Set default value + # Set default value if number == 0 or number: self.spnValue.setValue(float(number)) self.spnValue.setClearValue(float(number)) @@ -149,6 +149,9 @@ class NumberInputPanel(BASE, WIDGET): def getValue(self): return self.spnValue.value() + def setValue(self, value): + self.spnValue.setValue(value) + def calculateStep(self, minimum, maximum): valueRange = maximum - minimum if valueRange <= 1.0: diff --git a/python/plugins/processing/gui/ParametersPanel.py b/python/plugins/processing/gui/ParametersPanel.py index 07e086b27b7..f72835091a5 100644 --- a/python/plugins/processing/gui/ParametersPanel.py +++ b/python/plugins/processing/gui/ParametersPanel.py @@ -42,10 +42,7 @@ from qgis.PyQt.QtGui import QIcon from processing.core.ProcessingConfig import ProcessingConfig -from processing.gui.wrappers import ( - wrapper_from_param, - NotYetImplementedWidgetWrapper, - ) +from processing.gui.wrappers import NotYetImplementedWidgetWrapper from processing.gui.OutputSelectionPanel import OutputSelectionPanel from processing.gui.InputLayerSelectorPanel import InputLayerSelectorPanel @@ -82,8 +79,6 @@ from processing.core.outputs import OutputRaster from processing.core.outputs import OutputTable from processing.core.outputs import OutputVector -from processing.tools import dataobjects - pluginPath = os.path.split(os.path.dirname(__file__))[0] WIDGET, BASE = uic.loadUiType( os.path.join(pluginPath, 'ui', 'widgetParametersPanel.ui')) @@ -105,7 +100,7 @@ class ParametersPanel(BASE, WIDGET): self.parent = parent self.alg = alg self.valueItems = {} - self.widget_wrappers = {} + self.wrappers = {} self.labels = {} self.widgets = {} self.checkBoxes = {} @@ -114,69 +109,9 @@ class ParametersPanel(BASE, WIDGET): self.initWidgets() - def layerAdded(self, layer): - if layer.type() == QgsMapLayer.VectorLayer: - for param in self.alg.parameters: - if param.hidden: - continue - if isinstance(param, ParameterVector): - if dataobjects.canUseVectorLayer(layer, param.datatype): - widget = self.valueItems[param.name] - if isinstance(widget, InputLayerSelectorPanel): - widget = widget.cmbText - widget.addItem(self.getExtendedLayerName(layer), layer) - elif layer.type() == QgsMapLayer.RasterLayer and dataobjects.canUseRasterLayer(layer): - for param in self.alg.parameters: - if param.hidden: - continue - if isinstance(param, ParameterRaster): - widget = self.valueItems[param.name].cmbText - widget.addItem(self.getExtendedLayerName(layer), layer) - - self.updateMultipleInputs() - - def layersWillBeRemoved(self, layers): - for layer in layers: - self.layerRemoved(layer) - - def layerRemoved(self, layer): - layer = QgsMapLayerRegistry.instance().mapLayer(layer) - widget = None - if layer.type() == QgsMapLayer.VectorLayer: - for param in self.alg.parameters: - if param.hidden: - continue - if isinstance(param, ParameterVector): - widget = self.valueItems[param.name] - if isinstance(widget, InputLayerSelectorPanel): - widget = widget.cmbText - - elif layer.type() == QgsMapLayer.RasterLayer: - for param in self.alg.parameters: - if param.hidden: - continue - if isinstance(param, ParameterRaster): - widget = self.valueItems[param.name].cmbText - - if widget is not None: - idx = widget.findData(layer) - if idx != -1: - widget.removeItem(idx) - - self.updateMultipleInputs() - - def updateMultipleInputs(self): - for param in self.alg.parameters: - if isinstance(param, ParameterMultipleInput) and param.datatype != dataobjects.TYPE_FILE: - if param.datatype == dataobjects.TYPE_RASTER: - options = dataobjects.getRasterLayers(sorting=False) - elif param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = dataobjects.getVectorLayers(sorting=False) - else: - options = dataobjects.getVectorLayers([param.datatype], sorting=False) - opts = [self.getExtendedLayerName(opt) for opt in options] - widget = self.valueItems[param.name] - widget.updateForOptions(opts) + def layerRegistryChanged(self, layers): + for wrapper in self.wrappers.values(): + wrapper.refresh() def initWidgets(self): # If there are advanced parameters — show corresponding groupbox @@ -201,12 +136,11 @@ class ParametersPanel(BASE, WIDGET): pass wrapper = self.getWidgetWrapperFromParameter(param) - self.widget_wrappers[param.name] = wrapper + self.wrappers[param.name] = wrapper self.valueItems[param.name] = wrapper.widget widget = wrapper.widget - if isinstance(param, ParameterVector) and \ - not self.alg.allowOnlyOpenedLayers: + if isinstance(param, ParameterVector): layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) @@ -222,28 +156,21 @@ class ParametersPanel(BASE, WIDGET): widget = QWidget() widget.setLayout(layout) + print wrapper tooltips = self.alg.getParameterDescriptions() widget.setToolTip(tooltips.get(param.name, param.description)) - if isinstance(widget, QCheckBox): - widget.setText(desc) - if param.isAdvanced: - self.layoutAdvanced.addWidget(widget) - else: - self.layoutMain.insertWidget( - self.layoutMain.count() - 2, widget) + label = QLabel(desc) + # label.setToolTip(tooltip) + self.labels[param.name] = label + if param.isAdvanced: + self.layoutAdvanced.addWidget(label) + self.layoutAdvanced.addWidget(widget) else: - label = QLabel(desc) - #label.setToolTip(tooltip) - self.labels[param.name] = label - if param.isAdvanced: - self.layoutAdvanced.addWidget(label) - self.layoutAdvanced.addWidget(widget) - else: - self.layoutMain.insertWidget( - self.layoutMain.count() - 2, label) - self.layoutMain.insertWidget( - self.layoutMain.count() - 2, widget) + self.layoutMain.insertWidget( + self.layoutMain.count() - 2, label) + self.layoutMain.insertWidget( + self.layoutMain.count() - 2, widget) self.widgets[param.name] = widget @@ -262,24 +189,9 @@ class ParametersPanel(BASE, WIDGET): self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name] = check self.valueItems[output.name] = widget - wrapper = NotYetImplementedWidgetWrapper(output, widget) - self.widget_wrappers[output.name] = wrapper - if isinstance(output, OutputVector): - if output.base_input in self.dependentItems: - items = self.dependentItems[output.base_input] - else: - items = [] - self.dependentItems[output.base_input] = items - items.append(output) - - base_input = self.alg.getParameterFromName(output.base_input) - if isinstance(base_input, ParameterVector): - layers = dataobjects.getVectorLayers(base_input.datatype) - else: - layers = dataobjects.getTables() - if len(layers) > 0: - output.base_layer = layers[0] + for wrapper in self.wrappers.values(): + wrapper.postInitialize(self.wrappers.values()) def buttonToggled(self, value): if value: @@ -288,213 +200,11 @@ class ParametersPanel(BASE, WIDGET): if button is not sender: button.setChecked(False) - def getExtendedLayerName(self, layer): - authid = layer.crs().authid() - if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) \ - and authid is not None: - return u'{} [{}]'.format(layer.name(), authid) - else: - return layer.name() - def getWidgetWrapperFromParameter(self, param): - wrapper = wrapper_from_param(param) - if wrapper is not None: - return wrapper - - widget = self.getWidgetFromParameter(param) - wrapper = NotYetImplementedWidgetWrapper(param, widget) + wrapper = param.wrapper(self.parent) + wrapper.widgetValueHasChanged.connect(self.widgetValueHasChanged) return wrapper - def getWidgetFromParameter(self, param): - # TODO Create Parameter widget class that holds the logic - # for creating a widget that belongs to the parameter. - if isinstance(param, ParameterRaster): - layers = dataobjects.getRasterLayers() - items = [] - if param.optional: - items.append((self.NOT_SELECTED, None)) - for layer in layers: - items.append((self.getExtendedLayerName(layer), layer)) - item = InputLayerSelectorPanel(items, param) - elif isinstance(param, ParameterVector): - if self.somethingDependsOnThisParameter(param) or self.alg.allowOnlyOpenedLayers: - item = QComboBox() - layers = dataobjects.getVectorLayers(param.datatype) - layers.sort(key=lambda lay: lay.name()) - if param.optional: - item.addItem(self.NOT_SELECTED, None) - for layer in layers: - item.addItem(self.getExtendedLayerName(layer), layer) - item.currentIndexChanged.connect(self.updateDependentFields) - item.name = param.name - else: - layers = dataobjects.getVectorLayers(param.datatype) - items = [] - if param.optional: - items.append((self.NOT_SELECTED, None)) - for layer in layers: - items.append((self.getExtendedLayerName(layer), layer)) - # if already set, put first in list - for i, (name, layer) in enumerate(items): - if layer and layer.source() == param.value: - items.insert(0, items.pop(i)) - item = InputLayerSelectorPanel(items, param) - elif isinstance(param, ParameterTable): - if self.somethingDependsOnThisParameter(param): - item = QComboBox() - layers = dataobjects.getTables() - if param.optional: - item.addItem(self.NOT_SELECTED, None) - for layer in layers: - item.addItem(layer.name(), layer) - item.currentIndexChanged.connect(self.updateDependentFields) - item.name = param.name - else: - layers = dataobjects.getTables() - items = [] - if param.optional: - items.append((self.NOT_SELECTED, None)) - for layer in layers: - items.append((layer.name(), layer)) - # if already set, put first in list - for i, (name, layer) in enumerate(items): - if layer and layer.source() == param.value: - items.insert(0, items.pop(i)) - item = InputLayerSelectorPanel(items, param) - elif isinstance(param, ParameterTableField) or isinstance(param, ParameterTableMultipleField): - if isinstance(param, ParameterTableMultipleField): - item = ListMultiSelectWidget() - else: - item = QComboBox() - if param.parent in self.dependentItems: - items = self.dependentItems[param.parent] - else: - items = [] - self.dependentItems[param.parent] = items - items.append(param) - parent = self.alg.getParameterFromName(param.parent) - if isinstance(parent, ParameterVector): - layers = dataobjects.getVectorLayers(parent.datatype) - else: - layers = dataobjects.getTables() - if len(layers) > 0: - if param.optional and isinstance(param, ParameterTableField): - item.addItem(self.tr('[not set]')) - item.addItems(self.getFields(layers[0], param.datatype)) - elif isinstance(param, ParameterSelection): - item = QComboBox() - item.addItems(param.options) - if param.default: - item.setCurrentIndex(param.default) - elif isinstance(param, ParameterFixedTable): - item = FixedTablePanel(param) - elif isinstance(param, ParameterRange): - item = RangePanel(param) - elif isinstance(param, ParameterFile): - item = FileSelectionPanel(param.isFolder, param.ext) - elif isinstance(param, ParameterMultipleInput): - if param.datatype == dataobjects.TYPE_FILE: - item = MultipleInputPanel(datatype=dataobjects.TYPE_FILE) - else: - if param.datatype == dataobjects.TYPE_RASTER: - options = dataobjects.getRasterLayers(sorting=False) - elif param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = dataobjects.getVectorLayers(sorting=False) - else: - options = dataobjects.getVectorLayers([param.datatype], sorting=False) - opts = [self.getExtendedLayerName(opt) for opt in options] - item = MultipleInputPanel(opts) - elif isinstance(param, ParameterNumber): - item = NumberInputPanel(param.default, param.min, param.max, - param.isInteger) - elif isinstance(param, ParameterExtent): - item = ExtentSelectionPanel(self.parent, self.alg, param.default) - elif isinstance(param, ParameterPoint): - item = PointSelectionPanel(self.parent, param.default) - elif isinstance(param, ParameterString): - if param.multiline: - verticalLayout = QVBoxLayout() - verticalLayout.setSizeConstraint( - QLayout.SetDefaultConstraint) - textEdit = QPlainTextEdit() - if param.default: - textEdit.setPlainText(param.default) - verticalLayout.addWidget(textEdit) - item = textEdit - else: - item = QLineEdit() - if param.default: - item.setText(str(param.default)) - elif isinstance(param, ParameterGeometryPredicate): - item = GeometryPredicateSelectionPanel(param.enabledPredicates) - if param.left: - widget = self.valueItems[param.left] - if isinstance(widget, InputLayerSelectorPanel): - widget = widget.cmbText - widget.currentIndexChanged.connect(item.onLeftLayerChange) - item.leftLayer = widget.itemData(widget.currentIndex()) - if param.right: - widget = self.valueItems[param.right] - if isinstance(widget, InputLayerSelectorPanel): - widget = widget.cmbText - widget.currentIndexChanged.connect(item.onRightLayerChange) - item.rightLayer = widget.itemData(widget.currentIndex()) - item.updatePredicates() - if param.default: - item.setValue(param.default) - else: - item = QLineEdit() - if param.default: - item.setText(str(param.default)) - - return item - - def updateDependentFields(self): - sender = self.sender() - if not isinstance(sender, QComboBox): - return - if sender.name not in self.dependentItems: - return - layer = sender.itemData(sender.currentIndex()) - if not layer: - return - children = self.dependentItems[sender.name] - for child in children: - if (isinstance(child, ParameterTableField) or isinstance( - child, ParameterTableMultipleField)): - widget = self.valueItems[child.name] - widget.clear() - if (self.alg.getParameterFromName(child.name).optional and - not isinstance(child, ParameterTableMultipleField)): - widget.addItem(self.tr('[not set]')) - widget.addItems( - self.getFields(layer, self.alg.getParameterFromName( - child.name).datatype)) - if isinstance(child, OutputVector): - child.base_layer = layer - - def getFields(self, layer, datatype): - fieldTypes = [] - if datatype == ParameterTableField.DATA_TYPE_STRING: - fieldTypes = [QVariant.String] - elif datatype == ParameterTableField.DATA_TYPE_NUMBER: - fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong, - QVariant.UInt, QVariant.ULongLong] - - fieldNames = set() - for field in layer.fields(): - if not fieldTypes or field.type() in fieldTypes: - fieldNames.add(str(field.name())) - return sorted(list(fieldNames), cmp=locale.strcoll) - - def somethingDependsOnThisParameter(self, parent): - for param in self.alg.parameters: - if isinstance(param, (ParameterTableField, - ParameterTableMultipleField)): - if param.parent == parent.name: - return True - for output in self.alg.outputs: - if isinstance(output, OutputVector): - if output.base_layer == parent.name: - return True - return False + def widgetValueHasChanged(self, wrapper): + for wrapper in self.wrappers.values(): + wrapper.anotherParameterWidgetHasChanged(wrapper) diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py index d4228927a0c..6de1b00233a 100644 --- a/python/plugins/processing/gui/wrappers.py +++ b/python/plugins/processing/gui/wrappers.py @@ -5,8 +5,9 @@ BooleanWidget.py --------------------- Date : May 2016 - Copyright : (C) 2016 by Arnaud Morvan + Copyright : (C) 2016 by Arnaud Morvan, Victor Olaya Email : arnaud dot morvan at camptocamp dot com + volayaf at gmail dot com *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -26,34 +27,37 @@ __copyright__ = '(C) 2016, Arnaud Morvan' __revision__ = '$Format:%H$' -from inspect import isclass +import locale from qgis.core import QgsCoordinateReferenceSystem -from qgis.PyQt.QtWidgets import ( - QCheckBox, - QComboBox, -) +from qgis.PyQt.QtWidgets import QCheckBox, QComboBox, QLineEdit, QPlainTextEdit +from qgis.PyQt.QtCore import pyqtSignal, QObject, QVariant +from processing.gui.NumberInputPanel import NumberInputPanel +from processing.gui.InputLayerSelectorPanel import InputLayerSelectorPanel +from processing.modeler.MultilineTextPanel import MultilineTextPanel from processing.gui.CrsSelectionPanel import CrsSelectionPanel +from processing.gui.PointSelectionPanel import PointSelectionPanel +from processing.core.parameters import (ParameterBoolean, ParameterPoint, ParameterFile, + ParameterRaster, ParameterVector, ParameterNumber, ParameterString, ParameterTable, + ParameterTableField, ParameterExtent, ParameterFixedTable) +from processing.core.ProcessingConfig import ProcessingConfig +from processing.gui.FileSelectionPanel import FileSelectionPanel +from processing.core.outputs import (OutputFile, OutputRaster, OutputVector, OutputNumber, + OutputString, OutputTable, OutputExtent) +from processing.tools import dataobjects +from processing.gui.MultipleInputPanel import MultipleInputPanel +from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel +from processing.gui.FixedTablePanel import FixedTablePanel +from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel + DIALOG_STANDARD = 'standard' DIALOG_BATCH = 'batch' DIALOG_MODELER = 'modeler' - -def wrapper_from_param(param, dialog=DIALOG_STANDARD): - wrapper = param.metadata.get('widget_wrapper', None) - # wrapper metadata should be a class path - if isinstance(wrapper, basestring): - tokens = wrapper.split('.') - mod = __import__('.'.join(tokens[:-1]), fromlist=[tokens[-1]]) - wrapper = getattr(mod, tokens[-1]) - # or directly a class object - if isclass(wrapper): - wrapper = wrapper(param=param, dialog=dialog) - # or a wrapper instance - return wrapper - +class InvalidParameterValue(Exception): + pass class NotYetImplementedWidgetWrapper(): @@ -65,19 +69,43 @@ class NotYetImplementedWidgetWrapper(): self.param = param self.widget = widget +dialogTypes = {"AlgorithmDialog":DIALOG_STANDARD, + "ModelerParametersDialog":DIALOG_MODELER, + "BatchAlgorithmDialog": DIALOG_BATCH} -class WidgetWrapper(): +def getExtendedLayerName(layer): + authid = layer.crs().authid() + if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) and authid is not None: + return u'{} [{}]'.format(layer.name(), authid) + else: + return layer.name() + +class WidgetWrapper(QObject): implemented = True # TODO: Should be removed at the end + + widgetValueHasChanged = pyqtSignal(object) - def __init__(self, param, dialog=DIALOG_STANDARD): + def __init__(self, param, dialog, row=0, col=0): + QObject.__init__(self) self.param = param self.dialog = dialog + self.row = row + self.col = col + self.dialogType = dialogTypes[dialog.__class__.__name__] self.widget = self.createWidget() - self.setValue(param.default) + if param.default is not None: + self.setValue(param.default) - def comboValue(self): - return self.widget.itemData(self.widget.currentIndex()) + def comboValue(self, validator=None): + idx = self.widget.findText(self.widget.currentText()) + if idx < 0: + v = self.widget.currentText().strip() + if validator is not None and not validator(v): + raise InvalidParameterValue() + return v + else: + return self.widget.itemData(self.widget.currentIndex()) def createWidget(self): pass @@ -86,41 +114,68 @@ class WidgetWrapper(): pass def setComboValue(self, value): + if isinstance(value, list): + value = value[0] values = [self.widget.itemData(i) for i in range(self.widget.count())] try: idx = values.index(value) self.widget.setCurrentIndex(idx) except ValueError: pass + if self.widget.isEditable(): + if value is not None: + self.widget.setEditText(unicode(value)) def value(self): pass + + def anotherParameterWidgetHasChanged(self, wrapper): + pass + + def postInitialize(self, wrappers): + pass + + def refresh(self): + pass class BooleanWidgetWrapper(WidgetWrapper): def createWidget(self): - if self.dialog == DIALOG_STANDARD: + if self.dialogType == DIALOG_STANDARD: return QCheckBox() - - if self.dialog in (DIALOG_BATCH, DIALOG_MODELER): + elif self.dialogType == DIALOG_BATCH: widget = QComboBox() - widget.addItem(widget.tr('Yes'), True) - widget.addItem(widget.tr('No'), False) + widget.addItem(self.tr('Yes')) + widget.addItem(self.tr('No')) + if self.param.default: + widget.setCurrentIndex(0) + else: + widget.setCurrentIndex(1) + return widget + else: + widget = QComboBox() + widget.addItem('Yes', True) + widget.addItem('No', False) + bools = self.dialog.getAvailableValuesOfType(ParameterBoolean, None) + for b in bools: + widget.addItem(self.dialog.resolveValueDescription(b), b) + if self.param.default: + widget.setCurrentIndex(0) + else: + widget.setCurrentIndex(1) return widget def setValue(self, value): - if self.dialog == DIALOG_STANDARD: + if self.dialogType == DIALOG_STANDARD: self.widget.setChecked(value) - - if self.dialog in (DIALOG_BATCH, DIALOG_MODELER): + else: self.setComboValue(value) def value(self): - if self.dialog == DIALOG_STANDARD: + if self.dialogType == DIALOG_STANDARD: return self.widget.isChecked() - - if self.dialog in (DIALOG_BATCH, DIALOG_MODELER): + else: return self.comboValue() @@ -138,3 +193,590 @@ class CrsWidgetWrapper(WidgetWrapper): def value(self): return self.widget.getValue() + +class ExtentWidgetWrapper(WidgetWrapper): + + def createWidget(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return ExtentSelectionPanel(self.dialog, self.param) + else: + widget = QComboBox() + widget.setEditable(True) + extents = self.getAvailableValuesOfType(ParameterExtent, OutputExtent) + if self.param.optional: + widget.addItem(self.USE_MIN_COVERING_EXTENT, None) + for ex in extents: + widget.addItem(self.dialog.resolveValueDescription(ex), ex) + 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) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return self.widget.getValue() + else: + idx = self.widget.findText(self.widget.currentText()) + if idx < 0: + s = unicode(self.widget.currentText()).strip() + if s: + try: + tokens = s.split(',') + if len(tokens) != 4: + raise InvalidParameterValue() + for token in tokens: + float(token) + except: + raise InvalidParameterValue() + elif self.param.optional: + s = None + else: + raise InvalidParameterValue() + return s + else: + return self.widget.itemData(self.widget.currentIndex()) + + +class PointWidgetWrapper(WidgetWrapper): + + def createWidget(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return PointSelectionPanel(self.dialog, self.param.default) + else: + item = QComboBox() + item.setEditable(True) + points = self.dialog.getAvailableValuesOfType(ParameterPoint) + for p in points: + item.addItem(self.dialog.resolveValueDescription(p), p) + item.setEditText(unicode(self.param.default)) + + def setValue(self, value): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + self.widget.setPointFromString(value) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return self.widget.getValue() + else: + idx = self.widget.findText(self.widget.currentText()) + if idx < 0: + s = unicode(self.widget.currentText()).strip() + if s: + try: + tokens = s.split(',') + if len(tokens) != 2: + raise InvalidParameterValue() + for token in tokens: + float(token) + except: + raise InvalidParameterValue() + elif self.param.optional: + s = None + else: + raise InvalidParameterValue() + return s + else: + return self.widget.itemData(self.widget.currentIndex()) + + +class FileWidgetWrapper(WidgetWrapper): + + def createWidget(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return FileSelectionPanel(self.param.isFolder, self.param.ext) + else: + widget = QComboBox() + widget.setEditable(True) + files = self.dialog.getAvailableValuesOfType(ParameterFile, OutputFile) + for f in files: + widget.addItem(self.dialog.resolveValueDescription(f), f) + return widget + + def setValue(self, value): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + self.widget.setText(value) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return self.widget.getValue() + else: + return self.comboValue() + +class FixedTableWidgetWrapper(WidgetWrapper): + + def createWidget(self): + return FixedTablePanel(self.param) + + def setValue(self, value): + pass + + def value(self): + if self.dialogType == DIALOG_MODELER: + table = self.widget.table + if not bool(table) and not self.param.optional: + raise InvalidParameterValue() + return ParameterFixedTable.tableToString(table) + else: + return self.widget.table + + +class MultipleInputWidgetWrapper(WidgetWrapper): + + def _getOptions(self): + if self.param.datatype == dataobjects.TYPE_VECTOR_ANY: + options = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector) + elif self.param.datatype == dataobjects.TYPE_VECTOR_POINT: + options = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector, + [dataobjects.TYPE_VECTOR_POINT, dataobjects.TYPE_VECTOR_ANY]) + elif self.param.datatype == dataobjects.TYPE_VECTOR_LINE: + options = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector, + [dataobjects.TYPE_VECTOR_LINE, dataobjects.TYPE_VECTOR_ANY]) + elif self.param.datatype == dataobjects.TYPE_VECTOR_POLYGON: + options = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector, + [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_ANY]) + elif self.param.datatype == dataobjects.TYPE_RASTER: + options = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster) + else: + options = self.dialog.getAvailableValuesOfType(ParameterFile, OutputFile) + return options + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + if self.param.datatype == dataobjects.TYPE_FILE: + return MultipleInputPanel(datatype=dataobjects.TYPE_FILE) + else: + if self.param.datatype == dataobjects.TYPE_RASTER: + options = dataobjects.getRasterLayers(sorting=False) + elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY: + options = dataobjects.getVectorLayers(sorting=False) + else: + options = dataobjects.getVectorLayers([self.param.datatype], sorting=False) + opts = [getExtendedLayerName(opt) for opt in options] + return MultipleInputPanel(opts) + elif self.dialogType == DIALOG_BATCH: + return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) + 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: + options = dataobjects.getRasterLayers(sorting=False) + elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY: + options = dataobjects.getVectorLayers(sorting=False) + else: + options = dataobjects.getVectorLayers([self.param.datatype], sorting=False) + opts = [self.getExtendedLayerName(opt) for opt in options] + self.widget.updateForOptions(opts) + + def setValue(self, value): + if self.dialogType == DIALOG_STANDARD: + pass # TODO + elif self.dialogType == DIALOG_BATCH: + return self.widget.setText(value) + else: + options = self._getOptions() + selected = [] + for i, opt in enumerate(options): + if opt in value: + selected.append(i) + self.widget.setSelectedItems(selected) + + def value(self): + if self.dialogType == DIALOG_STANDARD: + if self.param.datatype == dataobjects.TYPE_FILE: + return self.param.setValue(self.widget.selectedoptions) + else: + if self.param.datatype == dataobjects.TYPE_RASTER: + options = dataobjects.getRasterLayers(sorting=False) + elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY: + options = dataobjects.getVectorLayers(sorting=False) + else: + options = dataobjects.getVectorLayers([self.param.datatype], sorting=False) + return self.param.setValue([options[i] for i in self.widget.selectedoptions]) + elif self.dialogType == DIALOG_BATCH: + return self.widget.getText() + else: + options = self._getOptions() + values = [options[i] for i in self.widget.selectedoptions] + if len(values) == 0 and not self.param.optional: + raise InvalidParameterValue() + return values + + +class NumberWidgetWrapper(WidgetWrapper): + + def createWidget(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return NumberInputPanel(self.param.default, self.param.min, self.param.max, + self.param.isInteger) + else: + widget = QComboBox() + widget.setEditable(True) + files = self.dialog.getAvailableValuesOfType(ParameterNumber, OutputNumber) + for f in files: + widget.addItem(self.dialog.resolveValueDescription(f), f) + return widget + + def setValue(self, value): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + self.widget.setValue(value) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): + return self.widget.getValue() + else: + def validator(v): + if str(v).strip(): + try: + if self.param.isInteger: + int(v) + else: + float(v) + return True + except: + return False + else: + return self.param.optional + return self.comboValue(validator) + + +class RasterWidgetWrapper(WidgetWrapper): + + NOT_SELECTED = '[Not selected]' + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + layers = dataobjects.getRasterLayers() + items = [] + if self.param.optional: + items.append((self.NOT_SELECTED, None)) + for layer in layers: + items.append((getExtendedLayerName(layer), layer)) + return InputLayerSelectorPanel(items, self.param) + elif self.dialogType == DIALOG_BATCH: + return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) + else: + widget = QComboBox() + widget.setEditable(True) + files = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster) + for f in files: + widget.addItem(self.dialog.resolveValueDescription(f), f) + return widget + + def refresh(self): + self.widget.cmbText.clear() + layers = dataobjects.getRasterLayers(self) + layers.sort(key=lambda lay: lay.name()) + if self.param.optional: + 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 + elif self.dialogType == DIALOG_BATCH: + return self.widget.setText(value) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType == DIALOG_STANDARD: + return self.widget.getValue() + elif self.dialogType == DIALOG_BATCH: + return self.widget.getText() + else: + return self.comboValue() + + +class SelectionWidgetWrapper(WidgetWrapper): + + def createWidget(self): + 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)) + + def value(self): + return self.widget.currentIndex() + + +class VectorWidgetWrapper(WidgetWrapper): + + NOT_SELECTED = '[Not selected]' + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + widget = QComboBox() + self._populate(widget) + return widget + elif self.dialogType == DIALOG_BATCH: + return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) + else: + widget = QComboBox() + layers = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector) + if self.param.optional: + widget.addItem(self.NOT_SELECTED, None) + 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) + layers.sort(key=lambda lay: lay.name()) + if self.param.optional: + widget.addItem(self.NOT_SELECTED, None) + for layer in layers: + 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 + elif self.dialogType == DIALOG_BATCH: + return self.widget.setText(value) + else: + self.setComboValue(value) + + + def value(self): + if self.dialogType == DIALOG_STANDARD: + try: + return self.widget.itemData(self.widget.currentIndex()) + except: + return self.widget.getValue() + elif self.dialogType == DIALOG_BATCH: + return self.widget.getText() + else: + return self.comboValue() + +class StringWidgetWrapper(WidgetWrapper): + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + if self.param.multiline: + widget = QPlainTextEdit() + if self.param.default: + widget.setPlainText(self.param.default) + else: + widget = QLineEdit() + if self.param.default: + widget.setText(self.param.default) + elif self.dialogType == DIALOG_BATCH: + widget = QLineEdit() + if self.param.default: + widget.setText(self.param.default) + else: + strings = self.dialog.getAvailableValuesOfType(ParameterString, OutputString) + options = [(self.dialog.resolveValueDescription(s), s) for s in strings] + if self.param.multiline: + widget = MultilineTextPanel(options) + widget.setText(self.param.default or "") + else: + widget = QComboBox() + widget.setEditable(True) + for desc, val in options: + widget.addItem(desc, val) + widget.setEditText(self.param.default or "") + return widget + + def setValue(self, value): + if self.dialogType == DIALOG_STANDARD: + pass # TODO + elif self.dialogType == DIALOG_BATCH: + self.widget.setText(value) + else: + if self.param.multiline: + self.widget.setValue(value) + else: + self.setComboValue(value) + + def value(self): + if self.dialogType in DIALOG_STANDARD: + if self.param.multiline: + text = self.widget.toPlainText() + else: + text = self.widget.text() + + if self.param.evaluateExpressions: + try: + text = self.evaluateExpression(text) + except: + pass + return text + if self.dialogType == DIALOG_BATCH: + text = self.widget.text() + if self.param.evaluateExpressions: + try: + text = self.evaluateExpression(text) + except: + pass + return text + else: + if self.param.multiline: + value = self.widget.getValue() + option = self.widget.getOption() + if option == MultilineTextPanel.USE_TEXT: + if value == '': + if self.param.optional: + return None + else: + raise InvalidParameterValue() + else: + return value + else: + return value + else: + def validator(v): + return bool(v) or self.param.optional + return self.comboValue(validator) + + +class TableWidgetWrapper(WidgetWrapper): + + NOT_SELECTED = '[Not selected]' + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + widget = QComboBox() + layers = dataobjects.getTables() + layers.sort(key=lambda lay: lay.name()) + if self.param.optional: + widget.addItem(self.NOT_SELECTED, None) + for layer in layers: + widget.addItem(layer.name(), layer) + widget.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) + widget.name = self.param.name + return widget + elif self.dialogType == DIALOG_BATCH: + return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) + else: + widget = QComboBox() + tables = self.getAvailableValuesOfType(ParameterTable, OutputTable) + layers = self.getAvailableValuesOfType(ParameterVector, OutputVector) + if self.param.optional: + widget.addItem(self.NOT_SELECTED, None) + for table in tables: + widget.addItem(self.dialog.resolveValueDescription(table), table) + for layer in layers: + widget.addItem(self.dialog.resolveValueDescription(layer), layer) + return widget + + def setValue(self, value): + if self.dialogType == DIALOG_STANDARD: + pass # TODO + elif self.dialogType == DIALOG_BATCH: + return self.widget.setText(value) + else: + self.setComboValue(value) + + + def value(self): + if self.dialogType == DIALOG_STANDARD: + try: + return self.widget.itemData(self.widget.currentIndex()) + except: + return self.widget.getValue() + elif self.dialogType == DIALOG_BATCH: + return self.widget.getText() + else: + return self.comboValue() + + +class TableFieldWidgetWrapper(WidgetWrapper): + + NOT_SET = '[Not set]' + + def createWidget(self): + if self.dialogType == DIALOG_STANDARD: + widget = QComboBox() + return widget + elif self.dialogType == DIALOG_BATCH: + item = QLineEdit() + if self.param.default is not None: + item.setText(self.param.default) + else: + widget = QComboBox() + widget.setEditable(True) + fields = self.getAvailableValuesOfType(ParameterTableField, None) + if self.param.optional: + widget.addItem(self.NOT_SELECTED, None) + for f in fields: + widget.addItem(self.resolveValueDescription(f), f) + return widget + + def postInitialize(self, wrappers): + for wrapper in wrappers: + if wrapper.param.name == self.param.parent: + layer = wrapper.widget.itemData(wrapper.widget.currentIndex()) + if layer is not None: + self.widget.clear() + if self.param.optional: + self.widget.addItem(self.tr(self.NOT_SET)) + self.widget.addItems(self.getFields(layer, wrapper.param.datatype)) + break + + def getFields(self, layer, datatype): + fieldTypes = [] + if datatype == ParameterTableField.DATA_TYPE_STRING: + fieldTypes = [QVariant.String] + elif datatype == ParameterTableField.DATA_TYPE_NUMBER: + fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong, + QVariant.UInt, QVariant.ULongLong] + + fieldNames = set() + for field in layer.fields(): + 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.dialogType == DIALOG_STANDARD: + pass # TODO + elif self.dialogType == DIALOG_BATCH: + return self.widget.setText(value) + else: + self.setComboValue(value) + + + def value(self): + if self.dialogType == DIALOG_STANDARD: + if self.param.optional and self.widget.currentIndex() == 0: + return None + return self.widget.currentText() + elif self.dialogType == DIALOG_BATCH: + return self.widget.text() + else: + return self.comboValue() + + def anotherParameterWidgetHasChanged(self,wrapper): + if wrapper.param.name == self.param.parent: + layer = wrapper.value() + if layer is not None: + self.widget.clear() + if self.param.optional: + self.widget.addItem(self.tr(self.NOT_SET)) + self.widget.addItems(self.getFields(layer, wrapper.param.datatype)) + diff --git a/python/plugins/processing/modeler/ModelerParametersDialog.py b/python/plugins/processing/modeler/ModelerParametersDialog.py index 0b156d7dec5..e2295896d02 100644 --- a/python/plugins/processing/modeler/ModelerParametersDialog.py +++ b/python/plugins/processing/modeler/ModelerParametersDialog.py @@ -40,12 +40,7 @@ from qgis.core import QgsNetworkAccessManager from qgis.gui import QgsMessageBar -from processing.gui.wrappers import ( - DIALOG_MODELER, - wrapper_from_param, - NotYetImplementedWidgetWrapper, - ) - +from processing.gui.wrappers import NotYetImplementedWidgetWrapper, InvalidParameterValue from processing.gui.CrsSelectionPanel import CrsSelectionPanel from processing.gui.MultipleInputPanel import MultipleInputPanel from processing.gui.FixedTablePanel import FixedTablePanel @@ -183,7 +178,7 @@ class ModelerParametersDialog(QDialog): self.widgets = {} self.checkBoxes = {} self.showAdvanced = False - self.widget_wrappers = {} + self.wrappers = {} self.valueItems = {} self.dependentItems = {} self.resize(650, 450) @@ -238,8 +233,8 @@ class ModelerParametersDialog(QDialog): label = QLabel(desc) self.labels[param.name] = label - wrapper = self.getWidgetWrapperFromParameter(param) - self.widget_wrappers[param.name] = wrapper + wrapper = param.wrapper(self) + self.wrappers[param.name] = wrapper widget = wrapper.widget self.valueItems[param.name] = widget @@ -255,7 +250,7 @@ class ModelerParametersDialog(QDialog): self.widgets[param.name] = widget self.verticalLayout.addWidget(label) - self.verticalLayout.addWidget(wrapper) + self.verticalLayout.addWidget(wrapper.widget) for output in self._alg.outputs: if output.hidden: @@ -396,135 +391,6 @@ class ModelerParametersDialog(QDialog): alg = self.model.algs[value.alg] return self.tr("'%s' from algorithm '%s'") % (alg.algorithm.getOutputFromName(value.output).description, alg.description) - def getWidgetWrapperFromParameter(self, param): - wrapper = wrapper_from_param(param, DIALOG_MODELER) - if wrapper is None: - widget = self.getWidgetFromParameter(param) - wrapper = NotYetImplementedWidgetWrapper(param, widget) - - model_values = [] - values = self.getAvailableValuesForParam(param) - for value in values: - model_values.append((self.resolveValueDescription(value), value)) - - input_wrapper = ModelerWidgetWrapper(wrapper, model_values) - return input_wrapper - - - def getWidgetFromParameter(self, param): - if isinstance(param, ParameterRaster): - item = QComboBox() - layers = self.getAvailableValuesOfType(ParameterRaster, OutputRaster) - if param.optional: - item.addItem(self.NOT_SELECTED, None) - for layer in layers: - item.addItem(self.resolveValueDescription(layer), layer) - elif isinstance(param, ParameterVector): - item = QComboBox() - layers = self.getAvailableValuesOfType(ParameterVector, OutputVector) - if param.optional: - item.addItem(self.NOT_SELECTED, None) - for layer in layers: - item.addItem(self.resolveValueDescription(layer), layer) - elif isinstance(param, ParameterTable): - item = QComboBox() - tables = self.getAvailableValuesOfType(ParameterTable, OutputTable) - layers = self.getAvailableValuesOfType(ParameterVector, OutputVector) - if param.optional: - item.addItem(self.NOT_SELECTED, None) - for table in tables: - item.addItem(self.resolveValueDescription(table), table) - for layer in layers: - item.addItem(self.resolveValueDescription(layer), layer) - elif isinstance(param, ParameterSelection): - item = QComboBox() - item.addItems(param.options) - item.setCurrentIndex(param.default or 0) - elif isinstance(param, ParameterFixedTable): - item = FixedTablePanel(param) - elif isinstance(param, ParameterRange): - item = RangePanel(param) - elif isinstance(param, ParameterMultipleInput): - if param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector) - elif param.datatype == dataobjects.TYPE_VECTOR_POINT: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POINT, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_LINE: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_LINE, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_POLYGON: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_RASTER: - options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster) - else: - options = self.getAvailableValuesOfType(ParameterFile, OutputFile) - opts = [] - for opt in options: - opts.append(self.resolveValueDescription(opt)) - item = MultipleInputPanel(opts) - elif isinstance(param, ParameterString): - strings = self.getAvailableValuesOfType(ParameterString, OutputString) - options = [(self.resolveValueDescription(s), s) for s in strings] - if param.multiline: - item = MultilineTextPanel(options) - item.setText(str(param.default or "")) - else: - item = QComboBox() - item.setEditable(True) - for desc, val in options: - item.addItem(desc, val) - item.setEditText(str(param.default or "")) - elif isinstance(param, ParameterTableField): - item = QComboBox() - item.setEditable(True) - fields = self.getAvailableValuesOfType(ParameterTableField, None) - for f in fields: - item.addItem(self.resolveValueDescription(f), f) - elif isinstance(param, ParameterTableMultipleField): - item = QComboBox() - item.setEditable(True) - fields = self.getAvailableValuesOfType(ParameterTableMultipleField, None) - for f in fields: - item.addItem(self.resolveValueDescription(f), f) - elif isinstance(param, ParameterNumber): - item = QComboBox() - item.setEditable(True) - numbers = self.getAvailableValuesOfType(ParameterNumber, OutputNumber) - for n in numbers: - item.addItem(self.resolveValueDescription(n), n) - item.setEditText(str(param.default)) - elif isinstance(param, ParameterExtent): - item = QComboBox() - item.setEditable(True) - extents = self.getAvailableValuesOfType(ParameterExtent, OutputExtent) - if self.canUseAutoExtent(): - item.addItem(self.USE_MIN_COVERING_EXTENT, None) - for ex in extents: - item.addItem(self.resolveValueDescription(ex), ex) - if not self.canUseAutoExtent(): - item.setEditText(str(param.default)) - elif isinstance(param, ParameterPoint): - item = QComboBox() - item.setEditable(True) - points = self.getAvailableValuesOfType(ParameterPoint) - for p in points: - item.addItem(self.resolveValueDescription(p), p) - item.setEditText(str(param.default)) - elif isinstance(param, ParameterFile): - item = QComboBox() - item.setEditable(True) - files = self.getAvailableValuesOfType(ParameterFile, OutputFile) - for f in files: - item.addItem(self.resolveValueDescription(f), f) - elif isinstance(param, ParameterGeometryPredicate): - item = GeometryPredicateSelectionPanel(param.enabledPredicates) - else: - item = QLineEdit() - try: - item.setText(str(param.default)) - except: - pass - return item - def canUseAutoExtent(self): for param in self._alg.parameters: if isinstance(param, (ParameterRaster, ParameterVector, ParameterMultipleInput)): @@ -559,22 +425,6 @@ class ModelerParametersDialog(QDialog): self.tableWidget.setCellWidget(i, 1, item) self.tableWidget.setRowHeight(i, 22) - def setComboBoxValue(self, combo, value, param): - if isinstance(value, list): - value = value[0] - items = [combo.itemData(i) for i in range(combo.count())] - try: - idx = items.index(value) - combo.setCurrentIndex(idx) - return - except ValueError: - pass - if combo.isEditable(): - if value is not None: - combo.setEditText(str(value)) - elif isinstance(param, ParameterSelection): - combo.setCurrentIndex(int(value)) - def setPreviousValues(self): if self._algName is not None: alg = self.model.algs[self._algName] @@ -587,52 +437,8 @@ class ModelerParametersDialog(QDialog): else: value = param.default - wrapper = self.widget_wrappers[param.name] - if wrapper.implemented: - wrapper.setValue(value) - continue - - widget = wrapper.widget - if isinstance(param, ( - ParameterRaster, - ParameterVector, - ParameterTable, - ParameterTableField, - ParameterSelection, - ParameterNumber, - ParameterExtent, - ParameterFile, - ParameterPoint, - ParameterCrs - )): - self.setComboBoxValue(widget, value, param) - elif isinstance(param, ParameterString): - if param.multiline: - widget.setValue(value) - else: - self.setComboBoxValue(widget, value, param) - elif isinstance(param, ParameterFixedTable): - pass # TODO! - elif isinstance(param, ParameterMultipleInput): - if param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector) - elif param.datatype == dataobjects.TYPE_VECTOR_POINT: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POINT, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_LINE: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_LINE, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_POLYGON: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_RASTER: - options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster) - else: - options = self.getAvailableValuesOfType(ParameterFile, OutputFile) - selected = [] - for i, opt in enumerate(options): - if opt in value: - selected.append(i) - widget.setSelectedItems(selected) - elif isinstance(param, ParameterGeometryPredicate): - widget.setValue(value) + wrapper = self.wrappers[param.name] + wrapper.setValue(value) for name, out in alg.outputs.items(): widget = self.valueItems[name].setText(out.description) @@ -654,7 +460,7 @@ class ModelerParametersDialog(QDialog): for param in params: if param.hidden: continue - if not self.setParamValue(alg, param, self.widget_wrappers[param.name]): + if not self.setParamValue(alg, param, self.wrappers[param.name]): self.bar.pushMessage("Error", "Wrong or missing value for parameter '%s'" % param.description, level=QgsMessageBar.WARNING) return None @@ -671,194 +477,13 @@ class ModelerParametersDialog(QDialog): return alg - def setParamValueLayerOrTable(self, alg, param, widget): - idx = widget.currentIndex() - if idx < 0: - return False - else: - value = widget.itemData(widget.currentIndex()) - alg.params[param.name] = value - return True - - def setParamTableFieldValue(self, alg, param, widget): - idx = widget.findText(widget.currentText()) - if idx < 0: - s = str(widget.currentText()).strip() - if s == '': - if param.optional: - alg.params[param.name] = None - return True - else: - return False - else: - alg.params[param.name] = s - return True - else: - alg.params[param.name] = widget.itemData(widget.currentIndex()) - return True - - def setParamStringValue(self, alg, param, widget): - if param.multiline: - value = widget.getValue() - option = widget.getOption() - if option == MultilineTextPanel.USE_TEXT: - if value == '': - if param.optional: - alg.params[param.name] = None - return True - else: - return False - else: - alg.params[param.name] = value - else: - alg.params[param.name] = value - else: - idx = widget.findText(widget.currentText()) - if idx < 0: - value = widget.currentText().strip() - if value == '': - if param.optional: - alg.params[param.name] = None - return True - else: - return False - else: - alg.params[param.name] = value - else: - alg.params[param.name] = widget.itemData(widget.currentIndex()) - return True - - def setParamFileValue(self, alg, param, widget): - idx = widget.findText(widget.currentText()) - if idx < 0: - value = widget.currentText() - else: - value = widget.itemData(widget.currentIndex()) - alg.params[param.name] = value - return True - - def setParamNumberValue(self, alg, param, widget): - idx = widget.findText(widget.currentText()) - if idx < 0: - s = widget.currentText().strip() - if s: - try: - value = float(s) - except: - return False - elif param.optional: - value = None - else: - return False - else: - value = widget.itemData(widget.currentIndex()) - alg.params[param.name] = value - return True - - def setParamExtentValue(self, alg, param, widget): - idx = widget.findText(widget.currentText()) - if idx < 0: - s = str(widget.currentText()).strip() - if s: - try: - tokens = s.split(',') - if len(tokens) != 4: - return False - for token in tokens: - float(token) - except: - return False - elif param.optional: - s = None - else: - return False - alg.params[param.name] = [s] - else: - value = widget.itemData(widget.currentIndex()) - alg.params[param.name] = value - return True - - def setParamPointValue(self, alg, param, widget): - idx = widget.findText(widget.currentText()) - if idx < 0: - s = str(widget.currentText()).strip() - if s: - try: - tokens = s.split(',') - if len(tokens) != 2: - return False - for token in tokens: - float(token) - except: - return False - elif param.optional: - s = None - else: - return False - alg.params[param.name] = [s] - else: - value = widget.itemData(widget.currentIndex()) - alg.params[param.name] = value - return True - def setParamValue(self, alg, param, wrapper): - if wrapper.implemented: - alg.params[param.name] = wrapper.value() - return True - - widget = wrapper.widget - if isinstance(param, (ParameterRaster, ParameterVector, - ParameterTable)): - return self.setParamValueLayerOrTable(alg, param, widget) - elif isinstance(param, ParameterString): - return self.setParamStringValue(alg, param, widget) - elif isinstance(param, ParameterNumber): - return self.setParamNumberValue(alg, param, widget) - elif isinstance(param, ParameterExtent): - return self.setParamExtentValue(alg, param, widget) - elif isinstance(param, ParameterPoint): - return self.setParamPointValue(alg, param, widget) - elif isinstance(param, ParameterFile): - return self.setParamFileValue(alg, param, widget) - elif isinstance(param, ParameterSelection): - alg.params[param.name] = widget.currentIndex() - return True - elif isinstance(param, ParameterRange): - alg.params[param.name] = widget.getValue() - return True - elif isinstance(param, ParameterFixedTable): - table = widget.table - if not bool(table) and not param.optional: - return False - alg.params[param.name] = ParameterFixedTable.tableToString(table) - return True - elif isinstance(param, (ParameterTableField, - ParameterTableMultipleField)): - return self.setParamTableFieldValue(alg, param, widget) - elif isinstance(param, ParameterMultipleInput): - if param.datatype == dataobjects.TYPE_VECTOR_ANY: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector) - elif param.datatype == dataobjects.TYPE_VECTOR_POINT: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POINT, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_LINE: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_LINE, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_VECTOR_POLYGON: - options = self.getAvailableValuesOfType(ParameterVector, OutputVector, [dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_ANY]) - elif param.datatype == dataobjects.TYPE_RASTER: - options = self.getAvailableValuesOfType(ParameterRaster, OutputRaster) - else: - options = self.getAvailableValuesOfType(ParameterFile, OutputFile) - values = [options[i] for i in widget.selectedoptions] - if len(values) == 0 and not param.optional: - return False - alg.params[param.name] = values - return True - elif isinstance(param, ParameterGeometryPredicate): - alg.params[param.name] = widget.value() - return True - else: - alg.params[param.name] = str(widget.text()) + try: + value = wrapper.value() + alg.params[param.name] = value return True + except InvalidParameterValue: + return False def okPressed(self): self.alg = self.createAlgorithm()