Merge branch 'processing_exps' of https://github.com/volaya/QGIS into processing_exps

Conflicts:
	python/plugins/processing/gui/NumberInputPanel.py
	python/plugins/processing/gui/OutputSelectionPanel.py
This commit is contained in:
Alexander Bruy 2016-05-13 09:26:55 +03:00
commit 730c5806aa
5 changed files with 152 additions and 17 deletions

View File

@ -29,7 +29,7 @@ from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout
from qgis.PyQt.QtGui import QCursor, QColor, QPalette 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.ProcessingLog import ProcessingLog
from processing.core.ProcessingConfig import ProcessingConfig from processing.core.ProcessingConfig import ProcessingConfig
@ -102,8 +102,8 @@ class AlgorithmDialog(AlgorithmDialogBase):
continue continue
if not self.setParamValue( if not self.setParamValue(
param, self.mainWidget.valueItems[param.name]): param, self.mainWidget.valueItems[param.name]):
raise AlgorithmDialogBase.InvalidParameterValue(param, raise AlgorithmDialogBase.InvalidParameterValue(
self.mainWidget.valueItems[param.name]) param, self.mainWidget.valueItems[param.name])
for param in params: for param in params:
if isinstance(param, ParameterExtent): if isinstance(param, ParameterExtent):
@ -121,6 +121,19 @@ class AlgorithmDialog(AlgorithmDialogBase):
return True 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): def setParamValue(self, param, widget, alg=None):
if isinstance(param, ParameterRaster): if isinstance(param, ParameterRaster):
return param.setValue(widget.getValue()) return param.setValue(widget.getValue())
@ -159,7 +172,12 @@ class AlgorithmDialog(AlgorithmDialogBase):
if param.multiline: if param.multiline:
return param.setValue(unicode(widget.toPlainText())) return param.setValue(unicode(widget.toPlainText()))
else: 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): elif isinstance(param, ParameterGeometryPredicate):
return param.setValue(widget.value()) return param.setValue(widget.value())
else: else:

View File

@ -29,9 +29,15 @@ import os
from qgis.PyQt import uic from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal from qgis.PyQt.QtCore import pyqtSignal
from PyQt.QtGui import QDialog
from math import log10, floor 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] pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType( WIDGET, BASE = uic.loadUiType(
@ -46,6 +52,7 @@ class NumberInputPanel(BASE, WIDGET):
super(NumberInputPanel, self).__init__(None) super(NumberInputPanel, self).__init__(None)
self.setupUi(self) self.setupUi(self)
self.spnValue.setExpressionsEnabled(True)
self.isInteger = isInteger self.isInteger = isInteger
if self.isInteger: if self.isInteger:
self.spnValue.setDecimals(0) self.spnValue.setDecimals(0)
@ -74,15 +81,65 @@ class NumberInputPanel(BASE, WIDGET):
self.spnValue.setValue(0) self.spnValue.setValue(0)
self.spnValue.setClearValue(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()) self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())
def showNumberInputDialog(self): def showExpressionsBuilder(self):
dlg = NumberInputDialog(self.isInteger) context = self.expressionContext()
dlg.exec_() dlg = QgsExpressionBuilderDialog(None, self.spnValue.text(), self, "generic", context)
if dlg.value is not None: dlg.setWindowTitle(self.tr("Expression based input"));
self.spnValue.setValue(dlg.value) 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): def getValue(self):
return self.spnValue.value() return self.spnValue.value()

View File

@ -32,8 +32,9 @@ from qgis.PyQt import uic
from qgis.PyQt.QtCore import QCoreApplication, QSettings from qgis.PyQt.QtCore import QCoreApplication, QSettings
from qgis.PyQt.QtWidgets import QDialog, QMenu, QAction, QFileDialog from qgis.PyQt.QtWidgets import QDialog, QMenu, QAction, QFileDialog
from qgis.PyQt.QtGui import QCursor from qgis.PyQt.QtGui import QCursor
from qgis.gui import QgsEncodingFileDialog from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
from qgis.core import QgsDataSourceURI, QgsCredentials from qgis.core import QgsDataSourceURI, QgsCredentials, QgsExpressionContext,\
QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope
from processing.core.ProcessingConfig import ProcessingConfig from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
@ -78,6 +79,11 @@ class OutputSelectionPanel(BASE, WIDGET):
actionSaveToFile.triggered.connect(self.selectFile) actionSaveToFile.triggered.connect(self.selectFile)
popupMenu.addAction(actionSaveToFile) popupMenu.addAction(actionSaveToFile)
actionShowExpressionsBuilder = QAction(
self.tr('Use expression...'), self.btnSelect)
actionShowExpressionsBuilder.triggered.connect(self.showExpressionsBuilder)
popupMenu.addAction(actionShowExpressionsBuilder)
if isinstance(self.output, OutputVector) \ if isinstance(self.output, OutputVector) \
and self.alg.provider.supportsNonFileBasedOutput(): and self.alg.provider.supportsNonFileBasedOutput():
actionSaveToMemory = QAction( actionSaveToMemory = QAction(
@ -100,6 +106,22 @@ class OutputSelectionPanel(BASE, WIDGET):
popupMenu.exec_(QCursor.pos()) 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): def saveToTemporaryFile(self):
self.leText.setText('') self.leText.setText('')
@ -202,6 +224,12 @@ class OutputSelectionPanel(BASE, WIDGET):
def getValue(self): def getValue(self):
fileName = unicode(self.leText.text()) 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]: if fileName.strip() in ['', self.SAVE_TO_TEMP_FILE]:
value = None value = None
elif fileName.startswith('memory:'): elif fileName.startswith('memory:'):

View File

@ -21,10 +21,23 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QLineEdit" name="leText"/> <widget class="QLineEdit" name="leText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="btnSelect"> <widget class="QToolButton" name="btnSelect">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>...</string> <string>...</string>
</property> </property>

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>250</width> <width>608</width>
<height>23</height> <height>20</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -21,10 +21,23 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QComboBox" name="cmbText"/> <widget class="QComboBox" name="cmbText">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="btnSelect"> <widget class="QToolButton" name="btnSelect">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>...</string> <string>...</string>
</property> </property>
@ -32,6 +45,12 @@
</item> </item>
<item> <item>
<widget class="QToolButton" name="btnIterate"> <widget class="QToolButton" name="btnIterate">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip"> <property name="toolTip">
<string>Iterate over this layer</string> <string>Iterate over this layer</string>
</property> </property>