Skip to content
Permalink
Browse files

[processing] Remove expression buttons from parameters outside modeler

Since these expressions were only evaluated immediately, it led to
confusing behavior for users who were expecting that the expression
would be applied per-feature.

Given that expressions can be directly entered into spin boxes, we already
have a way of users evaluating simple calculations for numeric
parameters at least.

I don't think there's a strong enough use case for needing to
calculate string results to leave the confusing expression builder
option in place.

This should be re-evaluated when we add UI support for dynamic
parameters (which are already supported in the backend), where
expressions are evaluated per-feature.

Fixes #17267
  • Loading branch information
nyalldawson committed Nov 10, 2017
1 parent abe5756 commit 612f51601a5dd17787c23d2540ddad19aa263f2b
@@ -122,11 +122,6 @@ 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.parameter, QgsProcessingParameterFeatureSink) \
and self.alg.provider().supportsNonFileBasedOutput():
actionSaveToSpatialite = QAction(
@@ -145,15 +140,6 @@ def selectOutput(self):

popupMenu.exec_(QCursor.pos())

def showExpressionsBuilder(self):
context = self.alg.createExpressionContext({}, createContext())
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic',
context)
dlg.setWindowTitle(self.tr('Expression based output'))
if dlg.exec_() == QDialog.Accepted:
expression = QgsExpression(dlg.expressionText())
self.leText.setText(expression.evaluate(context))

def saveToTemporary(self):
if isinstance(self.parameter, QgsProcessingParameterFeatureSink) and self.alg.provider().supportsNonFileBasedOutput():
self.leText.setPlaceholderText(self.SAVE_TO_TEMP_LAYER)
@@ -28,6 +28,7 @@

import os
import math
import sip

from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
@@ -123,9 +124,7 @@ class NumberInputPanel(NUMBER_BASE, NUMBER_WIDGET):

"""
Number input panel for use outside the modeller - this input panel
contains a user friendly spin box for entering values. It also
allows expressions to be evaluated, but these expressions are evaluated
immediately after entry and are not stored anywhere.
contains a user friendly spin box for entering values.
"""

hasChanged = pyqtSignal()
@@ -172,24 +171,13 @@ def __init__(self, param):
else:
self.setValue(0)
self.spnValue.setClearValue(0)
self.btnSelect.setFixedHeight(self.spnValue.height())

self.btnSelect.clicked.connect(self.showExpressionsBuilder)
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())

def showExpressionsBuilder(self):
context = createExpressionContext()
dlg = QgsExpressionBuilderDialog(None, str(self.spnValue.value()), self, 'generic', context)
# we don't show the expression button outside of modeler
self.layout().removeWidget(self.btnSelect)
sip.delete(self.btnSelect)
self.btnSelect = None

dlg.setWindowTitle(self.tr('Expression based input'))
if dlg.exec_() == QDialog.Accepted:
exp = QgsExpression(dlg.expressionText())
if not exp.hasParserError():
try:
val = float(exp.evaluate(context))
self.setValue(val)
except:
return
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())

def getValue(self):
return self.spnValue.value()
@@ -229,36 +229,6 @@ def getFileName(self, initial_value=''):
return filename, selected_filter


class ExpressionWidgetWrapperMixin():

def wrapWithExpressionButton(self, basewidget):
expr_button = QToolButton()
expr_button.clicked.connect(self.showExpressionsBuilder)
expr_button.setText('…')

layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(basewidget)
layout.addWidget(expr_button)

widget = QWidget()
widget.setLayout(layout)

return widget

def showExpressionsBuilder(self):
context = dataobjects.createExpressionContext()
value = self.value()
if not isinstance(value, str):
value = ''
dlg = QgsExpressionBuilderDialog(None, value, self.widget, 'generic', context)
dlg.setWindowTitle(self.tr('Expression based input'))
if dlg.exec_() == QDialog.Accepted:
exp = QgsExpression(dlg.expressionText())
if not exp.hasParserError():
self.setValue(dlg.expressionText())


class BasicWidgetWrapper(WidgetWrapper):

def createWidget(self):
@@ -1032,15 +1002,15 @@ def validator(v):
return self.comboValue(validator, combobox=self.combo)


class StringWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
class StringWidgetWrapper(WidgetWrapper):

def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
if self.param.multiLine():
widget = QPlainTextEdit()
else:
self._lineedit = QLineEdit()
return self.wrapWithExpressionButton(self._lineedit)
widget = self._lineedit

elif self.dialogType == DIALOG_BATCH:
widget = QLineEdit()
@@ -47,7 +47,7 @@ def createWidget(self):
for group in self.items():
self._combo.addItem(*group)
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return self.wrapWithExpressionButton(self._combo)
return self._combo

def items(self):
settings = QgsSettings()
@@ -86,7 +86,7 @@ def createWidget(self, connection_param=None):
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))

return self.wrapWithExpressionButton(self._combo)
return self._combo

def postInitialize(self, wrappers):
for wrapper in wrappers:
@@ -158,7 +158,7 @@ def createWidget(self, schema_param=None):
self._combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
self._combo.lineEdit().editingFinished.connect(lambda: self.widgetValueHasChanged.emit(self))

return self.wrapWithExpressionButton(self._combo)
return self._combo

def postInitialize(self, wrappers):
for wrapper in wrappers:

0 comments on commit 612f516

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