Skip to content
Permalink
Browse files

[FEATURE][processing] Add option to calculate parameter values by exp…

…ression in batch dialog

This new option is available under the Autofill menu for a column. Selecting it allows users
to create a new QGIS expression to use to update the value inside that column. Existing
parameter values (including those from other columns) are available for use inside
the expression via @variables.

E.g. this allows setting output file names to complex expressions like
'/home/me/stuff/buffer_' || left(@input, 30) || '_' || @distance || '.shp'
  • Loading branch information
nyalldawson committed Apr 26, 2019
1 parent 185172a commit ee7daa8db7b67f1d5f4a8c5367c41ae9c714645e
Showing with 58 additions and 2 deletions.
  1. +58 −2 python/plugins/processing/gui/BatchPanel.py
@@ -65,12 +65,15 @@
QgsProcessingParameterRasterDestination,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputLayerDefinition
QgsProcessingOutputLayerDefinition,
QgsExpressionContextUtils,
QgsExpression
)
from qgis.gui import (
QgsProcessingParameterWidgetContext,
QgsProcessingContextGenerator,
QgsFindFilesByPatternDialog
QgsFindFilesByPatternDialog,
QgsExpressionBuilderDialog
)
from qgis.utils import iface

@@ -120,12 +123,20 @@ def createMenu(self):
fill_down_action.setToolTip(self.tr('Copy the first value down to all other rows'))
self.menu.addAction(fill_down_action)

calculate_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'),
self.menu)
calculate_by_expression.setIcon(QgsApplication.getThemeIcon('/mActionCalculateField.svg'))
calculate_by_expression.triggered.connect(self.calculateByExpression)
calculate_by_expression.setToolTip(self.tr('Calculates parameter values by evaluating an expression'))
self.menu.addAction(calculate_by_expression)

if isinstance(self.parameterDefinition, (QgsProcessingParameterFile,
QgsProcessingParameterMapLayer,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterMeshLayer,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSource)):
self.menu.addSeparator()
find_by_pattern_action = QAction(QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'),
self.menu)
find_by_pattern_action.triggered.connect(self.addFilesByPattern)
@@ -177,6 +188,51 @@ def addFilesByPattern(self):
for row, file in enumerate(files):
self.setRowValue(first_row + row, file, context)

def calculateByExpression(self):
"""
Calculates parameter values by evaluating expressions.
"""
context = dataobjects.createContext()
expression_context = context.expressionContext()

# use the first row parameter values as a preview during expression creation
params = self.panel.parametersForRow(0, warnOnInvalid=False)
alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context)

# create explicit variables corresponding to every parameter
for k, v in params.items():
alg_scope.setVariable(k, v, True)

expression_context.appendScope(alg_scope)

# mark the parameter variables as highlighted for discoverability
highlighted_vars = expression_context.highlightedVariables()
highlighted_vars.extend(list(params.keys()))
expression_context.setHighlightedVariables(highlighted_vars)

dlg = QgsExpressionBuilderDialog(layer=None, context=context.expressionContext())
if not dlg.exec_():
return

for row in range(self.panel.batchRowCount()):
params = self.panel.parametersForRow(row, warnOnInvalid=False)

# remove previous algorithm scope -- we need to rebuild this completely, using the
# other parameter values from the current row
expression_context.popScope()
alg_scope = QgsExpressionContextUtils.processingAlgorithmScope(self.panel.alg, params, context)

for k, v in params.items():
alg_scope.setVariable(k, v, True)

expression_context.appendScope(alg_scope)

# rebuild a new expression every time -- we don't want the expression compiler to replace
# variables with precompiled values
exp = QgsExpression(dlg.expressionText())
value = exp.evaluate(expression_context)
self.setRowValue(row, value, context)


class BatchPanel(BASE, WIDGET):
PARAMETERS = "PARAMETERS"

0 comments on commit ee7daa8

Please sign in to comment.
You can’t perform that action at this time.