Skip to content

Commit

Permalink
[FEATURE][processing] Allow expression variables to be set for a model
Browse files Browse the repository at this point in the history
This adds a new "Model Variables" dock panel to the model editor, allowing
users to create and set custom expression variables for use in the model.
These variables are available anywhere expressions are (correctly) evaluated
within the model, so can be used as input parameter values for child
algorithms, within data-defined dynamic parameters, etc.

The use case here is for models which use a constant value throughout
multiple steps within the model (e.g. @target_resolution: a target
raster resolution, @max_simplification: a simplification value for
input features coming from different sources, etc), allowing users
one single place to define and edit these constant values (instead
of hunting down and setting them in multiple places throughout the model).

These variables are stored within the model itself, and are not exposed
outside of the model designer dialog.
  • Loading branch information
nyalldawson committed Feb 22, 2019
1 parent e31fb92 commit c1aac32
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
43 changes: 39 additions & 4 deletions python/plugins/processing/modeler/ModelerDialog.py
Expand Up @@ -79,14 +79,17 @@
QgsProcessingUtils,
QgsProcessingModelAlgorithm,
QgsProcessingModelParameter,
QgsProcessingParameterType
QgsProcessingParameterType,
QgsExpressionContextScope,
QgsExpressionContext
)
from qgis.gui import (QgsMessageBar,
QgsDockWidget,
QgsScrollArea,
QgsFilterLineEdit,
QgsProcessingToolboxTreeView,
QgsProcessingToolboxProxyModel)
QgsProcessingToolboxProxyModel,
QgsVariableEditorWidget)
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
Expand Down Expand Up @@ -140,6 +143,8 @@ def __init__(self, model=None):

self.setupUi(self)

self._variables_scope = None

# LOTS of bug reports when we include the dock creation in the UI file
# see e.g. #16428, #19068
# So just roll it all by hand......!
Expand Down Expand Up @@ -181,8 +186,7 @@ def __init__(self, model=None):
self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1)
self.verticalDockLayout_1.addWidget(self.scrollArea_1)
self.propertiesDock.setWidget(propertiesDockContents)
self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock)
self.propertiesDock.setWindowTitle(self.tr("Model properties"))
self.propertiesDock.setWindowTitle(self.tr("Model Properties"))

self.inputsDock = QgsDockWidget(self)
self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
Expand Down Expand Up @@ -243,6 +247,22 @@ def __init__(self, model=None):
self.searchBox.setToolTip(self.tr("Enter algorithm name to filter list"))
self.searchBox.setShowSearchIcon(True)

self.variables_dock = QgsDockWidget(self)
self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
self.variables_dock.setObjectName("variablesDock")
self.variables_dock_contents = QWidget()
vl_v = QVBoxLayout(self.algorithmsDockContents)
vl_v.setContentsMargins(0, 0, 0, 0)
self.variables_editor = QgsVariableEditorWidget()
vl_v.addWidget(self.variables_editor)
self.variables_dock_contents.setLayout(vl_v)
self.variables_dock.setWidget(self.variables_dock_contents)
self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock)
self.variables_dock.setWindowTitle(self.tr("Variables"))
self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock)
self.tabifyDockWidget(self.propertiesDock, self.variables_dock)
self.variables_editor.scopeChanged.connect(self.variables_changed)

self.bar = QgsMessageBar()
self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
self.centralWidget().layout().insertWidget(0, self.bar)
Expand Down Expand Up @@ -455,6 +475,7 @@ def _mimeDataInput(items):
else:
self.model = QgsProcessingModelAlgorithm()
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
self.update_variables_gui()

self.fillInputsTree()

Expand Down Expand Up @@ -492,6 +513,18 @@ def editHelp(self):
self.model.setHelpContent(dlg.descriptions)
self.hasChanged = True

def update_variables_gui(self):
variables_scope = QgsExpressionContextScope(self.tr('Model Variables'))
for k, v in self.model.variables().items():
variables_scope.setVariable(k, v)
variables_context = QgsExpressionContext()
variables_context.appendScope(variables_scope)
self.variables_editor.setContext(variables_context)
self.variables_editor.setEditableScopeIndex(0)

def variables_changed(self):
self.model.setVariables(self.variables_editor.variablesInActiveScope())

def runModel(self):
if len(self.model.childAlgorithms()) == 0:
self.bar.pushMessage("", self.tr("Model doesn't contain any algorithm and/or parameter and can't be executed"), level=Qgis.Warning, duration=5)
Expand Down Expand Up @@ -722,6 +755,8 @@ def loadModel(self, filename):
self.textName.setText(alg.name())
self.repaintModel()

self.update_variables_gui()

self.view.centerOn(0, 0)
self.hasChanged = False
else:
Expand Down
1 change: 1 addition & 0 deletions src/gui/processing/qgsprocessingmodelerparameterwidget.cpp
Expand Up @@ -198,6 +198,7 @@ QgsExpressionContext QgsProcessingModelerParameterWidget::createExpressionContex
QStringList highlightedVariables = childScope->variableNames();
QStringList highlightedFunctions = childScope->functionNames();
highlightedVariables += algorithmScope->variableNames();
highlightedVariables += mModel->variables().keys();
highlightedFunctions += algorithmScope->functionNames();
c.setHighlightedVariables( highlightedVariables );
c.setHighlightedFunctions( highlightedFunctions );
Expand Down
1 change: 1 addition & 0 deletions src/gui/processing/qgsprocessingwidgetwrapper.cpp
Expand Up @@ -326,6 +326,7 @@ QgsExpressionContext QgsProcessingGuiUtils::createExpressionContext( QgsProcessi
QStringList highlightedVariables = childScope->variableNames();
QStringList highlightedFunctions = childScope->functionNames();
highlightedVariables += algorithmScope->variableNames();
highlightedVariables += widgetContext.model()->variables().keys();
highlightedFunctions += algorithmScope->functionNames();
c.setHighlightedVariables( highlightedVariables );
c.setHighlightedFunctions( highlightedFunctions );
Expand Down

0 comments on commit c1aac32

Please sign in to comment.