From 065b3572e6f437d6a0fc1a35ff9945aef807d5b3 Mon Sep 17 00:00:00 2001 From: Victor Olaya Date: Sat, 13 Apr 2013 09:40:01 +0200 Subject: [PATCH] [sextante] several fixes for supporting optional parameters in modeler --- .../sextante/algs/ftools/ConvexHull.py | 27 +++++----- python/plugins/sextante/core/Sextante.py | 2 - .../sextante/modeler/ModelerAlgorithm.py | 6 +-- .../modeler/ModelerParametersDialog.py | 49 +++++++++++++------ .../sextante/modeler/MultilineTextPanel.py | 5 +- .../sextante/modeler/models/emptystring.model | 20 ++++++++ .../modeler/models/optionalfield.model | 12 +++++ .../sextante/parameters/ParameterExtent.py | 12 ++--- .../sextante/parameters/ParameterString.py | 1 + .../parameters/ParameterTableField.py | 5 +- .../sextante/tests/ModelerAlgorithmTest.py | 42 ++++++++++++++++ python/plugins/sextante/tests/QgisAlgsTest.py | 2 +- 12 files changed, 140 insertions(+), 43 deletions(-) create mode 100644 python/plugins/sextante/modeler/models/emptystring.model create mode 100644 python/plugins/sextante/modeler/models/optionalfield.model diff --git a/python/plugins/sextante/algs/ftools/ConvexHull.py b/python/plugins/sextante/algs/ftools/ConvexHull.py index cc68ac67199..fdb984fd184 100644 --- a/python/plugins/sextante/algs/ftools/ConvexHull.py +++ b/python/plugins/sextante/algs/ftools/ConvexHull.py @@ -59,7 +59,7 @@ class ConvexHull(GeoAlgorithm): self.name = "Convex hull" self.group = "Vector geometry tools" self.addParameter(ParameterVector(ConvexHull.INPUT, "Input layer", ParameterVector.VECTOR_TYPE_ANY)) - self.addParameter(ParameterTableField(ConvexHull.FIELD, "Field", ConvexHull.INPUT)) + self.addParameter(ParameterTableField(ConvexHull.FIELD, "Field (optional, only used if creating convex hulls by classes)", ConvexHull.INPUT, optional = True)) self.addParameter(ParameterSelection(ConvexHull.METHOD, "Method", ConvexHull.METHODS)) self.addOutput(OutputVector(ConvexHull.OUTPUT, "Convex hull")) @@ -71,22 +71,23 @@ class ConvexHull(GeoAlgorithm): GEOS_EXCEPT = True FEATURE_EXCEPT = True - index = layer.fieldNameIndex(fieldName) - fType = layer.pendingFields()[index].type() + f = QgsField("value") f.setType(QVariant.String) f.setLength(255) if useField: - if fType == QVariant.Int: - f.setType(QVariant.Int) - f.setLength(20) - elif fType == QVariant.Double: - f.setType(QVariant.Double) - f.setLength(20) - f.setPrecision(6) - else: - f.setType(QVariant.String) - f.setLength(255) + index = layer.fieldNameIndex(fieldName) + fType = layer.pendingFields()[index].type() + if fType == QVariant.Int: + f.setType(QVariant.Int) + f.setLength(20) + elif fType == QVariant.Double: + f.setType(QVariant.Double) + f.setLength(20) + f.setPrecision(6) + else: + f.setType(QVariant.String) + f.setLength(255) fields = [QgsField("id", QVariant.Int, "", 20), f, diff --git a/python/plugins/sextante/core/Sextante.py b/python/plugins/sextante/core/Sextante.py index aca14ac4037..289a49bcfd4 100644 --- a/python/plugins/sextante/core/Sextante.py +++ b/python/plugins/sextante/core/Sextante.py @@ -268,8 +268,6 @@ class Sextante: return else: i = 0 - - settrace() for param in alg.parameters: if not param.hidden: if not param.setValue(args[i]): diff --git a/python/plugins/sextante/modeler/ModelerAlgorithm.py b/python/plugins/sextante/modeler/ModelerAlgorithm.py index 202d26c9805..59a30d97b7e 100644 --- a/python/plugins/sextante/modeler/ModelerAlgorithm.py +++ b/python/plugins/sextante/modeler/ModelerAlgorithm.py @@ -409,11 +409,11 @@ class ModelerAlgorithm(GeoAlgorithm): aap = self.algParameters[iAlg][param.name] if aap == None: if isinstance(param, ParameterExtent): - value = self.getValueFromAlgorithmAndParameter(aap) - if value is None: - value = self.getMinCoveringExtent() + value = self.getMinCoveringExtent() if not param.setValue(value): raise GeoAlgorithmExecutionException("Wrong value: " + str(value)) + else: + param.setValue(None) continue if isinstance(param, ParameterMultipleInput): value = self.getValueFromAlgorithmAndParameter(aap) diff --git a/python/plugins/sextante/modeler/ModelerParametersDialog.py b/python/plugins/sextante/modeler/ModelerParametersDialog.py index fadf101ed00..ed2d541a02a 100644 --- a/python/plugins/sextante/modeler/ModelerParametersDialog.py +++ b/python/plugins/sextante/modeler/ModelerParametersDialog.py @@ -418,7 +418,7 @@ class ModelerParametersDialog(QtGui.QDialog): elif isinstance(param, ParameterString): strings = self.getStrings() if param.multiline: - item = MultilineTextPanel(strings) + item = MultilineTextPanel(strings,self.model) item.setText(str(param.default)) else: item = QtGui.QComboBox() @@ -597,6 +597,7 @@ class ModelerParametersDialog(QtGui.QDialog): params = self.alg.parameters outputs = self.alg.outputs + for param in params: if param.hidden: continue @@ -650,12 +651,16 @@ class ModelerParametersDialog(QtGui.QDialog): idx = widget.findText(widget.currentText()) if idx < 0: name = self.getSafeNameForHarcodedParameter(param) - value = AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, name) - self.params[param.name] = value - value = str(widget.currentText()).strip() - if value == "": - return False + value = AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, name) + s = str(widget.currentText()).strip() + if s == "": + if param.optional: + self.params[param.name] = None + return True + else: + return False else: + self.params[param.name] = value self.values[name] = str(widget.currentText()) return True else: @@ -664,16 +669,22 @@ class ModelerParametersDialog(QtGui.QDialog): return True def setParamStringValue(self, param, widget): - if param.multiline: - option = widget.getOption() + if param.multiline: + name = self.getSafeNameForHarcodedParameter(param) + paramValue = AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, name) value = widget.getValue() - if option == MultilineTextPanel.USE_TEXT: + option = widget.getOption() + if option == MultilineTextPanel.USE_TEXT: if value == "": - return False - name = self.getSafeNameForHarcodedParameter(param) - self.values[name] = value - paramValue = AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, name) - self.params[param.name] = paramValue + if param.optional: + self.params[param.name] = None + return True + else: + return False + else: + self.values[name] = value + + self.params[param.name] = paramValue else: self.params[param.name] = value else: @@ -684,7 +695,15 @@ class ModelerParametersDialog(QtGui.QDialog): name = self.getSafeNameForHarcodedParameter(param) value = AlgorithmAndParameter(AlgorithmAndParameter.PARENT_MODEL_ALGORITHM, name) self.params[param.name] = value - self.values[name] = str(widget.currentText()) + value = str(widget.currentText()).strip() + if value == "": + if param.optional: + self.values[name] = None + return True + else: + return False + else: + self.values[name] = str(widget.currentText()) else: value = widget.itemData(widget.currentIndex()).toPyObject() self.params[param.name] = value diff --git a/python/plugins/sextante/modeler/MultilineTextPanel.py b/python/plugins/sextante/modeler/MultilineTextPanel.py index c9d6db824f0..514d48e7e91 100644 --- a/python/plugins/sextante/modeler/MultilineTextPanel.py +++ b/python/plugins/sextante/modeler/MultilineTextPanel.py @@ -34,9 +34,10 @@ class MultilineTextPanel(QtGui.QWidget): USE_TEXT = 0 - def __init__(self, options, parent = None): + def __init__(self, options, model, parent = None): super(MultilineTextPanel, self).__init__(parent) self.options = options + self.model = model self.verticalLayout = QtGui.QVBoxLayout(self) self.verticalLayout.setSpacing(2) self.verticalLayout.setMargin(0) @@ -71,7 +72,7 @@ class MultilineTextPanel(QtGui.QWidget): if item.alg == value.alg and item.param == value.param: self.combo.setCurrentIndex(idx) return - self.combo.setCurrentIndex(idx) + self.combo.setCurrentIndex(0) value = self.model.getValueFromAlgorithmAndParameter(value) if value: self.textBox.setPlainText(str(value)) diff --git a/python/plugins/sextante/modeler/models/emptystring.model b/python/plugins/sextante/modeler/models/emptystring.model new file mode 100644 index 00000000000..00575bd2ae3 --- /dev/null +++ b/python/plugins/sextante/modeler/models/emptystring.model @@ -0,0 +1,20 @@ +NAME:A model with an empty string +GROUP:[Test models] +PARAMETER:ParameterVector|VECTORLAYER_V|v|-1|False +120.0,60.0 +VALUE:HARDCODEDPARAMVALUE_FORMULA_0===value = 10 +VALUE:HARDCODEDPARAMVALUE_FIELD_PRECISION_0===0 +VALUE:HARDCODEDPARAMVALUE_FIELD_TYPE_0===0 +VALUE:HARDCODEDPARAMVALUE_FIELD_LENGTH_0===10 +VALUE:HARDCODEDPARAMVALUE_FIELD_NAME_0===NewField +ALGORITHM:qgis:advancedpythonfieldcalculator +120.0,160.0 +None +-1|VECTORLAYER_V +-1|HARDCODEDPARAMVALUE_FIELD_NAME_0 +-1|HARDCODEDPARAMVALUE_FIELD_TYPE_0 +-1|HARDCODEDPARAMVALUE_FIELD_LENGTH_0 +-1|HARDCODEDPARAMVALUE_FIELD_PRECISION_0 +None +-1|HARDCODEDPARAMVALUE_FORMULA_0 +out diff --git a/python/plugins/sextante/modeler/models/optionalfield.model b/python/plugins/sextante/modeler/models/optionalfield.model new file mode 100644 index 00000000000..fe3247b38fe --- /dev/null +++ b/python/plugins/sextante/modeler/models/optionalfield.model @@ -0,0 +1,12 @@ +NAME:A model with an optional field +GROUP:[Test models] +PARAMETER:ParameterVector|VECTORLAYER_V|v|-1|False +120.0,60.0 +VALUE:HARDCODEDPARAMVALUE_METHOD_0===0 +ALGORITHM:qgis:convexhull +135.0,186.0 +None +-1|VECTORLAYER_V +None +-1|HARDCODEDPARAMVALUE_METHOD_0 +result diff --git a/python/plugins/sextante/parameters/ParameterExtent.py b/python/plugins/sextante/parameters/ParameterExtent.py index 2703b4c09c9..b8b7a976aac 100644 --- a/python/plugins/sextante/parameters/ParameterExtent.py +++ b/python/plugins/sextante/parameters/ParameterExtent.py @@ -39,13 +39,13 @@ class ParameterExtent(Parameter): self.value = self.default return True tokens = text.split(",") - if len(tokens)!= 5: + if len(tokens)!= 4: return False try: - n1 = float(tokens[1]) - n2 = float(tokens[2]) - n3 = float(tokens[3]) - n4 = float(tokens[4]) + n1 = float(tokens[0]) + n2 = float(tokens[1]) + n3 = float(tokens[2]) + n4 = float(tokens[3]) self.value=text return True except: @@ -60,5 +60,5 @@ class ParameterExtent(Parameter): def deserialize(self, s): tokens = s.split("|") - return ParameterExtent(tokens[0], tokens[1], tokens[2]) + return ParameterExtent(tokens[1], tokens[2], tokens[3]) diff --git a/python/plugins/sextante/parameters/ParameterString.py b/python/plugins/sextante/parameters/ParameterString.py index 005c94cab66..3dfb9569554 100644 --- a/python/plugins/sextante/parameters/ParameterString.py +++ b/python/plugins/sextante/parameters/ParameterString.py @@ -35,6 +35,7 @@ class ParameterString(Parameter): self.default = default self.value = None self.multiline = multiline + self.optional = optional def setValue(self, obj): if obj is None: diff --git a/python/plugins/sextante/parameters/ParameterTableField.py b/python/plugins/sextante/parameters/ParameterTableField.py index a94b22659bf..62b6454cd30 100644 --- a/python/plugins/sextante/parameters/ParameterTableField.py +++ b/python/plugins/sextante/parameters/ParameterTableField.py @@ -36,6 +36,7 @@ class ParameterTableField(Parameter): self.parent = parent self.value = None self.datatype = datatype + self.optional= optional def getValueAsCommandLineParameter(self): return "\"" + str(self.value) + "\"" @@ -44,7 +45,9 @@ class ParameterTableField(Parameter): return "##" + self.name + "=field " + str(self.parent) def setValue(self, field): - if len(field) > 0: + if field is None: + return self.optional + elif len(field) > 0: self.value = str(field) else: return self.optional diff --git a/python/plugins/sextante/tests/ModelerAlgorithmTest.py b/python/plugins/sextante/tests/ModelerAlgorithmTest.py index aa781801024..91baac5f3ab 100644 --- a/python/plugins/sextante/tests/ModelerAlgorithmTest.py +++ b/python/plugins/sextante/tests/ModelerAlgorithmTest.py @@ -121,6 +121,48 @@ class ModelerAlgorithmTest(unittest.TestCase): dataset=gdal.Open(output, GA_ReadOnly) strhash=hash(str(dataset.ReadAsArray(0).tolist())) self.assertEqual(strhash,-1557050506) + + def test_modeleroptionalfield(self): + outputs=sextante.runalg("modeler:optionalfield",points(),None) + output=outputs['OUTPUT_ALG0'] + layer=QGisLayers.getObjectFromUri(output, True) + fields=layer.pendingFields() + expectednames=['id','value','area','perim'] + expectedtypes=['Integer','String','Real','Real'] + names=[str(f.name()) for f in fields] + types=[str(f.typeName()) for f in fields] + self.assertEqual(expectednames, names) + self.assertEqual(expectedtypes, types) + features=sextante.getfeatures(layer) + self.assertEqual(1, len(features)) + feature=features.next() + attrs=feature.attributes() + expectedvalues=["0","all","3592.818848","230.989919"] + values=[str(attr.toString()) for attr in attrs] + self.assertEqual(expectedvalues, values) + wkt='POLYGON((270839.46818665 4458921.97813894,270778.60197966 4458935.96883677,270786.54279065 4458980.04784113,270803.15756434 4458983.84880322,270839.65586926 4458983.16267036,270855.74530134 4458940.79948673,270839.46818665 4458921.97813894))' + self.assertEqual(wkt, str(feature.geometry().exportToWkt())) + + def test_modeleremptystring(self): + outputs=sextante.runalg("modeler:emptystring",union(),None) + output=outputs['OUTPUT_LAYER_ALG0'] + layer=QGisLayers.getObjectFromUri(output, True) + fields=layer.pendingFields() + expectednames=['ID','POLY_NUM_A','POLY_ST_A','ID_2','POLY_NUM_B','POLY_ST_B','NewField'] + expectedtypes=['Integer','Real','String','Integer','Real','String','Integer'] + names=[str(f.name()) for f in fields] + types=[str(f.typeName()) for f in fields] + self.assertEqual(expectednames, names) + self.assertEqual(expectedtypes, types) + features=sextante.getfeatures(layer) + self.assertEqual(8, len(features)) + feature=features.next() + attrs=feature.attributes() + expectedvalues=["1","1.1","string a","2","1","string a","10"] + values=[str(attr.toString()) for attr in attrs] + self.assertEqual(expectedvalues, values) + wkt='POLYGON((270807.08580285 4458940.1594565,270798.42294527 4458914.62661676,270780.81854858 4458914.21983449,270763.52289518 4458920.715993,270760.3449542 4458926.6570575,270763.78234766 4458958.22561242,270794.30290024 4458942.16424502,270807.08580285 4458940.1594565))' + self.assertEqual(wkt, str(feature.geometry().exportToWkt())) def suite(): diff --git a/python/plugins/sextante/tests/QgisAlgsTest.py b/python/plugins/sextante/tests/QgisAlgsTest.py index 8fa7308b39f..34bf893b89d 100644 --- a/python/plugins/sextante/tests/QgisAlgsTest.py +++ b/python/plugins/sextante/tests/QgisAlgsTest.py @@ -142,7 +142,7 @@ class QgisAlgsTest(unittest.TestCase): self.assertEqual(wkt, str(feature.geometry().exportToWkt())) def test_qgiscreategridnointeger(self): - outputs=sextante.runalg("qgis:creategrid",0.1,0.1,1,1,0,0,None) + outputs=sextante.runalg("qgis:creategrid",0.1,0.1,1,1,0,0,0,None) output=outputs['SAVENAME'] layer=QGisLayers.getObjectFromUri(output, True) fields=layer.pendingFields()