mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-11-04 00:04:25 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			376 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			376 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# -*- coding: utf-8 -*-
 | 
						|
 | 
						|
"""
 | 
						|
***************************************************************************
 | 
						|
    ModelerParametersDialog.py
 | 
						|
    ---------------------
 | 
						|
    Date                 : August 2012
 | 
						|
    Copyright            : (C) 2012 by Victor Olaya
 | 
						|
    Email                : volayaf at gmail dot com
 | 
						|
***************************************************************************
 | 
						|
*                                                                         *
 | 
						|
*   This program is free software; you can redistribute it and/or modify  *
 | 
						|
*   it under the terms of the GNU General Public License as published by  *
 | 
						|
*   the Free Software Foundation; either version 2 of the License, or     *
 | 
						|
*   (at your option) any later version.                                   *
 | 
						|
*                                                                         *
 | 
						|
***************************************************************************
 | 
						|
"""
 | 
						|
 | 
						|
__author__ = 'Victor Olaya'
 | 
						|
__date__ = 'August 2012'
 | 
						|
__copyright__ = '(C) 2012, Victor Olaya'
 | 
						|
 | 
						|
# This will get replaced with a git SHA1 when you do a git archive
 | 
						|
 | 
						|
__revision__ = '$Format:%H$'
 | 
						|
 | 
						|
import webbrowser
 | 
						|
 | 
						|
from qgis.PyQt.QtCore import (Qt,
 | 
						|
                              QUrl,
 | 
						|
                              QMetaObject,
 | 
						|
                              QByteArray)
 | 
						|
from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit,
 | 
						|
                                 QFrame, QPushButton, QSizePolicy, QVBoxLayout,
 | 
						|
                                 QHBoxLayout, QWidget)
 | 
						|
 | 
						|
from qgis.core import (Qgis,
 | 
						|
                       QgsApplication,
 | 
						|
                       QgsProcessingParameterDefinition,
 | 
						|
                       QgsProcessingParameterPoint,
 | 
						|
                       QgsProcessingParameterExtent,
 | 
						|
                       QgsProcessingModelAlgorithm,
 | 
						|
                       QgsProcessingModelOutput,
 | 
						|
                       QgsProcessingModelChildAlgorithm,
 | 
						|
                       QgsProcessingModelChildParameterSource,
 | 
						|
                       QgsProcessingParameterFeatureSink,
 | 
						|
                       QgsProcessingParameterMultipleLayers,
 | 
						|
                       QgsProcessingParameterRasterDestination,
 | 
						|
                       QgsProcessingParameterFileDestination,
 | 
						|
                       QgsProcessingParameterFolderDestination,
 | 
						|
                       QgsProcessingParameterVectorDestination,
 | 
						|
                       QgsProcessingOutputDefinition,
 | 
						|
                       QgsSettings)
 | 
						|
 | 
						|
from qgis.gui import (QgsGui,
 | 
						|
                      QgsMessageBar,
 | 
						|
                      QgsScrollArea,
 | 
						|
                      QgsFilterLineEdit,
 | 
						|
                      QgsHelp)
 | 
						|
 | 
						|
from processing.gui.wrappers import WidgetWrapperFactory
 | 
						|
from processing.gui.wrappers import InvalidParameterValue
 | 
						|
from processing.gui.MultipleInputPanel import MultipleInputPanel
 | 
						|
 | 
						|
 | 
						|
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.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 setupUi(self):
 | 
						|
        self.checkBoxes = {}
 | 
						|
        self.showAdvanced = False
 | 
						|
        self.wrappers = {}
 | 
						|
        self.valueItems = {}
 | 
						|
        self.dependentItems = {}
 | 
						|
        self.algorithmItem = None
 | 
						|
 | 
						|
        self.resize(650, 450)
 | 
						|
        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.verticalLayout.setMargin(20)
 | 
						|
 | 
						|
        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)
 | 
						|
        self.algorithmItem = QgsGui.instance().processingGuiRegistry().algorithmConfigurationWidget(self._alg)
 | 
						|
        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
 | 
						|
 | 
						|
            widget = wrapper.widget
 | 
						|
            if widget is not None:
 | 
						|
                self.valueItems[param.name()] = widget
 | 
						|
                tooltip = param.description()
 | 
						|
                widget.setToolTip(tooltip)
 | 
						|
                if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
 | 
						|
                    wrapper.label.setVisible(self.showAdvanced)
 | 
						|
                    widget.setVisible(self.showAdvanced)
 | 
						|
                self.verticalLayout.addWidget(wrapper.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.verticalLayout2.addWidget(self.buttonBox)
 | 
						|
        self.setLayout(self.verticalLayout2)
 | 
						|
        self.buttonBox.accepted.connect(self.okPressed)
 | 
						|
        self.buttonBox.rejected.connect(self.cancelPressed)
 | 
						|
        self.buttonBox.helpRequested.connect(self.openHelp)
 | 
						|
        QMetaObject.connectSlotsByName(self)
 | 
						|
 | 
						|
        for wrapper in list(self.wrappers.values()):
 | 
						|
            wrapper.postInitialize(list(self.wrappers.values()))
 | 
						|
 | 
						|
    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:
 | 
						|
                self.wrappers[param.name()].widget.setVisible(self.showAdvanced)
 | 
						|
                self.wrappers[param.name()].label.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())
 | 
						|
                return self.tr("'{0}' from algorithm '{1}'").format(
 | 
						|
                    alg.algorithm().outputDefinition(value.outputName()).description(), 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
 | 
						|
                if value is None:
 | 
						|
                    value = param.defaultValue()
 | 
						|
 | 
						|
                if isinstance(value,
 | 
						|
                              QgsProcessingModelChildParameterSource) and value.source() == QgsProcessingModelChildParameterSource.StaticValue:
 | 
						|
                    value = value.staticValue()
 | 
						|
 | 
						|
                self.wrappers[param.name()].setValue(value)
 | 
						|
            for name, out in list(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:
 | 
						|
                val = self.wrappers[param.name()].value()
 | 
						|
            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
 | 
						|
 | 
						|
        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)
 |