Skip to content

Commit

Permalink
[processing] added support for expressions in some input params and o…
Browse files Browse the repository at this point in the history
…utputs
  • Loading branch information
volaya committed Apr 25, 2016
1 parent a7c3861 commit ac0bff3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 13 deletions.
25 changes: 21 additions & 4 deletions python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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())
Expand Down Expand Up @@ -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:
Expand Down
30 changes: 23 additions & 7 deletions python/plugins/processing/gui/NumberInputPanel.py
Expand Up @@ -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(
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
25 changes: 23 additions & 2 deletions python/plugins/processing/gui/OutputSelectionPanel.py
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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('')

Expand Down Expand Up @@ -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:'):
Expand Down

2 comments on commit ac0bff3

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@gioman
Copy link
Contributor

@gioman gioman commented on ac0bff3 May 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Please sign in to comment.