diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py
index d13331af150..c5698edb2a6 100644
--- a/python/plugins/processing/gui/AlgorithmDialog.py
+++ b/python/plugins/processing/gui/AlgorithmDialog.py
@@ -29,7 +29,7 @@ from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout
from qgis.PyQt.QtGui import QCursor, QColor, QPalette
-from qgis.core import QgsMapLayerRegistry
+from qgis.core import QgsMapLayerRegistry, QgsExpressionContext, QgsExpressionContextUtils, QgsExpression
from processing.core.ProcessingLog import ProcessingLog
from processing.core.ProcessingConfig import ProcessingConfig
@@ -102,8 +102,8 @@ class AlgorithmDialog(AlgorithmDialogBase):
continue
if not self.setParamValue(
param, self.mainWidget.valueItems[param.name]):
- raise AlgorithmDialogBase.InvalidParameterValue(param,
- self.mainWidget.valueItems[param.name])
+ raise AlgorithmDialogBase.InvalidParameterValue(
+ param, self.mainWidget.valueItems[param.name])
for param in params:
if isinstance(param, ParameterExtent):
@@ -121,6 +121,19 @@ class AlgorithmDialog(AlgorithmDialogBase):
return True
+ def evaluateExpression(self, text):
+ context = QgsExpressionContext()
+ context.appendScope(QgsExpressionContextUtils.globalScope())
+ context.appendScope(QgsExpressionContextUtils.projectScope())
+ exp = QgsExpression(text)
+ if exp.hasParserError():
+ raise Exception(exp.parserErrorString())
+ result = exp.evaluate(context)
+ if exp.hasEvalError():
+ raise ValueError(exp.evalErrorString())
+ return result
+
+
def setParamValue(self, param, widget, alg=None):
if isinstance(param, ParameterRaster):
return param.setValue(widget.getValue())
@@ -159,7 +172,12 @@ class AlgorithmDialog(AlgorithmDialogBase):
if param.multiline:
return param.setValue(unicode(widget.toPlainText()))
else:
- return param.setValue(unicode(widget.text()))
+ text = widget.text()
+ try:
+ text = self.evaluateExpression(text)
+ except:
+ return False
+ return param.setValue(text)
elif isinstance(param, ParameterGeometryPredicate):
return param.setValue(widget.value())
else:
diff --git a/python/plugins/processing/gui/NumberInputPanel.py b/python/plugins/processing/gui/NumberInputPanel.py
index 145e1ccd0b2..27b7298cd60 100644
--- a/python/plugins/processing/gui/NumberInputPanel.py
+++ b/python/plugins/processing/gui/NumberInputPanel.py
@@ -29,9 +29,15 @@ import os
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
+from PyQt.QtGui import QDialog
from math import log10, floor
-from processing.gui.NumberInputDialog import NumberInputDialog
+from qgis.core import (QgsDataSourceURI, QgsCredentials, QgsExpressionContext,
+ QgsExpressionContextUtils, QgsExpression, QgsRasterLayer,
+ QgsExpressionContextScope)
+from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
+from qgis.utils import iface
+from processing.tools import dataobjects
pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
@@ -46,6 +52,7 @@ class NumberInputPanel(BASE, WIDGET):
super(NumberInputPanel, self).__init__(None)
self.setupUi(self)
+ self.spnValue.setExpressionsEnabled(True)
self.isInteger = isInteger
if self.isInteger:
self.spnValue.setDecimals(0)
@@ -74,15 +81,65 @@ class NumberInputPanel(BASE, WIDGET):
self.spnValue.setValue(0)
self.spnValue.setClearValue(0)
- self.btnCalc.clicked.connect(self.showNumberInputDialog)
+ self.btnCalc.setFixedHeight(self.spnValue.height())
+
+ self.btnCalc.clicked.connect(self.showExpressionsBuilder)
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())
- def showNumberInputDialog(self):
- dlg = NumberInputDialog(self.isInteger)
- dlg.exec_()
- if dlg.value is not None:
- self.spnValue.setValue(dlg.value)
+ def showExpressionsBuilder(self):
+ context = self.expressionContext()
+ dlg = QgsExpressionBuilderDialog(None, self.spnValue.text(), self, "generic", context)
+ dlg.setWindowTitle(self.tr("Expression based input"));
+ if dlg.exec_() == QDialog.Accepted:
+ exp = QgsExpression(dlg.expressionText())
+ if not exp.hasParserError():
+ result = exp.evaluate(context)
+ if not exp.hasEvalError():
+ try:
+ self.spnValue.setValue(float(result))
+ except:
+ pass
+
+ def expressionContext(self):
+ context = QgsExpressionContext()
+ context.appendScope(QgsExpressionContextUtils.globalScope())
+ context.appendScope(QgsExpressionContextUtils.projectScope())
+ processingScope = QgsExpressionContextScope()
+ layers = dataobjects.getAllLayers()
+ for layer in layers:
+ name = layer.name()
+ processingScope.setVariable("%s_minx" % name, layer.extent().xMinimum())
+ processingScope.setVariable("%s_miny" % name, layer.extent().yMinimum())
+ processingScope.setVariable("%s_maxx" % name, layer.extent().xMaximum())
+ processingScope.setVariable("%s_maxy" % name, layer.extent().yMaximum())
+ if isinstance(layer, QgsRasterLayer):
+ cellsize = (layer.extent().xMaximum()
+ - layer.extent().xMinimum()) / layer.width()
+ processingScope.setVariable("%s_cellsize" % name, cellsize)
+
+ layers = dataobjects.getRasterLayers()
+ for layer in layers:
+ for i in range(layer.bandCount()):
+ stats = layer.dataProvider().bandStatistics(i + 1)
+ processingScope.setVariable("%s_band%i_avg" % (name, i + 1), stats.mean)
+ processingScope.setVariable("%s_band%i_stddev" % (name, i + 1), stats.stdDev)
+ processingScope.setVariable("%s_band%i_min" % (name, i + 1), stats.minimumValue)
+ processingScope.setVariable("%s_band%i_max" % (name, i + 1), stats.maximumValue)
+
+ extent = iface.mapCanvas().extent()
+ processingScope.setVariable("canvasextent_minx", extent.xMinimum())
+ processingScope.setVariable("canvasextent_miny", extent.yMinimum())
+ processingScope.setVariable("canvasextent_maxx", extent.xMaximum())
+ processingScope.setVariable("canvasextent_maxy", extent.yMaximum())
+
+ extent = iface.mapCanvas().fullExtent()
+ processingScope.setVariable("fullextent_minx", extent.xMinimum())
+ processingScope.setVariable("fullextent_miny", extent.yMinimum())
+ processingScope.setVariable("fullextent_maxx", extent.xMaximum())
+ processingScope.setVariable("fullextent_maxy", extent.yMaximum())
+ context.appendScope(processingScope)
+ return context
def getValue(self):
return self.spnValue.value()
diff --git a/python/plugins/processing/gui/OutputSelectionPanel.py b/python/plugins/processing/gui/OutputSelectionPanel.py
index 06b7a82880e..68447f45e2f 100644
--- a/python/plugins/processing/gui/OutputSelectionPanel.py
+++ b/python/plugins/processing/gui/OutputSelectionPanel.py
@@ -32,8 +32,9 @@ from qgis.PyQt import uic
from qgis.PyQt.QtCore import QCoreApplication, QSettings
from qgis.PyQt.QtWidgets import QDialog, QMenu, QAction, QFileDialog
from qgis.PyQt.QtGui import QCursor
-from qgis.gui import QgsEncodingFileDialog
-from qgis.core import QgsDataSourceURI, QgsCredentials
+from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
+from qgis.core import QgsDataSourceURI, QgsCredentials, QgsExpressionContext,\
+ QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope
from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.outputs import OutputVector
@@ -78,6 +79,11 @@ class OutputSelectionPanel(BASE, WIDGET):
actionSaveToFile.triggered.connect(self.selectFile)
popupMenu.addAction(actionSaveToFile)
+ actionShowExpressionsBuilder = QAction(
+ self.tr('Use expression...'), self.btnSelect)
+ actionShowExpressionsBuilder.triggered.connect(self.showExpressionsBuilder)
+ popupMenu.addAction(actionShowExpressionsBuilder)
+
if isinstance(self.output, OutputVector) \
and self.alg.provider.supportsNonFileBasedOutput():
actionSaveToMemory = QAction(
@@ -100,6 +106,22 @@ class OutputSelectionPanel(BASE, WIDGET):
popupMenu.exec_(QCursor.pos())
+ def showExpressionsBuilder(self):
+ dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, "generic", self.expressionContext())
+ dlg.setWindowTitle(self.tr("Expression based output"));
+ if dlg.exec_() == QDialog.Accepted:
+ self.leText.setText(dlg.expressionText())
+
+ def expressionContext(self):
+ context = QgsExpressionContext()
+ context.appendScope(QgsExpressionContextUtils.globalScope())
+ context.appendScope(QgsExpressionContextUtils.projectScope())
+ processingScope = QgsExpressionContextScope()
+ for param in self.ag.parameters:
+ processingScope.setVariable("%s_value" % param.name, "")
+ context.appendScope(processingScope)
+ return context
+
def saveToTemporaryFile(self):
self.leText.setText('')
@@ -202,6 +224,12 @@ class OutputSelectionPanel(BASE, WIDGET):
def getValue(self):
fileName = unicode(self.leText.text())
+ context = self.expressionContext()
+ exp = QgsExpression(fileName)
+ if not exp.hasParserError():
+ result = exp.evaluate(context)
+ if not exp.hasEvalError():
+ fileName = result
if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE]:
value = None
elif fileName.startswith('memory:'):
diff --git a/python/plugins/processing/ui/widgetBaseSelector.ui b/python/plugins/processing/ui/widgetBaseSelector.ui
index aeed39bf4db..9a88e4ddd0f 100644
--- a/python/plugins/processing/ui/widgetBaseSelector.ui
+++ b/python/plugins/processing/ui/widgetBaseSelector.ui
@@ -21,10 +21,23 @@
0
-
-
+
+
+
+ 0
+ 0
+
+
+
-
+
+
+ 0
+ 0
+
+
...
diff --git a/python/plugins/processing/ui/widgetLayerSelector.ui b/python/plugins/processing/ui/widgetLayerSelector.ui
index a57afc69a3d..4edcdf73058 100644
--- a/python/plugins/processing/ui/widgetLayerSelector.ui
+++ b/python/plugins/processing/ui/widgetLayerSelector.ui
@@ -6,8 +6,8 @@
0
0
- 250
- 23
+ 608
+ 20
@@ -21,10 +21,23 @@
0
-
-
+
+
+
+ 0
+ 0
+
+
+
-
+
+
+ 0
+ 0
+
+
...
@@ -32,6 +45,12 @@
-
+
+
+ 0
+ 0
+
+
Iterate over this layer