From f1c53c3aa49b1277d91939dea9c23b4e93d956e0 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 15 May 2017 16:16:32 +1000 Subject: [PATCH] Refactor Algorithm setParamValues -> getParamValues Now returns a dict of parameter inputs for the algorithm --- .../algs/gdal/GdalAlgorithmDialog.py | 8 ++-- .../processing/algs/qgis/QgisAlgorithm.py | 38 +++++++++++++++++ .../plugins/processing/gui/AlgorithmDialog.py | 36 ++++++++-------- .../processing/gui/AlgorithmDialogBase.py | 4 +- ...nPanel.py => DestinationSelectionPanel.py} | 41 ++++++++++--------- .../plugins/processing/gui/ParametersPanel.py | 34 +++++++++------ 6 files changed, 106 insertions(+), 55 deletions(-) create mode 100755 python/plugins/processing/algs/qgis/QgisAlgorithm.py rename python/plugins/processing/gui/{OutputSelectionPanel.py => DestinationSelectionPanel.py} (87%) diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py index 9f2d638cb8f..87f25de34d6 100644 --- a/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py +++ b/python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py @@ -107,10 +107,10 @@ class GdalParametersPanel(ParametersPanel): def parametersHaveChanged(self): try: - self.parent.setParamValues() - for output in self.alg.outputs: - if output.value is None: - output.value = self.tr("[temporary file]") + parameters = self.parent.getParamValues() + for output in self.alg.destinationParameterDefinitions(): + if parameters[output.name()] is None: + parameters[output.name()] = self.tr("[temporary file]") commands = self.alg.getConsoleCommands() commands = [c for c in commands if c not in ['cmd.exe', '/C ']] self.text.setPlainText(" ".join(commands)) diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithm.py b/python/plugins/processing/algs/qgis/QgisAlgorithm.py new file mode 100755 index 00000000000..da751a0d7dd --- /dev/null +++ b/python/plugins/processing/algs/qgis/QgisAlgorithm.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +""" +*************************************************************************** + QgisAlgorithm.py + ---------------- + Date : May 2017 + Copyright : (C) 2017 by Nyall Dawson + Email : nyall dot dawson 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__ = 'Nyall Dawson' +__date__ = 'May2017' +__copyright__ = '(C) 2017, Nyall Dawson' + +# This will get replaced with a git SHA1 when you do a git archive + +__revision__ = '$Format:%H$' + +from processing.core import GeoAlgorithm +from processing.algs.help import shortHelp + + +class QgisAlgorithm(QgisAlgorithm): + + def __init__(self): + super().__init__() + + def shortHelpString(self): + return shortHelp.get(self.id(), None) diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py index c80175d3dcf..94235d35852 100644 --- a/python/plugins/processing/gui/AlgorithmDialog.py +++ b/python/plugins/processing/gui/AlgorithmDialog.py @@ -31,7 +31,8 @@ from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, from qgis.PyQt.QtGui import QCursor, QColor, QPalette from qgis.core import (QgsProject, - QgsProcessingUtils) + QgsProcessingUtils, + QgsProcessingParameterDefinition) from qgis.gui import QgsMessageBar from qgis.utils import iface @@ -88,23 +89,26 @@ class AlgorithmDialog(AlgorithmDialogBase): dlg.show() dlg.exec_() - def setParamValues(self): - params = self.alg.parameters - outputs = self.alg.outputs + def getParamValues(self): + parameters = {} - for param in params: - if param.hidden: + for param in self.alg.parameterDefinitions(): + if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue - wrapper = self.mainWidget.wrappers[param.name] - if not self.setParamValue(param, wrapper): - raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget) + if not param.isDestination(): + wrapper = self.mainWidget.wrappers[param.name()] + if wrapper.widget: + value = wrapper.value() + parameters[param.name()] = value - for output in outputs: - if output.hidden: - continue - output.value = self.mainWidget.outputWidgets[output.name].getValue() - if isinstance(output, (OutputRaster, OutputVector, OutputTable)): - output.open = self.mainWidget.checkBoxes[output.name].isChecked() + #TODO + #if not self.setParamValue(param, wrapper): + # raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget) + else: + parameters[param.name()] = self.mainWidget.outputWidgets[param.name()].getValue() + # TODO + #if isinstance(output, (OutputRaster, OutputVector, OutputTable)): + # output.open = self.mainWidget.checkBoxes[param.name()].isChecked() return True @@ -154,7 +158,7 @@ class AlgorithmDialog(AlgorithmDialogBase): checkCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_CRS) try: - self.setParamValues() + parameters = self.getParamValues() if checkCRS and not self.alg.checkInputCRS(): reply = QMessageBox.question(self, self.tr("Unmatching CRS's"), self.tr('Layers do not all use the same CRS. This can ' diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py index 695ef9c765f..b29f65ec358 100644 --- a/python/plugins/processing/gui/AlgorithmDialogBase.py +++ b/python/plugins/processing/gui/AlgorithmDialogBase.py @@ -219,8 +219,8 @@ class AlgorithmDialogBase(BASE, WIDGET): self.setInfo(text, False) QCoreApplication.processEvents() - def setParamValues(self): - pass + def getParamValues(self): + return {} def setParamValue(self, param, widget, alg=None): pass diff --git a/python/plugins/processing/gui/OutputSelectionPanel.py b/python/plugins/processing/gui/DestinationSelectionPanel.py similarity index 87% rename from python/plugins/processing/gui/OutputSelectionPanel.py rename to python/plugins/processing/gui/DestinationSelectionPanel.py index 09574478300..66a12770adc 100644 --- a/python/plugins/processing/gui/OutputSelectionPanel.py +++ b/python/plugins/processing/gui/DestinationSelectionPanel.py @@ -36,7 +36,8 @@ from qgis.PyQt.QtGui import QCursor from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog from qgis.core import (QgsDataSourceUri, QgsCredentials, - QgsSettings) + QgsSettings, + QgsProcessingOutputVectorLayer) from processing.core.ProcessingConfig import ProcessingConfig from processing.core.outputs import OutputVector from processing.core.outputs import OutputDirectory @@ -47,22 +48,22 @@ WIDGET, BASE = uic.loadUiType( os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui')) -class OutputSelectionPanel(BASE, WIDGET): +class DestinationSelectionPanel(BASE, WIDGET): SAVE_TO_TEMP_FILE = QCoreApplication.translate( - 'OutputSelectionPanel', '[Save to temporary file]') + 'DestinationSelectionPanel', '[Save to temporary file]') SAVE_TO_TEMP_LAYER = QCoreApplication.translate( - 'OutputSelectionPanel', '[Create temporary layer]') + 'DestinationSelectionPanel', '[Create temporary layer]') - def __init__(self, output, alg): - super(OutputSelectionPanel, self).__init__(None) + def __init__(self, parameter, alg): + super(DestinationSelectionPanel, self).__init__(None) self.setupUi(self) - self.output = output + self.parameter = parameter self.alg = alg if hasattr(self.leText, 'setPlaceholderText'): - if isinstance(output, OutputVector) \ + if isinstance(self.parameter, QgsProcessingOutputVectorLayer) \ and alg.provider().supportsNonFileBasedOutput(): # use memory layers for temporary files if supported self.leText.setPlaceholderText(self.SAVE_TO_TEMP_LAYER) @@ -72,12 +73,12 @@ class OutputSelectionPanel(BASE, WIDGET): self.btnSelect.clicked.connect(self.selectOutput) def selectOutput(self): - if isinstance(self.output, OutputDirectory): + if isinstance(self.parameter, OutputDirectory): self.selectDirectory() else: popupMenu = QMenu() - if isinstance(self.output, OutputVector) \ + if isinstance(self.parameter, QgsProcessingOutputVectorLayer) \ and self.alg.provider().supportsNonFileBasedOutput(): # use memory layers for temporary layers if supported actionSaveToTemp = QAction( @@ -98,7 +99,7 @@ class OutputSelectionPanel(BASE, WIDGET): actionShowExpressionsBuilder.triggered.connect(self.showExpressionsBuilder) popupMenu.addAction(actionShowExpressionsBuilder) - if isinstance(self.output, OutputVector) \ + if isinstance(self.parameter, QgsProcessingOutputVectorLayer) \ and self.alg.provider().supportsNonFileBasedOutput(): actionSaveToSpatialite = QAction( self.tr('Save to Spatialite table...'), self.btnSelect) @@ -118,7 +119,7 @@ class OutputSelectionPanel(BASE, WIDGET): def showExpressionsBuilder(self): dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', - self.output.expressionContext(self.alg)) + self.parameter.expressionContext(self.alg)) dlg.setWindowTitle(self.tr('Expression based output')) if dlg.exec_() == QDialog.Accepted: self.leText.setText(dlg.expressionText()) @@ -127,7 +128,7 @@ class OutputSelectionPanel(BASE, WIDGET): self.leText.setText('') def saveToPostGIS(self): - dlg = PostgisTableSelector(self, self.output.name.lower()) + dlg = PostgisTableSelector(self, self.parameter.name().lower()) dlg.exec_() if dlg.connection: settings = QgsSettings() @@ -140,7 +141,7 @@ class OutputSelectionPanel(BASE, WIDGET): uri = QgsDataSourceUri() uri.setConnection(host, str(port), dbname, user, password) uri.setDataSource(dlg.schema, dlg.table, - "the_geom" if self.output.hasGeometry() else None) + "the_geom" if self.parameter.hasGeometry() else None) connInfo = uri.connectionInfo() (success, user, passwd) = QgsCredentials.instance().get(connInfo, None, None) @@ -149,7 +150,7 @@ class OutputSelectionPanel(BASE, WIDGET): self.leText.setText("postgis:" + uri.uri()) def saveToSpatialite(self): - fileFilter = self.output.tr('SpatiaLite files (*.sqlite)', 'OutputFile') + fileFilter = self.tr('SpatiaLite files (*.sqlite)', 'OutputFile') settings = QgsSettings() if settings.contains('/Processing/LastOutputPath'): @@ -167,7 +168,7 @@ class OutputSelectionPanel(BASE, WIDGET): if fileDialog.exec_() == QDialog.Accepted: files = fileDialog.selectedFiles() encoding = str(fileDialog.encoding()) - self.output.encoding = encoding + self.parameter.encoding = encoding fileName = str(files[0]) selectedFileFilter = str(fileDialog.selectedNameFilter()) if not fileName.lower().endswith( @@ -181,12 +182,12 @@ class OutputSelectionPanel(BASE, WIDGET): uri = QgsDataSourceUri() uri.setDatabase(fileName) - uri.setDataSource('', self.output.name.lower(), - 'the_geom' if self.output.hasGeometry() else None) + uri.setDataSource('', self.parameter.name().lower(), + 'the_geom' if self.parameter.hasGeometry() else None) self.leText.setText("spatialite:" + uri.uri()) def selectFile(self): - fileFilter = self.output.getFileFilter(self.alg) + fileFilter = self.parameter.getFileFilter(self.alg) settings = QgsSettings() if settings.contains('/Processing/LastOutputPath'): @@ -204,7 +205,7 @@ class OutputSelectionPanel(BASE, WIDGET): if fileDialog.exec_() == QDialog.Accepted: files = fileDialog.selectedFiles() encoding = str(fileDialog.encoding()) - self.output.encoding = encoding + self.parameter.encoding = encoding fileName = str(files[0]) selectedFileFilter = str(fileDialog.selectedNameFilter()) if not fileName.lower().endswith( diff --git a/python/plugins/processing/gui/ParametersPanel.py b/python/plugins/processing/gui/ParametersPanel.py index 78e08ae6fd9..66a57511b1c 100644 --- a/python/plugins/processing/gui/ParametersPanel.py +++ b/python/plugins/processing/gui/ParametersPanel.py @@ -34,14 +34,16 @@ import os from qgis.core import (QgsProcessingParameterDefinition, QgsProcessingParameterExtent, QgsProcessingParameterPoint, - QgsProcessingParameterVectorLayer) + QgsProcessingParameterVectorLayer, + QgsProcessingOutputVectorLayer, + QgsProcessingParameterOutputVectorLayer) from qgis.PyQt import uic from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtWidgets import (QWidget, QHBoxLayout, QToolButton, QLabel, QCheckBox) from qgis.PyQt.QtGui import QIcon -from processing.gui.OutputSelectionPanel import OutputSelectionPanel +from processing.gui.DestinationSelectionPanel import DestinationSelectionPanel from processing.gui.wrappers import WidgetWrapperFactory from processing.core.parameters import ParameterVector, ParameterExtent, ParameterPoint from processing.core.outputs import OutputRaster @@ -93,17 +95,7 @@ class ParametersPanel(BASE, WIDGET): continue if param.isDestination(): - label = QLabel(param.description()) - widget = OutputSelectionPanel(param, self.alg) - self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) - self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) - if isinstance(param, (OutputRaster, QgsProcessingParameterOutputVectorLayer, OutputTable)): - check = QCheckBox() - check.setText(self.tr('Open output file after running algorithm')) - check.setChecked(True) - self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) - self.checkBoxes[param.name()] = check - self.outputWidgets[param.name()] = widget + continue else: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): @@ -157,6 +149,22 @@ class ParametersPanel(BASE, WIDGET): self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) + for output in self.alg.destinationParameterDefinitions(): + if output.flags() & QgsProcessingParameterDefinition.FlagHidden: + continue + + label = QLabel(output.description()) + widget = DestinationSelectionPanel(output, self.alg) + self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) + self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) + if isinstance(output, (OutputRaster, QgsProcessingParameterOutputVectorLayer, OutputTable)): + check = QCheckBox() + check.setText(self.tr('Open output file after running algorithm')) + check.setChecked(True) + self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) + self.checkBoxes[output.name()] = check + self.outputWidgets[output.name()] = widget + for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))