Skip to content
Permalink
Browse files

[processing] added support for expressions in some input params and o…

…utputs
  • Loading branch information
volaya committed Apr 25, 2016
1 parent a7c3861 commit ac0bff32bf6ec7f31f7ebfd0e119162694c4b67d
@@ -29,7 +29,7 @@
from PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout
from 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 @@ def setParamValues(self):
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,18 @@ def setParamValues(self):

return True

def evaluateExpression(self, text):
context = QgsExpressionContext()
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 +171,12 @@ def setParamValue(self, param, widget, alg=None):
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:
@@ -29,9 +29,12 @@

from PyQt import uic
from 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)
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog

pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
@@ -46,6 +49,7 @@ def __init__(self, number, minimum, maximum, isInteger):
super(NumberInputPanel, self).__init__(None)
self.setupUi(self)

self.spnValue.setExpressionsEnabled(True)
self.isInteger = isInteger
if self.isInteger:
self.spnValue.setDecimals(0)
@@ -74,15 +78,27 @@ def __init__(self, number, minimum, maximum, isInteger):
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 = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope())
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 getValue(self):
return self.spnValue.value()
@@ -32,8 +32,9 @@
from PyQt.QtCore import QCoreApplication, QSettings
from PyQt.QtWidgets import QDialog, QMenu, QAction, QFileDialog
from 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

from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.outputs import OutputVector
@@ -78,6 +79,11 @@ def selectOutput(self):
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,14 @@ def selectOutput(self):

popupMenu.exec_(QCursor.pos())

def showExpressionsBuilder(self):
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.projectScope())
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, "generic", context)
dlg.setWindowTitle(self.tr("Expression based output"));
if dlg.exec_() == QDialog.Accepted:
self.leText.setText(dlg.expressionText())

def saveToTemporaryFile(self):
self.leText.setText('')

@@ -202,6 +216,13 @@ def selectDirectory(self):

def getValue(self):
fileName = unicode(self.leText.text())
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.projectScope())
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:'):

2 comments on commit ac0bff3

@nyalldawson

This comment has been minimized.

Copy link
Collaborator

@nyalldawson nyalldawson replied May 19, 2016

@volaya I've just noticed that this change has totally broken some algorithms - like the "select by expression" algorithm.

@gioman

This comment has been minimized.

Copy link
Contributor

@gioman gioman replied May 19, 2016

@nyalldawson @volaya there is already a ticket about this issue?

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