def testRasterDestination(self): param = QgsProcessingParameterRasterDestination('test') alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') panel = DestinationSelectionPanel(param, alg) panel.setValue('/home/me/test.tif') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '/home/me/test.tif') panel.setValue(QgsProcessing.TEMPORARY_OUTPUT) v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.sink.staticValue(), QgsProcessing.TEMPORARY_OUTPUT) ProcessingConfig.setSettingValue(ProcessingConfig.OUTPUT_FOLDER, testDataPath) panel.setValue('test.tif') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), os.path.join(testDataPath, 'test.tif'))
def testFileDestination(self): param = QgsProcessingParameterFileDestination('test') alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') panel = DestinationSelectionPanel(param, alg) panel.setValue('/home/me/test.tif') v = panel.getValue() self.assertEqual(v, '/home/me/test.tif') ProcessingConfig.setSettingValue(ProcessingConfig.OUTPUT_FOLDER, testDataPath) panel.setValue('test.tif') v = panel.getValue() self.assertEqual(v, os.path.join(testDataPath, 'test.tif'))
def testVectorDestination(self): param = QgsProcessingParameterVectorDestination('test') alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') panel = DestinationSelectionPanel(param, alg) panel.setValue(QgsProcessing.TEMPORARY_OUTPUT) v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.sink.staticValue(), QgsProcessing.TEMPORARY_OUTPUT) panel.setValue('''ogr:dbname='/me/a.gpkg' table="d" (geom) sql=''') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '''ogr:dbname='/me/a.gpkg' table="d" (geom) sql=''') panel.setValue('''postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='******' password='******' table="stufff"."output" (the_geom) sql=''') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '''postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='******' password='******' table="stufff"."output" (the_geom) sql=''') panel.setValue('/home/me/test.shp') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '/home/me/test.shp') ProcessingConfig.setSettingValue(ProcessingConfig.OUTPUT_FOLDER, testDataPath) panel.setValue('test.shp') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), os.path.join(testDataPath, 'test.shp'))
class ModelerParameterDefinitionDialog(QDialog): def __init__(self, alg, paramType=None, param=None): self.alg = alg self.paramType = paramType self.param = param QDialog.__init__(self) self.setModal(True) self.setupUi() settings = QgsSettings() self.restoreGeometry(settings.value("/Processing/modelParametersDefinitionDialogGeometry", QByteArray())) def closeEvent(self, event): settings = QgsSettings() settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) super(ModelerParameterDefinitionDialog, self).closeEvent(event) def setupUi(self): self.setWindowTitle(self.tr('Parameter Definition')) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(20) self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_BOOLEAN or \ isinstance(self.param, QgsProcessingParameterBoolean): self.state = QCheckBox() self.state.setText(self.tr('Checked')) self.state.setChecked(False) if self.param is not None: self.state.setChecked(bool(self.param.defaultValue())) self.verticalLayout.addWidget(self.state) elif self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self.tr('Default field name, or ; separated list of field names for multiple field parameters')) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in ( parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex(self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem(self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex(self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType == parameters.PARAMETER_NUMBER or self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance))): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType() == QgsProcessingParameterNumber.Integer: default = int(math.floor(default)) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_STRING or isinstance(self.param, QgsProcessingParameterString)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_FILE or isinstance(self.param, QgsProcessingParameterFile)): self.verticalLayout.addWidget(QLabel(self.tr('Type'))) self.fileFolderCombo = QComboBox() self.fileFolderCombo.addItem(self.tr('File')) self.fileFolderCombo.addItem(self.tr('Folder')) if self.param is not None: self.fileFolderCombo.setCurrentIndex( 1 if self.param.behavior() == QgsProcessingParameterFile.Folder else 0) self.verticalLayout.addWidget(self.fileFolderCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs(QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) elif self.paramType == parameters.PARAMETER_ENUM or \ isinstance(self.param, QgsProcessingParameterEnum): self.widget = EnumModelerWidget(self) if self.param is not None: self.widget.setAllowMultiple(bool(self.param.allowMultiple())) self.widget.setOptions(self.param.options()) self.widget.setDefault(self.param.defaultValue()) self.verticalLayout.addWidget(self.widget) elif self.paramType == parameters.PARAMETER_MATRIX or \ isinstance(self.param, QgsProcessingParameterMatrix): self.widget = MatrixModelerWidget(self) if self.param is not None: self.widget.setValue(self.param.defaultValue()) self.widget.setHeaders(self.param.headers()) self.widget.setFixedRows(self.param.hasFixedNumberRows()) self.verticalLayout.addWidget(self.widget) elif isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = DestinationSelectionPanel(self.param, self.alg, default_selection=True) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): provider_name, child_name, output_name = self.param.name().split(':') child = self.alg.childAlgorithms()['{}:{}'.format(provider_name, child_name)] model_output = child.modelOutput(output_name) param_def = child.algorithm().parameterDefinition(model_output.childOutputName()) if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addStretch() self.verticalLayout.addWidget(self.buttonBox) self.setLayout(self.verticalLayout) def accept(self): description = self.nameTextBox.text() if description.strip() == '': QMessageBox.warning(self, self.tr('Unable to define parameter'), self.tr('Invalid parameter name')) return if self.param is None: validChars = \ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' safeName = ''.join(c for c in description if c in validChars) name = safeName.lower() i = 2 while self.alg.parameterDefinition(name): name = safeName.lower() + str(i) i += 1 else: name = self.param.name() if (self.paramType == parameters.PARAMETER_BOOLEAN or isinstance(self.param, QgsProcessingParameterBoolean)): self.param = QgsProcessingParameterBoolean(name, description, self.state.isChecked()) elif (self.paramType == parameters.PARAMETER_TABLE_FIELD or isinstance(self.param, QgsProcessingParameterField)): if self.parentCombo.currentIndex() < 0: QMessageBox.warning(self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return parent = self.parentCombo.currentData() datatype = self.datatypeCombo.currentData() default = self.defaultTextBox.text() if not default: default = None self.param = QgsProcessingParameterField(name, description, defaultValue=default, parentLayerParameterName=parent, type=datatype, allowMultiple=self.multipleCheck.isChecked()) elif (self.paramType == parameters.PARAMETER_BAND or isinstance(self.param, QgsProcessingParameterBand)): if self.parentCombo.currentIndex() < 0: QMessageBox.warning(self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return parent = self.parentCombo.currentData() self.param = QgsProcessingParameterBand(name, description, None, parent) elif (self.paramType == parameters.PARAMETER_MAP_LAYER or isinstance(self.param, QgsProcessingParameterMapLayer)): self.param = QgsProcessingParameterMapLayer( name, description) elif (self.paramType == parameters.PARAMETER_RASTER or isinstance(self.param, QgsProcessingParameterRasterLayer)): self.param = QgsProcessingParameterRasterLayer( name, description) elif (self.paramType == parameters.PARAMETER_TABLE or isinstance(self.param, QgsProcessingParameterVectorLayer)): self.param = QgsProcessingParameterVectorLayer( name, description, [self.shapetypeCombo.currentData()]) elif (self.paramType == parameters.PARAMETER_VECTOR or isinstance(self.param, QgsProcessingParameterFeatureSource)): self.param = QgsProcessingParameterFeatureSource( name, description, [self.shapetypeCombo.currentData()]) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.param = QgsProcessingParameterMultipleLayers( name, description, self.datatypeCombo.currentData()) elif (self.paramType == parameters.PARAMETER_NUMBER or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance))): try: self.param = QgsProcessingParameterNumber(name, description, QgsProcessingParameterNumber.Double, self.defaultTextBox.text()) vmin = self.minTextBox.text().strip() if not vmin == '': self.param.setMinimum(float(vmin)) vmax = self.maxTextBox.text().strip() if not vmax == '': self.param.setMaximum(float(vmax)) except: QMessageBox.warning(self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): parent = self.parentCombo.currentData() self.param = QgsProcessingParameterExpression(name, description, str(self.defaultEdit.expression()), parent) elif (self.paramType == parameters.PARAMETER_STRING or isinstance(self.param, QgsProcessingParameterString)): self.param = QgsProcessingParameterString(name, description, str(self.defaultTextBox.text())) elif (self.paramType == parameters.PARAMETER_EXTENT or isinstance(self.param, QgsProcessingParameterExtent)): self.param = QgsProcessingParameterExtent(name, description) elif (self.paramType == parameters.PARAMETER_FILE or isinstance(self.param, QgsProcessingParameterFile)): isFolder = self.fileFolderCombo.currentIndex() == 1 self.param = QgsProcessingParameterFile(name, description, QgsProcessingParameterFile.Folder if isFolder else QgsProcessingParameterFile.File) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.param = QgsProcessingParameterPoint(name, description, str(self.defaultTextBox.text())) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.param = QgsProcessingParameterCrs(name, description, self.selector.crs().authid()) elif (self.paramType == parameters.PARAMETER_ENUM or isinstance(self.param, QgsProcessingParameterEnum)): self.param = QgsProcessingParameterEnum(name, description, self.widget.options(), self.widget.allowMultiple(), self.widget.defaultOptions()) elif (self.paramType == parameters.PARAMETER_MATRIX or isinstance(self.param, QgsProcessingParameterMatrix)): self.param = QgsProcessingParameterMatrix(name, description, hasFixedNumberRows=self.widget.fixedRows(), headers=self.widget.headers(), defaultValue=self.widget.value()) # Destination parameter elif (isinstance(self.param, QgsProcessingParameterFeatureSink)): self.param = QgsProcessingParameterFeatureSink( name=name, description=self.param.description(), type=self.param.dataType(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterFileDestination)): self.param = QgsProcessingParameterFileDestination( name=name, description=self.param.description(), fileFilter=self.param.fileFilter(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterFolderDestination)): self.param = QgsProcessingParameterFolderDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterRasterDestination)): self.param = QgsProcessingParameterRasterDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterVectorDestination)): self.param = QgsProcessingParameterVectorDestination( name=name, description=self.param.description(), type=self.param.dataType(), defaultValue=self.defaultWidget.getValue()) else: if self.paramType: typeId = self.paramType else: typeId = self.param.type() paramTypeDef = QgsApplication.instance().processingRegistry().parameterType(typeId) if not paramTypeDef: msg = self.tr('The parameter `{}` is not registered, are you missing a required plugin?'.format(typeId)) raise UndefinedParameterException(msg) self.param = paramTypeDef.create(name) self.param.setDescription(description) self.param.setMetadata(paramTypeDef.metadata()) if not self.requiredCheck.isChecked(): self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.FlagOptional) else: self.param.setFlags(self.param.flags() & ~QgsProcessingParameterDefinition.FlagOptional) settings = QgsSettings() settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) QDialog.accept(self) def reject(self): self.param = None settings = QgsSettings() settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) QDialog.reject(self)
def setupUi(self): self.setWindowTitle(self.tr('Parameter Definition')) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(20) self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_BOOLEAN or \ isinstance(self.param, QgsProcessingParameterBoolean): self.state = QCheckBox() self.state.setText(self.tr('Checked')) self.state.setChecked(False) if self.param is not None: self.state.setChecked(bool(self.param.defaultValue())) self.verticalLayout.addWidget(self.state) elif self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self.tr('Default field name, or ; separated list of field names for multiple field parameters')) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in ( parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex(self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem(self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex(self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType == parameters.PARAMETER_NUMBER or self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance))): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType() == QgsProcessingParameterNumber.Integer: default = int(math.floor(default)) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_STRING or isinstance(self.param, QgsProcessingParameterString)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_FILE or isinstance(self.param, QgsProcessingParameterFile)): self.verticalLayout.addWidget(QLabel(self.tr('Type'))) self.fileFolderCombo = QComboBox() self.fileFolderCombo.addItem(self.tr('File')) self.fileFolderCombo.addItem(self.tr('Folder')) if self.param is not None: self.fileFolderCombo.setCurrentIndex( 1 if self.param.behavior() == QgsProcessingParameterFile.Folder else 0) self.verticalLayout.addWidget(self.fileFolderCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs(QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) elif self.paramType == parameters.PARAMETER_ENUM or \ isinstance(self.param, QgsProcessingParameterEnum): self.widget = EnumModelerWidget(self) if self.param is not None: self.widget.setAllowMultiple(bool(self.param.allowMultiple())) self.widget.setOptions(self.param.options()) self.widget.setDefault(self.param.defaultValue()) self.verticalLayout.addWidget(self.widget) elif self.paramType == parameters.PARAMETER_MATRIX or \ isinstance(self.param, QgsProcessingParameterMatrix): self.widget = MatrixModelerWidget(self) if self.param is not None: self.widget.setValue(self.param.defaultValue()) self.widget.setHeaders(self.param.headers()) self.widget.setFixedRows(self.param.hasFixedNumberRows()) self.verticalLayout.addWidget(self.widget) elif isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = DestinationSelectionPanel(self.param, self.alg, default_selection=True) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): provider_name, child_name, output_name = self.param.name().split(':') child = self.alg.childAlgorithms()['{}:{}'.format(provider_name, child_name)] model_output = child.modelOutput(output_name) param_def = child.algorithm().parameterDefinition(model_output.childOutputName()) if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addStretch() self.verticalLayout.addWidget(self.buttonBox) self.setLayout(self.verticalLayout)
class ModelerParameterDefinitionDialog(QDialog): @staticmethod def use_legacy_dialog(param=None, paramType=None): if paramType in ( parameters.PARAMETER_TABLE_FIELD, parameters.PARAMETER_BAND, parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE, parameters.PARAMETER_MULTIPLE, parameters.PARAMETER_NUMBER, parameters.PARAMETER_DISTANCE, parameters.PARAMETER_SCALE, parameters.PARAMETER_EXPRESSION, parameters.PARAMETER_POINT, parameters.PARAMETER_CRS, parameters.PARAMETER_ENUM, parameters.PARAMETER_MATRIX): return True elif isinstance( param, (QgsProcessingParameterField, QgsProcessingParameterBand, QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale, QgsProcessingParameterExpression, QgsProcessingParameterPoint, QgsProcessingParameterCrs, QgsProcessingParameterEnum, QgsProcessingParameterMatrix, QgsProcessingDestinationParameter)): return True # yay, use new API! return False def __init__(self, alg, paramType=None, param=None): self.alg = alg self.paramType = paramType self.param = param QDialog.__init__(self) self.setModal(True) self.setupUi() settings = QgsSettings() self.restoreGeometry( settings.value( "/Processing/modelParametersDefinitionDialogGeometry", QByteArray())) def closeEvent(self, event): settings = QgsSettings() settings.setValue( "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) super(ModelerParameterDefinitionDialog, self).closeEvent(event) def switchToCommentTab(self): self.tab.setCurrentIndex(1) self.commentEdit.setFocus() self.commentEdit.selectAll() def setupUi(self): type_metadata = QgsApplication.processingRegistry().parameterType( self.param.type() if self.param else self.paramType) self.setWindowTitle( self.tr('{} Parameter Definition').format(type_metadata.name())) self.mainLayout = QVBoxLayout() self.tab = QTabWidget() self.mainLayout.addWidget(self.tab) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout() self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self. tr('Default field name, or ; separated list of field names for multiple field parameters' )) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in (parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex( self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem( self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex( self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType in (parameters.PARAMETER_NUMBER, parameters.PARAMETER_DISTANCE, parameters.PARAMETER_SCALE) or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale))): if (self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, QgsProcessingParameterDistance)): self.verticalLayout.addWidget(QLabel(self.tr('Linked input'))) self.parentCombo = QComboBox() self.parentCombo.addItem('', '') idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterCrs)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Number type'))) self.type_combo = QComboBox() self.type_combo.addItem(self.tr('Float'), QgsProcessingParameterNumber.Double) self.type_combo.addItem(self.tr('Integer'), QgsProcessingParameterNumber.Integer) if self.param: self.type_combo.setCurrentIndex( self.type_combo.findData(self.param.dataType())) self.verticalLayout.addWidget(self.type_combo) if (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType( ) == QgsProcessingParameterNumber.Integer: default = int(math.floor(float(default))) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs( QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) elif self.paramType == parameters.PARAMETER_ENUM or \ isinstance(self.param, QgsProcessingParameterEnum): self.widget = EnumModelerWidget(self) if self.param is not None: self.widget.setAllowMultiple(bool(self.param.allowMultiple())) self.widget.setOptions(self.param.options()) self.widget.setDefault(self.param.defaultValue()) self.verticalLayout.addWidget(self.widget) elif self.paramType == parameters.PARAMETER_MATRIX or \ isinstance(self.param, QgsProcessingParameterMatrix): self.widget = MatrixModelerWidget(self) if self.param is not None: self.widget.setValue(self.param.headers(), self.param.defaultValue()) self.widget.setFixedRows(self.param.hasFixedNumberRows()) self.verticalLayout.addWidget(self.widget) elif isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = DestinationSelectionPanel( self.param, self.alg, default_selection=True) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked( not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) self.advancedCheck = QCheckBox() self.advancedCheck.setText(self.tr('Advanced')) self.advancedCheck.setChecked(False) if self.param is not None: self.advancedCheck.setChecked( self.param.flags() & QgsProcessingParameterDefinition.FlagAdvanced) self.verticalLayout.addWidget(self.advancedCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): provider_name, child_name, output_name = self.param.name().split( ':') child = self.alg.childAlgorithms()['{}:{}'.format( provider_name, child_name)] model_output = child.modelOutput(output_name) param_def = child.algorithm().parameterDefinition( model_output.childOutputName()) if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) self.advancedCheck.setEnabled(False) self.advancedCheck.setChecked(False) self.verticalLayout.addStretch() w = QWidget() w.setLayout(self.verticalLayout) self.tab.addTab(w, self.tr('Properties')) self.commentLayout = QVBoxLayout() self.commentEdit = QTextEdit() self.commentEdit.setAcceptRichText(False) self.commentLayout.addWidget(self.commentEdit) w2 = QWidget() w2.setLayout(self.commentLayout) self.tab.addTab(w2, self.tr('Comments')) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.mainLayout.addWidget(self.buttonBox) self.setLayout(self.mainLayout) def setComments(self, text): self.commentEdit.setPlainText(text) def comments(self): return self.commentEdit.toPlainText() def accept(self): description = self.nameTextBox.text() if description.strip() == '': QMessageBox.warning(self, self.tr('Unable to define parameter'), self.tr('Invalid parameter name')) return if self.param is None: validChars = \ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' safeName = ''.join(c for c in description if c in validChars) name = safeName.lower() i = 2 while self.alg.parameterDefinition(name): name = safeName.lower() + str(i) i += 1 else: name = self.param.name() if (self.paramType == parameters.PARAMETER_TABLE_FIELD or isinstance(self.param, QgsProcessingParameterField)): if self.parentCombo.currentIndex() < 0: QMessageBox.warning( self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return parent = self.parentCombo.currentData() datatype = self.datatypeCombo.currentData() default = self.defaultTextBox.text() if not default: default = None self.param = QgsProcessingParameterField( name, description, defaultValue=default, parentLayerParameterName=parent, type=datatype, allowMultiple=self.multipleCheck.isChecked()) elif (self.paramType == parameters.PARAMETER_BAND or isinstance(self.param, QgsProcessingParameterBand)): if self.parentCombo.currentIndex() < 0: QMessageBox.warning( self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return parent = self.parentCombo.currentData() self.param = QgsProcessingParameterBand(name, description, None, parent) elif (self.paramType == parameters.PARAMETER_MAP_LAYER or isinstance(self.param, QgsProcessingParameterMapLayer)): self.param = QgsProcessingParameterMapLayer(name, description) elif (self.paramType == parameters.PARAMETER_RASTER or isinstance(self.param, QgsProcessingParameterRasterLayer)): self.param = QgsProcessingParameterRasterLayer(name, description) elif (self.paramType == parameters.PARAMETER_TABLE or isinstance(self.param, QgsProcessingParameterVectorLayer)): self.param = QgsProcessingParameterVectorLayer( name, description, [self.shapetypeCombo.currentData()]) elif (self.paramType == parameters.PARAMETER_VECTOR or isinstance(self.param, QgsProcessingParameterFeatureSource)): self.param = QgsProcessingParameterFeatureSource( name, description, [self.shapetypeCombo.currentData()]) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.param = QgsProcessingParameterMultipleLayers( name, description, self.datatypeCombo.currentData()) elif (self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, QgsProcessingParameterDistance)): self.param = QgsProcessingParameterDistance( name, description, self.defaultTextBox.text()) try: vmin = self.minTextBox.text().strip() if not vmin == '': self.param.setMinimum(float(vmin)) vmax = self.maxTextBox.text().strip() if not vmax == '': self.param.setMaximum(float(vmax)) except: QMessageBox.warning( self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return if self.parentCombo.currentIndex() < 0: QMessageBox.warning( self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return parent = self.parentCombo.currentData() if parent: self.param.setParentParameterName(parent) elif (self.paramType == parameters.PARAMETER_SCALE or isinstance(self.param, QgsProcessingParameterScale)): self.param = QgsProcessingParameterScale( name, description, self.defaultTextBox.text()) elif (self.paramType == parameters.PARAMETER_NUMBER or isinstance(self.param, QgsProcessingParameterNumber)): type = self.type_combo.currentData() self.param = QgsProcessingParameterNumber( name, description, type, self.defaultTextBox.text()) try: vmin = self.minTextBox.text().strip() if not vmin == '': self.param.setMinimum(float(vmin)) vmax = self.maxTextBox.text().strip() if not vmax == '': self.param.setMaximum(float(vmax)) except: QMessageBox.warning( self, self.tr('Unable to define parameter'), self.tr('Wrong or missing parameter values')) return elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): parent = self.parentCombo.currentData() self.param = QgsProcessingParameterExpression( name, description, str(self.defaultEdit.expression()), parent) elif (self.paramType == parameters.PARAMETER_EXTENT or isinstance(self.param, QgsProcessingParameterExtent)): self.param = QgsProcessingParameterExtent(name, description) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.param = QgsProcessingParameterPoint( name, description, str(self.defaultTextBox.text())) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.param = QgsProcessingParameterCrs( name, description, self.selector.crs().authid()) elif (self.paramType == parameters.PARAMETER_ENUM or isinstance(self.param, QgsProcessingParameterEnum)): self.param = QgsProcessingParameterEnum( name, description, self.widget.options(), self.widget.allowMultiple(), self.widget.defaultOptions()) elif (self.paramType == parameters.PARAMETER_MATRIX or isinstance(self.param, QgsProcessingParameterMatrix)): self.param = QgsProcessingParameterMatrix( name, description, hasFixedNumberRows=self.widget.fixedRows(), headers=self.widget.headers(), defaultValue=self.widget.value()) # Destination parameter elif (isinstance(self.param, QgsProcessingParameterFeatureSink)): self.param = QgsProcessingParameterFeatureSink( name=name, description=self.param.description(), type=self.param.dataType(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterFileDestination)): self.param = QgsProcessingParameterFileDestination( name=name, description=self.param.description(), fileFilter=self.param.fileFilter(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterFolderDestination)): self.param = QgsProcessingParameterFolderDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterRasterDestination)): self.param = QgsProcessingParameterRasterDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.getValue()) elif (isinstance(self.param, QgsProcessingParameterVectorDestination)): self.param = QgsProcessingParameterVectorDestination( name=name, description=self.param.description(), type=self.param.dataType(), defaultValue=self.defaultWidget.getValue()) else: if self.paramType: typeId = self.paramType else: typeId = self.param.type() paramTypeDef = QgsApplication.instance().processingRegistry( ).parameterType(typeId) if not paramTypeDef: msg = self.tr( 'The parameter `{}` is not registered, are you missing a required plugin?' .format(typeId)) raise UndefinedParameterException(msg) self.param = paramTypeDef.create(name) self.param.setDescription(description) self.param.setMetadata(paramTypeDef.metadata()) if not self.requiredCheck.isChecked(): self.param.setFlags( self.param.flags() | QgsProcessingParameterDefinition.FlagOptional) else: self.param.setFlags( self.param.flags() & ~QgsProcessingParameterDefinition.FlagOptional) if self.advancedCheck.isChecked(): self.param.setFlags( self.param.flags() | QgsProcessingParameterDefinition.FlagAdvanced) else: self.param.setFlags( self.param.flags() & ~QgsProcessingParameterDefinition.FlagAdvanced) settings = QgsSettings() settings.setValue( "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) QDialog.accept(self) def reject(self): self.param = None settings = QgsSettings() settings.setValue( "/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry()) QDialog.reject(self)
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags( ) & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') wrapper = WidgetWrapperFactory.create_wrapper( param, self.parent) self.wrappers[param.name()] = wrapper widget = wrapper.widget if widget is not None: if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon( os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip( self. tr('Iterate over this layer, creating a separate output for every feature in the layer' )) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) widget.setToolTip(self.formatParameterTooltip(param)) if type(widget) is QCheckBox: # checkbox widget - so description is embedded in widget rather than a separate # label widget.setText(desc) else: label = QLabel(desc) # label.setToolTip(tooltip) self.labels[param.name()] = label if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText( self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(self.formatParameterTooltip(param)) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
def setupUi(self): type_metadata = QgsApplication.processingRegistry().parameterType( self.param.type() if self.param else self.paramType) self.setWindowTitle( self.tr('{} Parameter Definition').format(type_metadata.name())) self.mainLayout = QVBoxLayout() self.tab = QTabWidget() self.mainLayout.addWidget(self.tab) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout() self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self. tr('Default field name, or ; separated list of field names for multiple field parameters' )) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in (parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex( self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem( self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex( self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType in (parameters.PARAMETER_NUMBER, parameters.PARAMETER_DISTANCE, parameters.PARAMETER_SCALE) or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale))): if (self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, QgsProcessingParameterDistance)): self.verticalLayout.addWidget(QLabel(self.tr('Linked input'))) self.parentCombo = QComboBox() self.parentCombo.addItem('', '') idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterCrs)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Number type'))) self.type_combo = QComboBox() self.type_combo.addItem(self.tr('Float'), QgsProcessingParameterNumber.Double) self.type_combo.addItem(self.tr('Integer'), QgsProcessingParameterNumber.Integer) if self.param: self.type_combo.setCurrentIndex( self.type_combo.findData(self.param.dataType())) self.verticalLayout.addWidget(self.type_combo) if (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType( ) == QgsProcessingParameterNumber.Integer: default = int(math.floor(float(default))) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs( QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) elif self.paramType == parameters.PARAMETER_ENUM or \ isinstance(self.param, QgsProcessingParameterEnum): self.widget = EnumModelerWidget(self) if self.param is not None: self.widget.setAllowMultiple(bool(self.param.allowMultiple())) self.widget.setOptions(self.param.options()) self.widget.setDefault(self.param.defaultValue()) self.verticalLayout.addWidget(self.widget) elif self.paramType == parameters.PARAMETER_MATRIX or \ isinstance(self.param, QgsProcessingParameterMatrix): self.widget = MatrixModelerWidget(self) if self.param is not None: self.widget.setValue(self.param.headers(), self.param.defaultValue()) self.widget.setFixedRows(self.param.hasFixedNumberRows()) self.verticalLayout.addWidget(self.widget) elif isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = DestinationSelectionPanel( self.param, self.alg, default_selection=True) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked( not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) self.advancedCheck = QCheckBox() self.advancedCheck.setText(self.tr('Advanced')) self.advancedCheck.setChecked(False) if self.param is not None: self.advancedCheck.setChecked( self.param.flags() & QgsProcessingParameterDefinition.FlagAdvanced) self.verticalLayout.addWidget(self.advancedCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): provider_name, child_name, output_name = self.param.name().split( ':') child = self.alg.childAlgorithms()['{}:{}'.format( provider_name, child_name)] model_output = child.modelOutput(output_name) param_def = child.algorithm().parameterDefinition( model_output.childOutputName()) if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) self.advancedCheck.setEnabled(False) self.advancedCheck.setChecked(False) self.verticalLayout.addStretch() w = QWidget() w.setLayout(self.verticalLayout) self.tab.addTab(w, self.tr('Properties')) self.commentLayout = QVBoxLayout() self.commentEdit = QTextEdit() self.commentEdit.setAcceptRichText(False) self.commentLayout.addWidget(self.commentEdit) w2 = QWidget() w2.setLayout(self.commentLayout) self.tab.addTab(w2, self.tr('Comments')) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.mainLayout.addWidget(self.buttonBox) self.setLayout(self.mainLayout)
def testVectorDestination(self): param = QgsProcessingParameterVectorDestination('test') alg = QgsApplication.processingRegistry().createAlgorithmById('native:centroids') panel = DestinationSelectionPanel(param, alg) panel.setValue('''ogr:dbname='/me/a.gpkg' table="d" (geom) sql=''') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '''ogr:dbname='/me/a.gpkg' table="d" (geom) sql=''') panel.setValue('''postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='******' password='******' table="stufff"."output" (the_geom) sql=''') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '''postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='******' password='******' table="stufff"."output" (the_geom) sql=''') panel.setValue('/home/me/test.shp') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '/home/me/test.shp') ProcessingConfig.setSettingValue(ProcessingConfig.OUTPUT_FOLDER, testDataPath) panel.setValue('test.shp') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), os.path.join(testDataPath, 'test.shp'))
def testRasterDestination(self): param = QgsProcessingParameterRasterDestination('test') alg = QgsApplication.processingRegistry().createAlgorithmById( 'native:centroids') panel = DestinationSelectionPanel(param, alg) panel.setValue('/home/me/test.tif') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), '/home/me/test.tif') panel.setValue(QgsProcessing.TEMPORARY_OUTPUT) v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.sink.staticValue(), QgsProcessing.TEMPORARY_OUTPUT) ProcessingConfig.setSettingValue(ProcessingConfig.OUTPUT_FOLDER, testDataPath) panel.setValue('test.tif') v = panel.getValue() self.assertIsInstance(v, QgsProcessingOutputLayerDefinition) self.assertEqual(v.createOptions, {'fileEncoding': 'System'}) self.assertEqual(v.sink.staticValue(), os.path.join(testDataPath, 'test.tif'))
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break widget_context = QgsProcessingParameterWidgetContext() if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent) self.wrappers[param.name()] = wrapper # For compatibility with 3.x API, we need to check whether the wrapper is # the deprecated WidgetWrapper class. If not, it's the newer # QgsAbstractProcessingParameterWidgetWrapper class # TODO QGIS 4.0 - remove is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper) if not is_python_wrapper: wrapper.setWidgetContext(widget_context) widget = wrapper.createWrappedWidget(self.processing_context) wrapper.registerProcessingContextGenerator(self.context_generator) else: widget = wrapper.widget if self.in_place and param.name() in ('INPUT', 'OUTPUT'): # don't show the input/output parameter widgets in in-place mode # we still need to CREATE them, because other wrappers may need to interact # with them (e.g. those parameters which need the input layer for field # selections/crs properties/etc) continue if widget is not None: if is_python_wrapper: widget.setToolTip(param.toolTip()) if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(6) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer')) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) label = None if not is_python_wrapper: label = wrapper.createWrappedLabel() else: label = wrapper.label if label is not None: if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) elif is_python_wrapper: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags() & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') widget.setText(desc) if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if self.in_place and param.name() in ('INPUT', 'OUTPUT'): continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file after running algorithm')) def skipOutputChanged(checkbox, skipped): checkbox.setEnabled(not skipped) if skipped: checkbox.setChecked(False) check.setChecked(not widget.outputIsSkipped()) check.setEnabled(not widget.outputIsSkipped()) widget.skipOutputChanged.connect(partial(skipOutputChanged, check)) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
def initWidgets(self): # Heavy overload # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break #widget_context = QgsProcessingParameterWidgetContext() #if iface is not None: # widget_context.setMapCanvas(iface.mapCanvas()) # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue print('initWidgets - param.name(): {}'.format(param.name())) if param.isDestination(): # and param.name() != 'OUTPUT_ASC': continue else: wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent) self.wrappers[param.name()] = wrapper #widget = wrapper.widget # For compatibility with 3.x API, we need to check whether the wrapper is # the deprecated WidgetWrapper class. If not, it's the newer # QgsAbstractProcessingParameterWidgetWrapper class # TODO QGIS 4.0 - remove is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper) if not is_python_wrapper: from qgis.gui import (QgsProcessingContextGenerator, QgsProcessingParameterWidgetContext) widget_context = QgsProcessingParameterWidgetContext() if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) wrapper.setWidgetContext(widget_context) widget = wrapper.createWrappedWidget(self.processing_context) wrapper.registerProcessingContextGenerator(self.context_generator) else: widget = wrapper.widget #if self.in_place and param.name() in ('INPUT', 'OUTPUT'): # don't show the input/output parameter widgets in in-place mode # we still need to CREATE them, because other wrappers may need to interact # with them (e.g. those parameters which need the input layer for field # selections/crs properties/etc) # continue if widget is not None: if is_python_wrapper: widget.setToolTip(param.toolTip()) if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(6) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer')) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) label = None if not is_python_wrapper: label = wrapper.createWrappedLabel() else: label = wrapper.label if label is not None: if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) elif is_python_wrapper: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags() & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') widget.setText(desc) if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue #if self.in_place and param.name() in ('INPUT', 'OUTPUT'): # continue label = QLabel(output.description()) #print('initWidgets 2 - param.name(): {}'.format(param.name())) widget = DestinationSelectionPanel(output, self.alg) # TODO, overload self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination # alk: checkboxes for Chloe handling ,ChloeCSVParameterFileDestination, ChloeASCParameterFileDestination, ChloeParameterFolderDestination) ): check = QCheckBox() check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file(s) after running algorithm')) def skipOutputChanged(checkbox, skipped): checkbox.setEnabled(not skipped) if skipped: checkbox.setChecked(False) check.setChecked(not widget.outputIsSkipped()) check.setEnabled(not widget.outputIsSkipped()) widget.skipOutputChanged.connect(partial(skipOutputChanged, check)) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check # initial state if hasattr(output,'addToMapDefaultState'): check.setChecked(output.addToMapDefaultState) widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values())) # # alk: checkboxes for Chloe handling # for output in self.alg.destinationParameterDefinitions(): # if output.flags() & QgsProcessingParameterDefinition.FlagHidden: # continue # if isinstance(output, (ChloeCSVParameterFileDestination)) or isinstance(output, (ChloeASCParameterFileDestination)): # check = QCheckBox() # check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file(s) after running algorithm')) # def skipOutputChanged(checkbox, skipped): # checkbox.setEnabled(not skipped) # if skipped: # checkbox.setChecked(False) # check.setChecked(not widget.outputIsSkipped()) # check.setEnabled(not widget.outputIsSkipped()) # widget.skipOutputChanged.connect(partial(skipOutputChanged, check)) # print(str(self.layoutMain)+1) # self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) # self.checkBoxes[output.name()] = check # # connecting alg outputLoading info with checkbox state # self.alg.outputLoading[output.name()] = check.isChecked() # def updateOutputLoadingState(alg, outputName, checkbox, state): # self.alg.outputLoading[outputName] = checkbox.isChecked() # print( outputName + " " + str(checkbox.isChecked()) + " " + str(self.alg.outputLoading) + " " + str(self.alg)) # #print(str(self.alg.parameters)) # check.stateChanged.connect(partial(updateOutputLoadingState, self, output.name(), check)) # alk: addition of wrapper special config handling # for dependancy between wrapper, i.e. changing the value # of a FileSelectionPanel entails the update of another widget for k in self.wrappers: w = self.wrappers[k] if hasattr(w,'getParentWidgetConfig'): print(str(w) + " " + "getParentWidgetConfig") config = w.getParentWidgetConfig() if config != None: p = self.wrappers[config['paramName']] m = getattr(w, config['refreshMethod']) if m!=None: print(str(p) + " " + str(p.widget)) # todo generalize valueChanged handling # to any type of widget componant if isinstance(p.widget, FileSelectionPanel): p.widget.leText.textChanged.connect(m) elif isinstance(p, RasterWidgetWrapper): try: p.combo.valueChanged.connect(m) # QGIS 3.8 version except: p.combo.currentIndexChanged.connect(m) # QGIS LTR 3.4