QGIS/python/plugins/processing/modeler/ModelerParametersDialog.py

372 lines
17 KiB
Python
Raw Normal View History

2012-10-04 19:33:47 +02:00
# -*- 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. *
* *
***************************************************************************
"""
2012-10-04 19:33:47 +02:00
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
2012-10-04 19:33:47 +02:00
# This will get replaced with a git SHA1 when you do a git archive
2012-10-04 19:33:47 +02:00
__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)
2017-06-13 15:51:40 +10:00
from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterPoint,
2017-06-13 16:05:59 +10:00
QgsProcessingParameterExtent,
2017-06-20 20:40:19 +10:00
QgsProcessingModelAlgorithm,
QgsProcessingModelOutput,
QgsProcessingModelChildAlgorithm,
QgsProcessingModelChildParameterSource,
2017-06-20 20:40:19 +10:00
QgsProcessingParameterFeatureSink,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterFileDestination,
QgsProcessingParameterFolderDestination,
QgsProcessingOutputDefinition,
QgsSettings)
from qgis.gui import (QgsMessageBar,
2017-07-08 15:58:56 +10:00
QgsScrollArea,
QgsFilterLineEdit,
QgsHelp)
2017-05-16 16:36:00 +10:00
from processing.gui.wrappers import WidgetWrapperFactory
from processing.gui.wrappers import InvalidParameterValue
from processing.gui.MultipleInputPanel import MultipleInputPanel
class ModelerParametersDialog(QDialog):
ENTER_NAME = '[Enter name if this is a final result]'
NOT_SELECTED = '[Not selected]'
USE_MIN_COVERING_EXTENT = '[Use min covering extent]'
2012-09-15 18:25:25 +03:00
def __init__(self, alg, model, algName=None):
QDialog.__init__(self)
2012-09-15 18:25:25 +03:00
self.setModal(True)
# The algorithm to define in this dialog. It is an instance of QgsProcessingModelAlgorithm
self._alg = alg
# The model this algorithm is going to be added to
2012-09-15 18:25:25 +03:00
self.model = model
# The name of the algorithm in the model, in case we are editing it and not defining it for the first time
2017-07-03 19:42:29 +10:00
self.childId = algName
2012-09-15 18:25:25 +03:00
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)
2012-09-15 18:25:25 +03:00
def setupUi(self):
self.labels = {}
self.widgets = {}
self.checkBoxes = {}
self.showAdvanced = False
self.wrappers = {}
2012-09-15 18:25:25 +03:00
self.valueItems = {}
self.dependentItems = {}
self.resize(650, 450)
self.buttonBox = QDialogButtonBox()
self.buttonBox.setOrientation(Qt.Horizontal)
2017-06-13 15:51:40 +10:00
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)
2014-07-02 07:46:03 +02:00
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)
2014-07-02 07:46:03 +02:00
2017-06-13 15:51:40 +10:00
for param in self._alg.parameterDefinitions():
2017-05-16 16:36:00 +10:00
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
2017-05-16 16:36:00 +10:00
for param in self._alg.parameterDefinitions():
2017-06-13 15:51:40 +10:00
if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
2017-05-16 16:36:00 +10:00
desc = param.description()
2017-06-13 15:51:40 +10:00
if isinstance(param, QgsProcessingParameterExtent):
desc += self.tr('(xmin, xmax, ymin, ymax)')
2017-06-13 15:51:40 +10:00
if isinstance(param, QgsProcessingParameterPoint):
desc += self.tr('(x, y)')
2017-05-16 16:36:00 +10:00
if param.flags() & QgsProcessingParameterDefinition.FlagOptional:
desc += self.tr(' [optional]')
label = QLabel(desc)
2017-05-16 16:36:00 +10:00
self.labels[param.name()] = label
2017-05-16 16:36:00 +10:00
wrapper = WidgetWrapperFactory.create_wrapper(param, self)
self.wrappers[param.name()] = wrapper
widget = wrapper.widget
if widget is not None:
2017-05-16 16:36:00 +10:00
self.valueItems[param.name()] = widget
tooltip = param.description()
label.setToolTip(tooltip)
widget.setToolTip(tooltip)
2017-05-16 16:36:00 +10:00
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
label.setVisible(self.showAdvanced)
widget.setVisible(self.showAdvanced)
2017-05-16 16:36:00 +10:00
self.widgets[param.name()] = widget
2016-11-25 09:27:50 +02:00
self.verticalLayout.addWidget(label)
self.verticalLayout.addWidget(widget)
2017-06-20 20:40:19 +10:00
for dest in self._alg.destinationParameterDefinitions():
if dest.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if isinstance(dest, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink,
QgsProcessingParameterFileDestination, QgsProcessingParameterFolderDestination)):
2017-06-20 20:40:19 +10:00
label = QLabel(dest.description())
2017-07-08 15:58:56 +10:00
item = QgsFilterLineEdit()
2017-06-20 20:40:19 +10:00
if hasattr(item, 'setPlaceholderText'):
item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
self.verticalLayout.addWidget(label)
self.verticalLayout.addWidget(item)
self.valueItems[dest.name()] = item
2013-02-07 01:09:39 +01:00
label = QLabel(' ')
2013-02-03 10:26:43 +01:00
self.verticalLayout.addWidget(label)
label = QLabel(self.tr('Parent algorithms'))
2013-02-07 01:09:39 +01:00
self.dependenciesPanel = self.getDependenciesPanel()
2013-02-03 10:26:43 +01:00
self.verticalLayout.addWidget(label)
self.verticalLayout.addWidget(self.dependenciesPanel)
self.verticalLayout.addStretch(1000)
2012-09-15 18:25:25 +03:00
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)
2014-04-19 22:04:24 +02:00
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)
2012-09-15 18:25:25 +03:00
2016-09-27 19:51:06 +02:00
for wrapper in list(self.wrappers.values()):
wrapper.postInitialize(list(self.wrappers.values()))
2016-09-18 12:56:24 +02:00
2017-01-23 09:24:31 +10:00
def getAvailableDependencies(self): # spellok
2017-07-03 19:42:29 +10:00
if self.childId is None:
2013-02-03 10:26:43 +01:00
dependent = []
else:
2017-07-03 19:42:29 +10:00
dependent = list(self.model.dependentChildAlgorithms(self.childId))
dependent.append(self.childId)
2013-02-07 01:09:39 +01:00
opts = []
2017-06-13 16:05:59 +10:00
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
opts.append(alg)
2013-02-03 10:26:43 +01:00
return opts
def getDependenciesPanel(self):
2017-06-20 19:23:21 +10:00
return MultipleInputPanel([alg.description() for alg in self.getAvailableDependencies()]) # spellok
2013-02-07 01:09:39 +01:00
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'))
2017-06-13 15:51:40 +10:00
for param in self._alg.parameterDefinitions():
2017-05-16 16:36:00 +10:00
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
2017-06-13 15:51:40 +10:00
self.labels[param.name()].setVisible(self.showAdvanced)
self.widgets[param.name()].setVisible(self.showAdvanced)
2012-12-10 00:12:07 +01:00
2017-07-03 19:42:29 +10:00
def getAvailableValuesOfType(self, paramType, outTypes=[], dataTypes=[]):
# upgrade paramType to list
2017-06-13 15:51:40 +10:00
if paramType is None:
paramType = []
elif not isinstance(paramType, (tuple, list)):
paramType = [paramType]
2017-06-13 15:51:40 +10:00
if outTypes is None:
outTypes = []
elif not isinstance(outTypes, (tuple, list)):
2017-06-13 15:51:40 +10:00
outTypes = [outTypes]
2017-08-23 00:38:28 +10:00
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)
2014-07-02 07:46:03 +02:00
def resolveValueDescription(self, value):
if isinstance(value, QgsProcessingModelChildParameterSource):
if value.source() == QgsProcessingModelChildParameterSource.StaticValue:
2017-06-13 16:05:59 +10:00
return value.staticValue()
elif value.source() == QgsProcessingModelChildParameterSource.ModelParameter:
2017-06-13 16:05:59 +10:00
return self.model.parameterDefinition(value.parameterName()).description()
elif value.source() == QgsProcessingModelChildParameterSource.ChildOutput:
2017-06-13 16:05:59 +10:00
alg = self.model.childAlgorithm(value.outputChildId())
2017-06-15 20:28:39 +10:00
return self.tr("'{0}' from algorithm '{1}'").format(
alg.algorithm().outputDefinition(value.outputName()).description(), alg.description())
2017-06-13 16:05:59 +10:00
return value
2012-09-15 18:25:25 +03:00
2014-07-02 07:46:03 +02:00
def setPreviousValues(self):
2017-07-03 19:42:29 +10:00
if self.childId is not None:
alg = self.model.childAlgorithm(self.childId)
2017-06-13 16:05:59 +10:00
self.descriptionBox.setText(alg.description())
for param in alg.algorithm().parameterDefinitions():
2017-06-13 15:51:40 +10:00
if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
value = None
2017-06-13 16:05:59 +10:00
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:
2017-05-16 16:36:00 +10:00
value = param.defaultValue()
2017-06-20 19:23:21 +10:00
2017-08-23 00:38:28 +10:00
if isinstance(value,
QgsProcessingModelChildParameterSource) and value.source() == QgsProcessingModelChildParameterSource.StaticValue:
2017-06-20 19:23:21 +10:00
value = value.staticValue()
2017-05-16 16:36:00 +10:00
self.wrappers[param.name()].setValue(value)
2017-06-13 16:05:59 +10:00
for name, out in list(alg.modelOutputs().items()):
if out.childOutputName() in self.valueItems:
self.valueItems[out.childOutputName()].setText(out.name())
2013-02-07 01:09:39 +01:00
2013-02-03 10:26:43 +01:00
selected = []
2017-01-23 09:24:31 +10:00
dependencies = self.getAvailableDependencies() # spellok
for idx, dependency in enumerate(dependencies):
2017-06-13 16:05:59 +10:00
if dependency.childId() in alg.dependencies():
selected.append(idx)
2013-02-07 01:09:39 +01:00
2013-02-03 10:26:43 +01:00
self.dependenciesPanel.setSelectedItems(selected)
2012-09-15 18:25:25 +03:00
def createAlgorithm(self):
alg = QgsProcessingModelChildAlgorithm(self._alg.id())
2017-07-03 19:42:29 +10:00
if not self.childId:
2017-06-20 20:40:19 +10:00
alg.generateChildId(self.model)
else:
2017-07-03 19:42:29 +10:00
alg.setChildId(self.childId)
2017-06-13 16:05:59 +10:00
alg.setDescription(self.descriptionBox.text())
2017-06-13 15:51:40 +10:00
for param in self._alg.parameterDefinitions():
if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden:
2012-09-15 18:25:25 +03:00
continue
try:
val = self.wrappers[param.name()].value()
except InvalidParameterValue:
2017-08-23 00:38:28 +10:00
self.bar.pushMessage(self.tr("Error"),
self.tr("Wrong or missing value for parameter '{}'").format(param.description()),
level=QgsMessageBar.WARNING)
return None
if isinstance(val, QgsProcessingModelChildParameterSource):
val = [val]
2017-08-23 00:38:28 +10:00
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
2017-08-23 00:38:28 +10:00
not param.checkValueIsAcceptable(subval.staticValue())) \
or (subval is None and not param.flags() & QgsProcessingParameterDefinition.FlagOptional):
2017-08-23 00:38:28 +10:00
self.bar.pushMessage(self.tr("Error"), self.tr("Wrong or missing value for parameter '{}'").format(
param.description()),
level=QgsMessageBar.WARNING)
return None
alg.addParameterSources(param.name(), val)
2017-06-13 15:51:40 +10:00
2017-06-20 20:40:19 +10:00
outputs = {}
for dest in self._alg.destinationParameterDefinitions():
if not dest.flags() & QgsProcessingParameterDefinition.FlagHidden:
name = str(self.valueItems[dest.name()].text())
if name.strip() != '' and name != ModelerParametersDialog.ENTER_NAME:
output = QgsProcessingModelOutput(name, name)
2017-06-20 20:40:19 +10:00
output.setChildId(alg.childId())
output.setChildOutputName(dest.name())
outputs[name] = output
2017-06-20 20:40:19 +10:00
alg.setModelOutputs(outputs)
2013-02-07 01:09:39 +01:00
2013-02-03 10:26:43 +01:00
selectedOptions = self.dependenciesPanel.selectedoptions
2017-01-23 09:24:31 +10:00
availableDependencies = self.getAvailableDependencies() # spellok
2017-06-13 16:05:59 +10:00
dep_ids = []
2013-02-03 10:26:43 +01:00
for selected in selectedOptions:
2017-06-13 16:05:59 +10:00
dep_ids.append(availableDependencies[selected].childId()) # spellok
alg.setDependencies(dep_ids)
2017-06-13 15:51:40 +10:00
#try:
# self._alg.processBeforeAddingToModeler(alg, self.model)
#except:
# pass
2013-02-07 01:09:39 +01:00
return alg
2012-09-15 18:25:25 +03:00
def okPressed(self):
alg = self.createAlgorithm()
if alg is not None:
self.accept()
2012-09-15 18:25:25 +03:00
def cancelPressed(self):
self.reject()
def openHelp(self):
algHelp = self._alg.helpUrl()
if not algHelp:
algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format(
self._alg.provider().id(), self._alg.id())).toString()
if algHelp not in [None, ""]:
webbrowser.open(algHelp)