mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-04 00:30:59 -05:00
249 lines
8.9 KiB
Python
249 lines
8.9 KiB
Python
from qgis.core import (QgsProcessingUtils,
|
|
QgsProcessingParameterDefinition,
|
|
QgsProject)
|
|
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_BATCH
|
|
from processing.tools import dataobjects
|
|
from processing.tools.system import userFolder
|
|
from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
|
|
from qgis.PyQt.QtWidgets import (QLineEdit, QPushButton, QLabel,
|
|
QComboBox, QSpacerItem, QSizePolicy)
|
|
from qgis.PyQt.QtGui import QTextCursor
|
|
from processing.core.outputs import OutputRaster
|
|
from processing.core.parameters import ParameterRaster
|
|
from processing.gui.wrappers import InvalidParameterValue
|
|
import os
|
|
from qgis.PyQt import uic
|
|
from functools import partial
|
|
import re
|
|
import json
|
|
|
|
pluginPath = os.path.dirname(__file__)
|
|
WIDGET_ADD_NEW, BASE_ADD_NEW = uic.loadUiType(
|
|
os.path.join(pluginPath, 'AddNewExpressionDialog.ui'))
|
|
|
|
|
|
class AddNewExpressionDialog(BASE_ADD_NEW, WIDGET_ADD_NEW):
|
|
|
|
def __init__(self, expression):
|
|
super(AddNewExpressionDialog, self).__init__()
|
|
self.setupUi(self)
|
|
|
|
self.name = None
|
|
self.expression = None
|
|
self.txtExpression.setPlainText(expression)
|
|
self.buttonBox.rejected.connect(self.cancelPressed)
|
|
self.buttonBox.accepted.connect(self.okPressed)
|
|
|
|
def cancelPressed(self):
|
|
self.close()
|
|
|
|
def okPressed(self):
|
|
self.name = self.txtName.text()
|
|
self.expression = self.txtExpression.toPlainText()
|
|
self.close()
|
|
|
|
|
|
WIDGET_DLG, BASE_DLG = uic.loadUiType(
|
|
os.path.join(pluginPath, 'PredefinedExpressionDialog.ui'))
|
|
|
|
|
|
class PredefinedExpressionDialog(BASE_DLG, WIDGET_DLG):
|
|
|
|
def __init__(self, expression, options):
|
|
super(PredefinedExpressionDialog, self).__init__()
|
|
self.setupUi(self)
|
|
|
|
self.filledExpression = None
|
|
self.options = options
|
|
self.expression = expression
|
|
self.variables = set(re.findall('\[.*?\]', expression))
|
|
self.comboBoxes = {}
|
|
for variable in self.variables:
|
|
label = QLabel(variable[1:-1])
|
|
combo = QComboBox()
|
|
for opt in self.options.keys():
|
|
combo.addItem(opt)
|
|
self.comboBoxes[variable] = combo
|
|
self.groupBox.layout().addWidget(label)
|
|
self.groupBox.layout().addWidget(combo)
|
|
|
|
verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
self.groupBox.layout().addItem(verticalSpacer)
|
|
|
|
self.buttonBox.rejected.connect(self.cancelPressed)
|
|
self.buttonBox.accepted.connect(self.okPressed)
|
|
|
|
def cancelPressed(self):
|
|
self.close()
|
|
|
|
def okPressed(self):
|
|
self.filledExpression = self.expression
|
|
for name, combo in self.comboBoxes.items():
|
|
self.filledExpression = self.filledExpression.replace(name,
|
|
self.options[combo.currentText()])
|
|
self.close()
|
|
|
|
|
|
WIDGET, BASE = uic.loadUiType(
|
|
os.path.join(pluginPath, 'ExpressionWidget.ui'))
|
|
|
|
|
|
class ExpressionWidget(BASE, WIDGET):
|
|
|
|
_expressions = {"NDVI": "([NIR] - [Red]) % ([NIR] + [Red])"}
|
|
|
|
def __init__(self, options):
|
|
super(ExpressionWidget, self).__init__(None)
|
|
self.setupUi(self)
|
|
|
|
self.setList(options)
|
|
|
|
def doubleClicked(item):
|
|
self.text.insertPlainText(self.options[item.text()])
|
|
|
|
def addButtonText(text):
|
|
if any(c for c in text if c.islower()):
|
|
self.text.insertPlainText(" {}()".format(text))
|
|
self.text.moveCursor(QTextCursor.PreviousCharacter, QTextCursor.MoveAnchor)
|
|
else:
|
|
self.text.insertPlainText(" {} ".format(text))
|
|
buttons = [b for b in self.buttonsGroupBox.children()if isinstance(b, QPushButton)]
|
|
for button in buttons:
|
|
button.clicked.connect(partial(addButtonText, button.text()))
|
|
self.listWidget.itemDoubleClicked.connect(doubleClicked)
|
|
|
|
self.expressions = {}
|
|
if os.path.exists(self.expsFile()):
|
|
with open(self.expsFile()) as f:
|
|
self.expressions.update(json.load(f))
|
|
self.expressions.update(self._expressions)
|
|
|
|
self.fillPredefined()
|
|
self.buttonAddPredefined.clicked.connect(self.addPredefined)
|
|
|
|
self.buttonSavePredefined.clicked.connect(self.savePredefined)
|
|
|
|
def expsFile(self):
|
|
return os.path.join(userFolder(), 'rastercalcexpressions.json')
|
|
|
|
def addPredefined(self):
|
|
expression = self.expressions[self.comboPredefined.currentText()]
|
|
dlg = PredefinedExpressionDialog(expression, self.options)
|
|
dlg.exec_()
|
|
if dlg.filledExpression:
|
|
self.text.setPlainText(dlg.filledExpression)
|
|
|
|
def savePredefined(self):
|
|
exp = self.text.toPlainText()
|
|
used = [v for v in self.options.values() if v in exp]
|
|
|
|
for i, v in enumerate(used):
|
|
exp = exp.replace(v, chr(97 + i))
|
|
|
|
dlg = AddNewExpressionDialog(exp)
|
|
dlg.exec_()
|
|
if dlg.name:
|
|
self.expressions[dlg.name] = dlg.expression
|
|
|
|
with open(self.expsFile(), "w") as f:
|
|
f.write(json.dumps(self.expressions))
|
|
|
|
def fillPredefined(self):
|
|
self.comboPredefined.clear()
|
|
for expression in self.expressions:
|
|
self.comboPredefined.addItem(expression)
|
|
|
|
def setList(self, options):
|
|
self.options = options
|
|
self.listWidget.clear()
|
|
for opt in options.keys():
|
|
self.listWidget.addItem(opt)
|
|
|
|
def setValue(self, value):
|
|
self.text.setPlainText(value)
|
|
|
|
def value(self):
|
|
return self.text.toPlainText()
|
|
|
|
|
|
class ExpressionWidgetWrapper(WidgetWrapper):
|
|
|
|
def _panel(self, options):
|
|
return ExpressionWidget(options)
|
|
|
|
def createWidget(self):
|
|
if self.dialogType == DIALOG_STANDARD:
|
|
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
|
|
options = {}
|
|
for lyr in layers:
|
|
for n in range(lyr.bandCount()):
|
|
name = '{:s}@{:d}'.format(lyr.name(), n + 1)
|
|
options[name] = name
|
|
return self._panel(options)
|
|
elif self.dialogType == DIALOG_BATCH:
|
|
return QLineEdit()
|
|
else:
|
|
layers = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster)
|
|
options = {self.dialog.resolveValueDescription(lyr): "{}@1".format(lyr) for lyr in layers}
|
|
return self._panel(options)
|
|
|
|
def refresh(self):
|
|
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
|
|
options = {}
|
|
for lyr in layers:
|
|
for n in range(lyr.bandCount()):
|
|
options[lyr.name()] = '{:s}@{:d}'.format(lyr.name(), n + 1)
|
|
self.widget.setList(options)
|
|
|
|
def setValue(self, value):
|
|
if self.dialogType == DIALOG_STANDARD:
|
|
pass # TODO
|
|
elif self.dialogType == DIALOG_BATCH:
|
|
return self.widget.setText(value)
|
|
else:
|
|
self.widget.setValue(value)
|
|
|
|
def value(self):
|
|
if self.dialogType in DIALOG_STANDARD:
|
|
return self.widget.value()
|
|
elif self.dialogType == DIALOG_BATCH:
|
|
return self.widget.text()
|
|
else:
|
|
return self.widget.value()
|
|
|
|
|
|
class LayersListWidgetWrapper(WidgetWrapper):
|
|
|
|
def createWidget(self):
|
|
if self.dialogType == DIALOG_BATCH:
|
|
widget = BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog)
|
|
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
|
|
return widget
|
|
else:
|
|
return None
|
|
|
|
def setValue(self, value):
|
|
if self.dialogType == DIALOG_BATCH:
|
|
return self.widget.setText(value)
|
|
|
|
def value(self):
|
|
if self.dialogType == DIALOG_STANDARD:
|
|
if self.param.datatype == dataobjects.TYPE_FILE:
|
|
return self.param.setValue(self.widget.selectedoptions)
|
|
else:
|
|
if self.param.datatype == dataobjects.TYPE_RASTER:
|
|
options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
|
|
elif self.param.datatype == dataobjects.TYPE_VECTOR_ANY:
|
|
options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
|
|
else:
|
|
options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.param.datatype], False)
|
|
return [options[i] for i in self.widget.selectedoptions]
|
|
elif self.dialogType == DIALOG_BATCH:
|
|
return self.widget.getText()
|
|
else:
|
|
options = self._getOptions()
|
|
values = [options[i] for i in self.widget.selectedoptions]
|
|
if len(values) == 0 and not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
|
|
raise InvalidParameterValue()
|
|
return values
|