def testNulling(self): """ Test clearing colors to null """ # start with a valid color button = QgsColorButton() button.setAllowOpacity(True) button.setColor(QColor(255, 100, 200, 255)) self.assertEqual(button.color(), QColor(255, 100, 200, 255)) spy_changed = QSignalSpy(button.colorChanged) spy_cleared = QSignalSpy(button.cleared) button.setColor(QColor(50, 100, 200, 255)) self.assertEqual(button.color(), QColor(50, 100, 200, 255)) self.assertEqual(len(spy_changed), 1) self.assertEqual(len(spy_cleared), 0) # now set to null button.setToNull() self.assertEqual(button.color(), QColor()) self.assertEqual(len(spy_changed), 2) self.assertEqual(len(spy_cleared), 1) button.setToNull() self.assertEqual(button.color(), QColor()) # should not be refired, the color wasn't changed self.assertEqual(len(spy_changed), 2) # SHOULD be refired self.assertEqual(len(spy_cleared), 2)
def testClearingColors(self): """ Test setting colors to transparent """ # start with a valid color button = QgsColorButton() button.setAllowOpacity(True) button.setColor(QColor(255, 100, 200, 255)) self.assertEqual(button.color(), QColor(255, 100, 200, 255)) # now set to no color button.setToNoColor() # ensure that only the alpha channel has changed - not the other color components self.assertEqual(button.color(), QColor(255, 100, 200, 0))
def testClearingColors(self): """ Test setting colors to transparent """ # start with a valid color button = QgsColorButton() button.setAllowOpacity(True) button.setColor(QColor(255, 100, 200, 255)) self.assertEqual(button.color(), QColor(255, 100, 200, 255)) # now set to no color button.setToNoColor() # ensure that only the alpha channel has changed - not the other color components self.assertEqual(button.color(), QColor(255, 100, 200, 0))
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 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 QrCodeLayoutItemWidget(QgsLayoutItemBaseWidget): # pylint: disable=too-few-public-methods """Widget for configuring a QrCodeLayoutItem.""" def __init__(self, parent, layout_object): super().__init__(parent, layout_object) self._qrcode_item = layout_object self.message_bar = None self.setPanelTitle(self.tr('QR Code Properties')) self._init_widgets(layout_object) self._update_gui_values() def _init_widgets(self, layout_object): """Initialize widgets""" lbl_title = QLabel() lbl_title.setStyleSheet( 'padding: 2px; font-weight: bold; background-color: ' 'rgb(200, 200, 200);') lbl_title.setText(self.tr('QR Code')) self._cd_value_widget = CodeValueWidget(self) self._cd_value_widget.value_changed.connect( self._on_code_value_changed) value_groupbox = QgsCollapsibleGroupBoxBasic(self.tr('Data')) gp_layout = QVBoxLayout() gp_layout.setContentsMargins(0, 0, 0, 0) gp_layout.addWidget(self._cd_value_widget) value_groupbox.setLayout(gp_layout) # Item appearance appearance_groupbox = QgsCollapsibleGroupBoxBasic( self.tr('Appearance')) appearance_layout = QGridLayout() # Data color lbl_data_clr = QLabel(self.tr('Data color')) self._data_clr_btn = QgsColorButton() self._data_clr_btn.setColorDialogTitle(self.tr('Select Data Color')) self._data_clr_btn.setContext('composer') self._data_clr_btn.setAllowOpacity(False) self._data_clr_btn.colorChanged.connect(self.on_data_color_changed) appearance_layout.addWidget(lbl_data_clr, 0, 0) appearance_layout.addWidget(self._data_clr_btn, 0, 1) appearance_layout.setColumnStretch(2, 1) # Background color lbl_background_clr = QLabel(self.tr('Background color')) self._background_clr_btn = QgsColorButton() self._background_clr_btn.setColorDialogTitle( self.tr('Select Background Color')) self._background_clr_btn.setContext('composer') self._background_clr_btn.setAllowOpacity(False) self._background_clr_btn.colorChanged.connect( self.on_background_color_changed) appearance_layout.addWidget(lbl_background_clr, 1, 0) appearance_layout.addWidget(self._background_clr_btn, 1, 1) appearance_groupbox.setLayout(appearance_layout) # Properties widget self._prop_widget = QgsLayoutItemPropertiesWidget(self, layout_object) self._prop_widget.showBackgroundGroup(False) # Add widgets to layout layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(lbl_title) layout.addWidget(value_groupbox) layout.addWidget(appearance_groupbox) layout.addWidget(self._prop_widget) # Set layout self.setLayout(layout) def _on_code_value_changed(self, txt): # Slot raised when the code value changes. self._qrcode_item.beginCommand(self.tr('Change code value'), QgsLayoutItem.UndoLabelText) self._qrcode_item.blockSignals(True) self._qrcode_item.code_value = txt self._qrcode_item.blockSignals(False) self._qrcode_item.endCommand() def setNewItem(self, item): """ Set widget properties to sync with item properties. """ if item.type() != QR_CODE_TYPE: return False self._qrcode_item = item self._prop_widget.setItem(self._qrcode_item) self._update_gui_values() return True def _update_gui_values(self): # Updates values of widgets based on item properties. self._cd_value_widget.block_value_widget_signals(True) self._cd_value_widget.code_value = self._qrcode_item.code_value self._cd_value_widget.value_text_edit.moveCursor( QTextCursor.End, QTextCursor.MoveAnchor) self._cd_value_widget.block_value_widget_signals(False) self._data_clr_btn.blockSignals(True) self._data_clr_btn.setColor( color_from_name(self._qrcode_item.data_color, '#000000')) self._data_clr_btn.blockSignals(False) self._background_clr_btn.blockSignals(True) self._background_clr_btn.setColor( color_from_name(self._qrcode_item.bg_color, '#FFFFFF')) self._background_clr_btn.blockSignals(False) def setDesignerInterface(self, iface): """ Use iface to set the message_bar. """ super().setDesignerInterface(iface) self.message_bar = iface.messageBar() def on_data_color_changed(self, color): """ Slot raised when new data color is set. """ self._qrcode_item.beginCommand(self.tr('Change data color'), QgsLayoutItem.UndoPictureFillColor) self._qrcode_item.blockSignals(True) self._qrcode_item.data_color = color.name() self._qrcode_item.blockSignals(False) self._qrcode_item.endCommand() def on_background_color_changed(self, color): """ Slot raised when new background color is set. """ self._qrcode_item.beginCommand(self.tr('Change background color'), QgsLayoutItem.UndoPictureFillColor) self._qrcode_item.blockSignals(True) self._qrcode_item.bg_color = color.name() self._qrcode_item.blockSignals(False) self._qrcode_item.endCommand()
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_MAP_LAYER): return True elif isinstance( param, (QgsProcessingParameterField, QgsProcessingParameterBand, QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale, 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 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, 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 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 # 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)