def testStringWithMaxLen(self): """ tests that text edit wrappers correctly handle string fields with a maximum length """ layer = QgsVectorLayer("none?field=fldint:integer", "layer", "memory") assert layer.isValid() layer.dataProvider().addAttributes([QgsField('max', QVariant.String, 'string', 10), QgsField('nomax', QVariant.String, 'string', 0)]) layer.updateFields() QgsMapLayerRegistry.instance().addMapLayer(layer) reg = QgsEditorWidgetRegistry.instance() config = {'IsMultiline': 'True'} # first test for field without character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 2, config, editor, None) self.assertEqual(w.value(), 'this_is_a_long_string') # next test for field with character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 1, config, editor, None) self.assertEqual(w.value(), 'this_is_a_') QgsMapLayerRegistry.instance().removeAllMapLayers()
def testStringWithMaxLen(self): """ tests that text edit wrappers correctly handle string fields with a maximum length """ layer = QgsVectorLayer("none?field=fldint:integer", "layer", "memory") self.assertTrue(layer.isValid()) layer.dataProvider().addAttributes([QgsField('max', QVariant.String, 'string', 10), QgsField('nomax', QVariant.String, 'string', 0)]) layer.updateFields() QgsProject.instance().addMapLayer(layer) reg = QgsGui.editorWidgetRegistry() config = {'IsMultiline': 'True'} # first test for field without character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 2, config, editor, None) self.assertEqual(w.value(), 'this_is_a_long_string') # next test for field with character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 1, config, editor, None) self.assertEqual(w.value(), 'this_is_a_') QgsProject.instance().removeAllMapLayers()
class TextEditorDialog(QDialog): def __init__(self, text): super(TextEditorDialog, self).__init__() self.text = text self.resize(600, 350) self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint) self.setWindowTitle("Editor") layout = QVBoxLayout() buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.editor = QTextEdit() self.editor.setPlainText(text) layout.addWidget(self.editor) layout.addWidget(buttonBox) self.setLayout(layout) buttonBox.accepted.connect(self.okPressed) buttonBox.rejected.connect(self.cancelPressed) def okPressed(self): self.text = self.editor.toPlainText() self.accept() def cancelPressed(self): self.reject()
def widgetFromParameter(self, param): paramtype = param["type"] if paramtype == FILES: def edit(textbox): f = QFileDialog.getOpenFileNames(self, "Select file", "", "*.*") if f: textbox.value = ",".join(f) return TextBoxWithLink("Browse", edit, None, True) elif paramtype == FOLDER: def edit(textbox): f = QFileDialog.getExistingDirectory(self, "Select folder", "") if f: textbox.value = f return TextBoxWithLink("Browse", edit, None, True) elif paramtype == BOOL: check = QCheckBox(param["label"]) if param["default"]: check.setCheckState(Qt.Checked) else: check.setCheckState(Qt.Unchecked) return check elif paramtype == CHOICE: combo = QComboBox() for option in param["options"]: combo.addItem(option) idx = combo.findText(str(param["default"])) combo.setCurrentIndex(idx) return combo elif paramtype == TEXT: textEdit = QTextEdit() textEdit.setPlainText(param["default"]) return textEdit elif paramtype == VECTOR: combo = QgsMapLayerComboBox() combo.setFilters(QgsMapLayerProxyModel.VectorLayer) return combo elif paramtype == RASTER: combo = QgsMapLayerComboBox() combo.setFilters(QgsMapLayerProxyModel.RasterLayer) return combo elif paramtype == PASSWORD: lineEdit = QLineEdit() lineEdit.setEchoMode(QLineEdit.Password) return lineEdit else: lineEdit = QLineEdit() lineEdit.setText(str(param["default"])) return lineEdit
class ModelerParametersWidget(QWidget): def __init__(self, alg, model, algName=None, configuration=None, dialog=None, context=None): super().__init__() self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm self.childId = algName # The name of the algorithm in the model, in case we are editing it and not defining it for the first time self.configuration = configuration self.context = context self.dialog = dialog self.widget = ModelerParametersPanelWidget(alg, model, algName, configuration, dialog, context) class ContextGenerator(QgsProcessingContextGenerator): def __init__(self, context): super().__init__() self.processing_context = context def processingContext(self): return self.processing_context self.context_generator = ContextGenerator(self.context) self.setupUi() self.params = None def algorithm(self): return self._alg def switchToCommentTab(self): self.tab.setCurrentIndex(1) self.commentEdit.setFocus() self.commentEdit.selectAll() def setupUi(self): self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(0, 0, 0, 0) self.tab = QTabWidget() self.mainLayout.addWidget(self.tab) self.param_widget = QgsPanelWidgetStack() self.widget.setDockMode(True) self.param_widget.setMainPanel(self.widget) self.tab.addTab(self.param_widget, self.tr('Properties')) self.commentLayout = QVBoxLayout() self.commentEdit = QTextEdit() self.commentEdit.setAcceptRichText(False) self.commentLayout.addWidget(self.commentEdit, 1) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) hl.addWidget(QLabel(self.tr('Color'))) self.comment_color_button = QgsColorButton() self.comment_color_button.setAllowOpacity(True) self.comment_color_button.setWindowTitle(self.tr('Comment Color')) self.comment_color_button.setShowNull(True, self.tr('Default')) hl.addWidget(self.comment_color_button) self.commentLayout.addLayout(hl) w2 = QWidget() w2.setLayout(self.commentLayout) self.tab.addTab(w2, self.tr('Comments')) self.setLayout(self.mainLayout) def setComments(self, text): self.commentEdit.setPlainText(text) def comments(self): return self.commentEdit.toPlainText() def setCommentColor(self, color): if color.isValid(): self.comment_color_button.setColor(color) else: self.comment_color_button.setToNull() def commentColor(self): return self.comment_color_button.color() if not self.comment_color_button.isNull() else QColor() def getAvailableDependencies(self): return self.widget.getAvailableDependencies() def getDependenciesPanel(self): return self.widget.getDependenciesPanel() def getAvailableValuesOfType(self, paramType, outTypes=[], dataTypes=[]): return self.widget.getAvailableValuesOfType(paramType, outTypes, dataTypes) def resolveValueDescription(self, value): return self.widget.resolveValueDescription(value) def setPreviousValues(self): self.widget.setPreviousValues() def createAlgorithm(self): alg = self.widget.createAlgorithm() if alg: alg.comment().setDescription(self.comments()) alg.comment().setColor(self.commentColor()) return alg
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_ENUM, parameters.PARAMETER_MATRIX, parameters.PARAMETER_MAP_LAYER): return True elif isinstance(param, (QgsProcessingParameterField, QgsProcessingParameterBand, QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale, QgsProcessingParameterEnum, QgsProcessingParameterMatrix, QgsProcessingParameterMapLayer, 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 == parameters.PARAMETER_MAP_LAYER or isinstance(self.param, QgsProcessingParameterMapLayer)): 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 (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('Mesh'), QgsProcessing.TypeMesh) if self.param is not None: self.datatypeCombo.setCurrentIndex(self.datatypeCombo.findData(self.param.dataTypes()[0])) 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_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 = QgsProcessingLayerOutputDestinationWidget(self.param, defaultSelection=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, types=[self.datatypeCombo.currentData()]) 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_EXTENT or isinstance(self.param, QgsProcessingParameterExtent)): self.param = QgsProcessingParameterExtent(name, description) 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.value()) elif (isinstance(self.param, QgsProcessingParameterFileDestination)): self.param = QgsProcessingParameterFileDestination( name=name, description=self.param.description(), fileFilter=self.param.fileFilter(), defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterFolderDestination)): self.param = QgsProcessingParameterFolderDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterRasterDestination)): self.param = QgsProcessingParameterRasterDestination( name=name, description=self.param.description(), defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterVectorDestination)): self.param = QgsProcessingParameterVectorDestination( name=name, description=self.param.description(), type=self.param.dataType(), defaultValue=self.defaultWidget.value()) 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)
class ConsoleWidget(QWidget): def __init__(self, exc_info, parent=None): QWidget.__init__(self, parent) self.compiler = code.CommandCompiler() # for console self.tb = exc_info[2] self.entries = traceback.extract_tb(self.tb) self.console = QLineEdit() self.console.setPlaceholderText(">>> Python Console") self.console.returnPressed.connect(self.exec_console) self.console.setFont(QFont("Courier")) self.console_out = QTextEdit() self.console_out.setReadOnly(True) self.console_out.setFont(QFont("Courier")) self.console_out.setVisible(False) # initially hidden self.console_outs = [''] * len(self.entries) self.frame_vars = [None] * len(self.entries) l = QVBoxLayout() l.addWidget(self.console_out) l.addWidget(self.console) l.setContentsMargins(0, 0, 0, 0) self.setLayout(l) def go_to_frame(self, index): self.console_out.setPlainText(self.console_outs[index]) self.current_frame_index = index def exec_console(self): index = self.current_frame_index if index < 0: return # cache frame variables (globals and locals) # because every time we ask for frame.f_locals, a new dict instance # is created - we keep our local cache that may contain some changes if self.frame_vars[index] is None: #print "init", index frame = frame_from_traceback(self.tb, index) self.frame_vars[index] = (dict(frame.f_globals), dict(frame.f_locals)) frame_vars = self.frame_vars[index] #print frame_vars[1] line = self.console.text() try: c = self.compiler(line, "<console>", "single") except (OverflowError, SyntaxError, ValueError) as e: QMessageBox.critical(self, "Error", str(e)) return if c is None: QMessageBox.critical(self, "Error", "Code not complete") return import io io = io.StringIO() if sys.version_info.major >= 3 else io.BytesIO() try: with stdout_redirected(io): exec(c, frame_vars[0], frame_vars[1]) except: etype, value, tb = sys.exc_info() QMessageBox.critical(self, "Error", etype.__name__ + "\n" + str(value)) return stuff = self.console_outs[index] stuff += ">>> " + line + "\n" stuff += io.getvalue() self.console_outs[index] = stuff self.console_out.setPlainText(stuff) self.console_out.setVisible(True) # make sure we are at the end c = self.console_out.textCursor() c.movePosition(QTextCursor.End) self.console_out.setTextCursor(c) self.console_out.ensureCursorVisible() self.console.setText('')
class ModelerParameterDefinitionDialog(QDialog): @staticmethod def use_legacy_dialog(param=None, paramType=None): if isinstance(param, 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 isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = QgsProcessingLayerOutputDestinationWidget( self.param, defaultSelection=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): child = self.alg.childAlgorithms()[self.param.metadata() ['_modelChildId']] model_output = child.modelOutput( self.param.metadata()['_modelChildOutputName']) 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, 1) hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) hl.addWidget(QLabel(self.tr('Color'))) self.comment_color_button = QgsColorButton() self.comment_color_button.setAllowOpacity(True) self.comment_color_button.setWindowTitle(self.tr('Comment Color')) self.comment_color_button.setShowNull(True, self.tr('Default')) hl.addWidget(self.comment_color_button) self.commentLayout.addLayout(hl) 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 setCommentColor(self, color): if color.isValid(): self.comment_color_button.setColor(color) else: self.comment_color_button.setToNull() def commentColor(self): return self.comment_color_button.color( ) if not self.comment_color_button.isNull() else QColor() 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 validChars = \ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' safeName = ''.join(c for c in description if c in validChars) name = safeName.lower() # Destination parameter if (isinstance(self.param, QgsProcessingParameterFeatureSink)): self.param = QgsProcessingParameterFeatureSink( name=name, description=description, type=self.param.dataType(), defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterFileDestination)): self.param = QgsProcessingParameterFileDestination( name=name, description=description, fileFilter=self.param.fileFilter(), defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterFolderDestination)): self.param = QgsProcessingParameterFolderDestination( name=name, description=description, defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterRasterDestination)): self.param = QgsProcessingParameterRasterDestination( name=name, description=description, defaultValue=self.defaultWidget.value()) elif (isinstance(self.param, QgsProcessingParameterVectorDestination)): self.param = QgsProcessingParameterVectorDestination( name=name, description=description, type=self.param.dataType(), defaultValue=self.defaultWidget.value()) 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)
class TreeSettingItem(QTreeWidgetItem): comboStyle = '''QComboBox { border: 1px solid gray; border-radius: 3px; padding: 1px 18px 1px 3px; min-width: 6em; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 15px; border-left-width: 1px; border-left-color: darkgray; border-left-style: solid; border-top-right-radius: 3px; border-bottom-right-radius: 3px; } ''' def _addTextEdit(self, editable=True): layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.textEdit = QTextEdit() if not editable: self.textEdit.setReadOnly(True) self.textEdit.setPlainText(self._value) layout.addWidget(self.textEdit) w = QWidget() w.setLayout(layout) self.tree.setItemWidget(self, 1, w) def _addTextBoxWithLink(self, text, func, editable=True): layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.lineEdit = QLineEdit() if not editable: self.lineEdit.setReadOnly(True) self.lineEdit.setText(self._value) layout.addWidget(self.lineEdit) if text: self.linkLabel = QLabel() self.linkLabel.setText("<a href='#'> %s</a>" % text) self.linkLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) layout.addWidget(self.linkLabel) self.linkLabel.linkActivated.connect(func) w = QWidget() w.setLayout(layout) self.tree.setItemWidget(self, 1, w) def __init__(self, parent, tree, setting, namespace, value): QTreeWidgetItem.__init__(self, parent) self.parent = parent self.namespace = namespace self.tree = tree self._value = value self.setting = setting self.name = setting["name"] self.labelText = setting["label"] self.settingType = setting["type"] self.setText(0, self.labelText) if self.settingType == CRS: def edit(): selector = QgsProjectionSelectionDialog() selector.setCrs(value); if selector.exec_(): crs = selector.crs() if crs.upper().startswith("EPSG:"): self.lineEdit.setText(crs) self._addTextBoxWithLink("Edit", edit, False) elif self.settingType == FILES: def edit(): f = QFileDialog.getOpenFileNames(parent.treeWidget(), "Select file", "", "*.*") if f: self.lineEdit.setText(",".join(f)) self._addTextBoxWithLink("Browse", edit, True) elif self.settingType == FILE: def edit(): f = QFileDialog.getOpenFileName(parent.treeWidget(), "Select file", "", "*.*") if f: self.lineEdit.setText(f) self._addTextBoxWithLink("Browse", edit, True) elif self.settingType == FOLDER: def edit(): f = QFileDialog.getExistingDirectory(parent.treeWidget(), "Select folder", "") if f: self.lineEdit.setText(f) self._addTextBoxWithLink("Browse", edit, True) elif self.settingType == BOOL: if value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif self.settingType == CHOICE: self.combo = QComboBox() self.combo.setStyleSheet(self.comboStyle) for option in setting["options"]: self.combo.addItem(option) self.tree.setItemWidget(self, 1, self.combo) idx = self.combo.findText(str(value)) self.combo.setCurrentIndex(idx) elif self.settingType == TEXT: self._addTextEdit() elif self.settingType == STRING: self._addTextBoxWithLink(None, None) elif self.settingType == AUTHCFG: def edit(): currentAuthCfg = self.value() dlg = AuthConfigSelectDialog(parent.treeWidget(), authcfg=currentAuthCfg) ret = dlg.exec_() if ret: self.lineEdit.setText(dlg.authcfg) self._addTextBoxWithLink("Select", edit, True) else: self.setFlags(self.flags() | Qt.ItemIsEditable) self.setText(1, unicode(value)) def saveValue(self): value = self.value() setPluginSetting(self.name, value, self.namespace) def value(self): self.setBackgroundColor(0, Qt.white) self.setBackgroundColor(1, Qt.white) try: if self.settingType == BOOL: return self.checkState(1) == Qt.Checked elif self.settingType == NUMBER: v = float(self.text(1)) return v elif self.settingType == CHOICE: return self.combo.currentText() elif self.settingType in [TEXT]: return self.textEdit.toPlainText() elif self.settingType in [CRS, STRING, FILES, FOLDER, AUTHCFG]: return self.lineEdit.text() else: return self.text(1) except: self.setBackgroundColor(0, Qt.yellow) self.setBackgroundColor(1, Qt.yellow) raise WrongValueException() def setValue(self, value): if self.settingType == BOOL: if value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif self.settingType == CHOICE: idx = self.combo.findText(str(value)) self.combo.setCurrentIndex(idx) elif self.settingType in [TEXT, CRS, STRING, FILES, FOLDER, AUTHCFG]: self.lineEdit.setText(value) else: self.setText(1, unicode(value)) def resetDefault(self): self.setValue(self.setting["default"])
class ModelerParametersDialog(QDialog): def __init__(self, alg, model, algName=None, configuration=None): QDialog.__init__(self) self.setModal(True) self._alg = alg # The algorithm to define in this dialog. It is an instance of QgsProcessingAlgorithm self.model = model # The model this algorithm is going to be added to. It is an instance of QgsProcessingModelAlgorithm self.childId = algName # The name of the algorithm in the model, in case we are editing it and not defining it for the first time self.configuration = configuration self.context = createContext() self.widget_labels = {} class ContextGenerator(QgsProcessingContextGenerator): def __init__(self, context): super().__init__() self.processing_context = context def processingContext(self): return self.processing_context self.context_generator = ContextGenerator(self.context) self.setupUi() self.params = None settings = QgsSettings() self.restoreGeometry(settings.value("/Processing/modelParametersDialogGeometry", QByteArray())) def closeEvent(self, event): settings = QgsSettings() settings.setValue("/Processing/modelParametersDialogGeometry", self.saveGeometry()) super(ModelerParametersDialog, self).closeEvent(event) def switchToCommentTab(self): self.tab.setCurrentIndex(1) self.commentEdit.setFocus() self.commentEdit.selectAll() def setupUi(self): self.checkBoxes = {} self.showAdvanced = False self.wrappers = {} self.valueItems = {} self.dependentItems = {} self.algorithmItem = None self.resize(650, 450) self.mainLayout = QVBoxLayout() self.tab = QTabWidget() self.mainLayout.addWidget(self.tab) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.Help) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(5) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.verticalLayout.addWidget(self.bar) hLayout = QHBoxLayout() hLayout.setSpacing(5) hLayout.setMargin(0) descriptionLabel = QLabel(self.tr("Description")) self.descriptionBox = QLineEdit() self.descriptionBox.setText(self._alg.displayName()) hLayout.addWidget(descriptionLabel) hLayout.addWidget(self.descriptionBox) self.verticalLayout.addLayout(hLayout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.verticalLayout.addWidget(line) widget_context = QgsProcessingParameterWidgetContext() widget_context.setProject(QgsProject.instance()) if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) widget_context.setModel(self.model) widget_context.setModelChildAlgorithmId(self.childId) self.algorithmItem = QgsGui.instance().processingGuiRegistry().algorithmConfigurationWidget(self._alg) if self.algorithmItem: self.algorithmItem.setWidgetContext(widget_context) self.algorithmItem.registerProcessingContextGenerator(self.context_generator) if self.configuration: self.algorithmItem.setConfiguration(self.configuration) self.verticalLayout.addWidget(self.algorithmItem) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.advancedButton = QPushButton() self.advancedButton.setText(self.tr('Show advanced parameters')) self.advancedButton.clicked.connect( self.showAdvancedParametersClicked) advancedButtonHLayout = QHBoxLayout() advancedButtonHLayout.addWidget(self.advancedButton) advancedButtonHLayout.addStretch() self.verticalLayout.addLayout(advancedButtonHLayout) break for param in self._alg.parameterDefinitions(): if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue wrapper = WidgetWrapperFactory.create_wrapper(param, self) self.wrappers[param.name()] = wrapper wrapper.setWidgetContext(widget_context) wrapper.registerProcessingContextGenerator(self.context_generator) if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): widget = wrapper else: widget = wrapper.widget if widget is not None: self.valueItems[param.name()] = widget if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): label = wrapper.createLabel() else: tooltip = param.description() widget.setToolTip(tooltip) label = wrapper.label self.widget_labels[param.name()] = label if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: label.setVisible(self.showAdvanced) widget.setVisible(self.showAdvanced) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(widget) for dest in self._alg.destinationParameterDefinitions(): if dest.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if isinstance(dest, (QgsProcessingParameterRasterDestination, QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterFileDestination, QgsProcessingParameterFolderDestination)): label = QLabel(dest.description()) item = QgsFilterLineEdit() if hasattr(item, 'setPlaceholderText'): item.setPlaceholderText(self.tr('[Enter name if this is a final result]')) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(item) self.valueItems[dest.name()] = item label = QLabel(' ') self.verticalLayout.addWidget(label) label = QLabel(self.tr('Parent algorithms')) self.dependenciesPanel = self.getDependenciesPanel() self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(self.dependenciesPanel) self.verticalLayout.addStretch(1000) self.setPreviousValues() self.setWindowTitle(self._alg.displayName()) self.verticalLayout2 = QVBoxLayout() self.verticalLayout2.setSpacing(2) self.verticalLayout2.setMargin(0) self.paramPanel = QWidget() self.paramPanel.setLayout(self.verticalLayout) self.scrollArea = QgsScrollArea() self.scrollArea.setWidget(self.paramPanel) self.scrollArea.setWidgetResizable(True) self.verticalLayout2.addWidget(self.scrollArea) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.buttonBox.helpRequested.connect(self.openHelp) w = QWidget() w.setLayout(self.verticalLayout2) 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.mainLayout.addWidget(self.buttonBox) self.setLayout(self.mainLayout) QMetaObject.connectSlotsByName(self) def setComments(self, text): self.commentEdit.setPlainText(text) def comments(self): return self.commentEdit.toPlainText() def getAvailableDependencies(self): # spellok if self.childId is None: dependent = [] else: dependent = list(self.model.dependentChildAlgorithms(self.childId)) dependent.append(self.childId) opts = [] for alg in list(self.model.childAlgorithms().values()): if alg.childId() not in dependent: opts.append(alg) return opts def getDependenciesPanel(self): return MultipleInputPanel([alg.description() for alg in self.getAvailableDependencies()]) # spellok def showAdvancedParametersClicked(self): self.showAdvanced = not self.showAdvanced if self.showAdvanced: self.advancedButton.setText(self.tr('Hide advanced parameters')) else: self.advancedButton.setText(self.tr('Show advanced parameters')) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: wrapper = self.wrappers[param.name()] if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): wrapper.setVisible(self.showAdvanced) else: wrapper.widget.setVisible(self.showAdvanced) self.widget_labels[param.name()].setVisible(self.showAdvanced) def getAvailableValuesOfType(self, paramType, outTypes=[], dataTypes=[]): # upgrade paramType to list if paramType is None: paramType = [] elif not isinstance(paramType, (tuple, list)): paramType = [paramType] if outTypes is None: outTypes = [] elif not isinstance(outTypes, (tuple, list)): outTypes = [outTypes] return self.model.availableSourcesForChild(self.childId, [p.typeName() for p in paramType if issubclass(p, QgsProcessingParameterDefinition)], [o.typeName() for o in outTypes if issubclass(o, QgsProcessingOutputDefinition)], dataTypes) def resolveValueDescription(self, value): if isinstance(value, QgsProcessingModelChildParameterSource): if value.source() == QgsProcessingModelChildParameterSource.StaticValue: return value.staticValue() elif value.source() == QgsProcessingModelChildParameterSource.ModelParameter: return self.model.parameterDefinition(value.parameterName()).description() elif value.source() == QgsProcessingModelChildParameterSource.ChildOutput: alg = self.model.childAlgorithm(value.outputChildId()) output_name = alg.algorithm().outputDefinition(value.outputName()).description() # see if this output has been named by the model designer -- if so, we use that friendly name for name, output in alg.modelOutputs().items(): if output.childOutputName() == value.outputName(): output_name = name break return self.tr("'{0}' from algorithm '{1}'").format(output_name, alg.description()) return value def setPreviousValues(self): if self.childId is not None: alg = self.model.childAlgorithm(self.childId) self.descriptionBox.setText(alg.description()) for param in alg.algorithm().parameterDefinitions(): if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue value = None if param.name() in alg.parameterSources(): value = alg.parameterSources()[param.name()] if isinstance(value, list) and len(value) == 1: value = value[0] elif isinstance(value, list) and len(value) == 0: value = None wrapper = self.wrappers[param.name()] if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): if value is None: value = QgsProcessingModelChildParameterSource.fromStaticValue(param.defaultValue()) wrapper.setWidgetValue(value) else: if value is None: value = param.defaultValue() if isinstance(value, QgsProcessingModelChildParameterSource) and value.source() == QgsProcessingModelChildParameterSource.StaticValue: value = value.staticValue() wrapper.setValue(value) for name, out in alg.modelOutputs().items(): if out.childOutputName() in self.valueItems: self.valueItems[out.childOutputName()].setText(out.name()) selected = [] dependencies = self.getAvailableDependencies() # spellok for idx, dependency in enumerate(dependencies): if dependency.childId() in alg.dependencies(): selected.append(idx) self.dependenciesPanel.setSelectedItems(selected) def createAlgorithm(self): alg = QgsProcessingModelChildAlgorithm(self._alg.id()) if not self.childId: alg.generateChildId(self.model) else: alg.setChildId(self.childId) alg.setDescription(self.descriptionBox.text()) if self.algorithmItem: alg.setConfiguration(self.algorithmItem.configuration()) self._alg = alg.algorithm().create(self.algorithmItem.configuration()) for param in self._alg.parameterDefinitions(): if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue try: wrapper = self.wrappers[param.name()] if issubclass(wrapper.__class__, WidgetWrapper): val = wrapper.value() elif issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): val = wrapper.value() else: val = wrapper.parameterValue() except InvalidParameterValue: self.bar.pushMessage(self.tr("Error"), self.tr("Wrong or missing value for parameter '{}'").format(param.description()), level=Qgis.Warning) return None if isinstance(val, QgsProcessingModelChildParameterSource): val = [val] elif not (isinstance(val, list) and all( [isinstance(subval, QgsProcessingModelChildParameterSource) for subval in val])): val = [QgsProcessingModelChildParameterSource.fromStaticValue(val)] for subval in val: if (isinstance(subval, QgsProcessingModelChildParameterSource) and subval.source() == QgsProcessingModelChildParameterSource.StaticValue and not param.checkValueIsAcceptable(subval.staticValue())) \ or (subval is None and not param.flags() & QgsProcessingParameterDefinition.FlagOptional): self.bar.pushMessage(self.tr("Error"), self.tr("Wrong or missing value for parameter '{}'").format( param.description()), level=Qgis.Warning) return None alg.addParameterSources(param.name(), val) outputs = {} for dest in self._alg.destinationParameterDefinitions(): if not dest.flags() & QgsProcessingParameterDefinition.FlagHidden: name = self.valueItems[dest.name()].text() if name.strip() != '': output = QgsProcessingModelOutput(name, name) output.setChildId(alg.childId()) output.setChildOutputName(dest.name()) outputs[name] = output if dest.flags() & QgsProcessingParameterDefinition.FlagIsModelOutput: if dest.name() not in outputs: output = QgsProcessingModelOutput(dest.name(), dest.name()) output.setChildId(alg.childId()) output.setChildOutputName(dest.name()) outputs[dest.name()] = output alg.setModelOutputs(outputs) selectedOptions = self.dependenciesPanel.selectedoptions availableDependencies = self.getAvailableDependencies() # spellok dep_ids = [] for selected in selectedOptions: dep_ids.append(availableDependencies[selected].childId()) # spellok alg.setDependencies(dep_ids) #try: # self._alg.processBeforeAddingToModeler(alg, self.model) #except: # pass alg.comment().setDescription(self.comments()) return alg def okPressed(self): alg = self.createAlgorithm() if alg is not None: self.accept() def cancelPressed(self): self.reject() def openHelp(self): algHelp = self._alg.helpUrl() if not algHelp: algHelp = QgsHelp.helpUrl("processing_algs/{}/{}.html#{}".format( self._alg.provider().helpId(), self._alg.groupId(), "{}{}".format(self._alg.provider().helpId(), self._alg.name()))).toString() if algHelp not in [None, ""]: webbrowser.open(algHelp)
class CodeValueWidget(QWidget): """Widget for specifying barcode or QR code values.""" value_changed = pyqtSignal(str) def __init__(self, item_widget): super().__init__(item_widget) self._item_widget = item_widget self._value_text_edit = QTextEdit() self._value_text_edit.setLineWrapMode(QTextEdit.WidgetWidth) self._value_text_edit.textChanged.connect(self._on_code_value_changed) self._exp_btn = QPushButton(self.tr('Insert expression...')) self._exp_btn.setIcon( QgsApplication.getThemeIcon('/mIconExpression.svg')) self._exp_btn.clicked.connect(self._on_insert_expression) layout = QVBoxLayout() layout.addWidget(self._value_text_edit) layout.addWidget(self._exp_btn) self.setLayout(layout) @property def value_text_edit(self): """ :return: Returns text edit widget for entering code values. :rtype: QPlainTextEdit """ return self._value_text_edit @property def code_value(self): """ :return: Returns the value in the text widget. :rtype: str """ return self._value_text_edit.toPlainText() @code_value.setter def code_value(self, val): """ Sets the text widget to the given value. :param val: Value to set in the text widget. :type val: str """ if self.code_value == val: return self._value_text_edit.setPlainText(val) def highlight_invalid_data(self, invalid): """ Highlights barcode data in red to indicate invalidity. :param invalid: True to highlight in red, else False to restore default color. :type invalid: bool """ if invalid: stylesheet = 'color:#ff0000; font-weight: bold;' else: stylesheet = '' self._value_text_edit.setStyleSheet(stylesheet) def _on_code_value_changed(self): # Slot raised when the code value changes. code_txt = self.code_value self.value_changed.emit(code_txt) def _on_insert_expression(self): # Slot raised to insert an expression. if not isinstance(self._item_widget, QgsLayoutItemBaseWidget): return qrcode_item = self._item_widget.layoutObject() if not qrcode_item: return sel_txt = self._value_text_edit.textCursor().selectedText() # Edit expression text if specified if sel_txt.startswith('[%') and sel_txt.endswith('%]'): sel_txt = sel_txt.lstrip('[%') sel_txt = sel_txt.rstrip('%]') cov_layer = self._item_widget.coverageLayer() exp_ctx = qrcode_item.createExpressionContext() exp_dlg = QgsExpressionBuilderDialog(cov_layer, sel_txt, self, 'generic', exp_ctx) exp_dlg.setWindowTitle(self.tr('Insert Expression for Barcode Data')) exp_dlg.setAllowEvalErrors(False) if exp_dlg.exec_() == QDialog.Accepted: exp = exp_dlg.expressionText() if exp: self._value_text_edit.setPlainText('[%{0}%]'.format(exp)) def block_value_widget_signals(self, status): """ Set True to block all signals emitted by the code value widget, else False to restore. :param status: True to block signals, False to restore. :type status: bool """ self._value_text_edit.blockSignals(status)