mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
Merge pull request #38695 from suricactus/alg_fieldcalc_cpp_simple
Translate qgis::fieldcalculator to C++
This commit is contained in:
commit
3bea2e702e
@ -114,9 +114,6 @@ qgis:extractbyexpression: >
|
||||
|
||||
For more information about expressions see the <a href ="{qgisdocs}/user_manual/working_with_vector/expression.html">user manual</a>
|
||||
|
||||
qgis:fieldcalculator: >
|
||||
This algorithm computes a new vector layer with the same features of the input layer, but with an additional attribute. The values of this new attribute are computed from each feature using a mathematical formula, based on the properties and attributes of the feature.
|
||||
|
||||
qgis:findprojection: >
|
||||
This algorithm allows creation of a shortlist of possible candidate coordinate reference systems for a layer with an unknown projection.
|
||||
|
||||
|
@ -1,164 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
FieldsCalculator.py
|
||||
---------------------
|
||||
Date : August 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'August 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.core import (QgsExpression,
|
||||
QgsExpressionContext,
|
||||
QgsExpressionContextUtils,
|
||||
QgsFeatureSink,
|
||||
QgsField,
|
||||
QgsDistanceArea,
|
||||
QgsProcessing,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterBoolean,
|
||||
QgsProcessingParameterExpression,
|
||||
QgsProcessingParameterString,
|
||||
QgsProcessingParameterFeatureSink,
|
||||
QgsProcessingException)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
|
||||
from .ui.FieldsCalculatorDialog import FieldsCalculatorDialog
|
||||
|
||||
|
||||
class FieldsCalculator(QgisAlgorithm):
|
||||
INPUT = 'INPUT'
|
||||
NEW_FIELD = 'NEW_FIELD'
|
||||
FIELD_NAME = 'FIELD_NAME'
|
||||
FIELD_TYPE = 'FIELD_TYPE'
|
||||
FIELD_LENGTH = 'FIELD_LENGTH'
|
||||
FIELD_PRECISION = 'FIELD_PRECISION'
|
||||
FORMULA = 'FORMULA'
|
||||
OUTPUT = 'OUTPUT'
|
||||
|
||||
TYPES = [QVariant.Double, QVariant.Int, QVariant.String, QVariant.Date]
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector table')
|
||||
|
||||
def groupId(self):
|
||||
return 'vectortable'
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.type_names = [self.tr('Float'),
|
||||
self.tr('Integer'),
|
||||
self.tr('String'),
|
||||
self.tr('Date')]
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
|
||||
types=[QgsProcessing.TypeVector]))
|
||||
self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
|
||||
self.tr('Result field name')))
|
||||
self.addParameter(QgsProcessingParameterEnum(self.FIELD_TYPE,
|
||||
self.tr('Field type'), options=self.type_names))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.FIELD_LENGTH,
|
||||
self.tr('Field length'), minValue=0, defaultValue=10))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.FIELD_PRECISION,
|
||||
self.tr('Field precision'), minValue=0, maxValue=15, defaultValue=3))
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.NEW_FIELD,
|
||||
self.tr('Create new field'), defaultValue=True))
|
||||
self.addParameter(QgsProcessingParameterExpression(self.FORMULA, self.tr('Formula')))
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
|
||||
self.tr('Calculated')))
|
||||
|
||||
def name(self):
|
||||
return 'fieldcalculator'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Field calculator')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
if source is None:
|
||||
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
|
||||
|
||||
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
|
||||
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
|
||||
field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)]
|
||||
width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
|
||||
precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
|
||||
new_field = self.parameterAsBoolean(parameters, self.NEW_FIELD, context)
|
||||
formula = self.parameterAsString(parameters, self.FORMULA, context)
|
||||
|
||||
expression = QgsExpression(formula)
|
||||
da = QgsDistanceArea()
|
||||
da.setSourceCrs(source.sourceCrs(), context.transformContext())
|
||||
da.setEllipsoid(context.ellipsoid())
|
||||
expression.setGeomCalculator(da)
|
||||
|
||||
expression.setDistanceUnits(context.distanceUnit())
|
||||
expression.setAreaUnits(context.areaUnit())
|
||||
|
||||
fields = source.fields()
|
||||
field_index = fields.lookupField(field_name)
|
||||
if new_field or field_index < 0:
|
||||
fields.append(QgsField(field_name, field_type, '', width, precision))
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
fields, source.wkbType(), source.sourceCrs())
|
||||
if sink is None:
|
||||
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
|
||||
|
||||
exp_context = self.createExpressionContext(parameters, context)
|
||||
if layer is not None:
|
||||
exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
|
||||
|
||||
expression.prepare(exp_context)
|
||||
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
|
||||
for current, f in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
rownum = current + 1
|
||||
exp_context.setFeature(f)
|
||||
exp_context.lastScope().setVariable("row_number", rownum)
|
||||
value = expression.evaluate(exp_context)
|
||||
if expression.hasEvalError():
|
||||
feedback.reportError(expression.evalErrorString())
|
||||
else:
|
||||
attrs = f.attributes()
|
||||
if new_field or field_index < 0:
|
||||
attrs.append(value)
|
||||
else:
|
||||
attrs[field_index] = value
|
||||
f.setAttributes(attrs)
|
||||
sink.addFeature(f, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
||||
def checkParameterValues(self, parameters, context):
|
||||
newField = self.parameterAsBoolean(parameters, self.NEW_FIELD, context)
|
||||
fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context).strip()
|
||||
if newField and len(fieldName) == 0:
|
||||
return False, self.tr('Field name is not set. Please enter a field name')
|
||||
return super(FieldsCalculator, self).checkParameterValues(parameters, context)
|
||||
|
||||
def createCustomParametersWidget(self, parent):
|
||||
return FieldsCalculatorDialog(self)
|
@ -42,7 +42,6 @@ from .EliminateSelection import EliminateSelection
|
||||
from .ExecuteSQL import ExecuteSQL
|
||||
from .ExportGeometryInfo import ExportGeometryInfo
|
||||
from .FieldPyculator import FieldsPyculator
|
||||
from .FieldsCalculator import FieldsCalculator
|
||||
from .FindProjection import FindProjection
|
||||
from .GeometryConvert import GeometryConvert
|
||||
from .Heatmap import Heatmap
|
||||
@ -112,7 +111,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
|
||||
EliminateSelection(),
|
||||
ExecuteSQL(),
|
||||
ExportGeometryInfo(),
|
||||
FieldsCalculator(),
|
||||
FieldsPyculator(),
|
||||
FindProjection(),
|
||||
GeometryConvert(),
|
||||
|
@ -1,276 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FieldsCalculator</class>
|
||||
<widget class="QDialog" name="FieldsCalculator">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>681</width>
|
||||
<height>681</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Field calculator</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="mNewFieldGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Create a new field</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mFieldNameLabel">
|
||||
<property name="text">
|
||||
<string>Output field name</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOutputFieldNameLineEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="mOutputFieldNameLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="mOutputFieldTypeLabel">
|
||||
<property name="text">
|
||||
<string>Output field type</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOutputFieldTypeComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QComboBox" name="mOutputFieldTypeComboBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="mOutputFieldWidthLabel">
|
||||
<property name="text">
|
||||
<string>Output field width</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOutputFieldWidthSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="mOutputFieldWidthSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>Width of complete output. For example 123,456 means 6 as field width.</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>15</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="mOutputFieldPrecisionLabel">
|
||||
<property name="text">
|
||||
<string>Precision</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mOutputFieldPrecisionSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QSpinBox" name="mOutputFieldPrecisionSpinBox">
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="mButtonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Input layer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsMapLayerComboBox" name="cmbInputLayer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QGroupBox" name="mUpdateExistingGroupBox">
|
||||
<property name="title">
|
||||
<string>Update existing field</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="mExistingFieldComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QgsExpressionBuilderWidget" name="builder" native="true">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Output file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="leOutputFile"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnBrowse">
|
||||
<property name="text">
|
||||
<string>…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsExpressionBuilderWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgis.gui</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsMapLayerComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>qgis.gui</header>
|
||||
<container>0</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mOutputFieldNameLineEdit</tabstop>
|
||||
<tabstop>mOutputFieldTypeComboBox</tabstop>
|
||||
<tabstop>mOutputFieldWidthSpinBox</tabstop>
|
||||
<tabstop>mOutputFieldPrecisionSpinBox</tabstop>
|
||||
<tabstop>mButtonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>mButtonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>FieldsCalculator</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>679</x>
|
||||
<y>559</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>mButtonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>FieldsCalculator</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>679</x>
|
||||
<y>559</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,270 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
FieldsCalculatorDialog.py
|
||||
---------------------
|
||||
Date : October 2013
|
||||
Copyright : (C) 2013 by Alexander Bruy
|
||||
Email : alexander dot bruy at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Alexander Bruy'
|
||||
__date__ = 'October 2013'
|
||||
__copyright__ = '(C) 2013, Alexander Bruy'
|
||||
|
||||
import os
|
||||
import re
|
||||
import warnings
|
||||
|
||||
from qgis.PyQt import uic
|
||||
from qgis.PyQt.QtCore import Qt
|
||||
from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QApplication, QMessageBox
|
||||
from qgis.PyQt.QtGui import QCursor
|
||||
from qgis.core import (Qgis,
|
||||
QgsExpressionContextUtils,
|
||||
QgsProcessingFeedback,
|
||||
QgsSettings,
|
||||
QgsMapLayerProxyModel,
|
||||
QgsProperty,
|
||||
QgsProject,
|
||||
QgsMessageLog,
|
||||
QgsMapLayerType,
|
||||
QgsProcessingOutputLayerDefinition)
|
||||
from qgis.gui import QgsEncodingFileDialog, QgsGui
|
||||
from qgis.utils import OverrideCursor, iface
|
||||
|
||||
from processing.core.ProcessingConfig import ProcessingConfig
|
||||
from processing.core.ProcessingLog import ProcessingLog
|
||||
from processing.gui.AlgorithmExecutor import execute
|
||||
from processing.tools import dataobjects
|
||||
from processing.gui.Postprocessing import handleAlgorithmResults
|
||||
|
||||
pluginPath = os.path.dirname(__file__)
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
WIDGET, BASE = uic.loadUiType(
|
||||
os.path.join(pluginPath, 'DlgFieldsCalculator.ui'))
|
||||
|
||||
|
||||
class FieldCalculatorFeedback(QgsProcessingFeedback):
|
||||
"""
|
||||
Directs algorithm feedback to an algorithm dialog
|
||||
"""
|
||||
|
||||
def __init__(self, dialog):
|
||||
QgsProcessingFeedback.__init__(self)
|
||||
self.dialog = dialog
|
||||
|
||||
def reportError(self, msg, fatalError=False):
|
||||
self.dialog.error(msg)
|
||||
|
||||
|
||||
class FieldsCalculatorDialog(BASE, WIDGET):
|
||||
|
||||
def __init__(self, alg):
|
||||
super(FieldsCalculatorDialog, self).__init__(None)
|
||||
self.setupUi(self)
|
||||
|
||||
self.executed = False
|
||||
self._wasExecuted = False
|
||||
self.alg = alg
|
||||
self.layer = None
|
||||
|
||||
self.cmbInputLayer.setFilters(QgsMapLayerProxyModel.VectorLayer)
|
||||
try:
|
||||
if iface.activeLayer().type() == QgsMapLayerType.VectorLayer:
|
||||
self.cmbInputLayer.setLayer(iface.activeLayer())
|
||||
except:
|
||||
pass
|
||||
|
||||
self.cmbInputLayer.layerChanged.connect(self.updateLayer)
|
||||
self.btnBrowse.clicked.connect(self.selectFile)
|
||||
self.mNewFieldGroupBox.toggled.connect(self.toggleExistingGroup)
|
||||
self.mUpdateExistingGroupBox.toggled.connect(self.toggleNewGroup)
|
||||
self.mOutputFieldTypeComboBox.currentIndexChanged.connect(self.setupSpinboxes)
|
||||
|
||||
# Default values for field width and precision
|
||||
self.mOutputFieldWidthSpinBox.setValue(10)
|
||||
self.mOutputFieldPrecisionSpinBox.setValue(3)
|
||||
|
||||
# Output is a shapefile, so limit maximum field name length
|
||||
self.mOutputFieldNameLineEdit.setMaxLength(10)
|
||||
|
||||
self.manageGui()
|
||||
|
||||
def manageGui(self):
|
||||
if hasattr(self.leOutputFile, 'setPlaceholderText'):
|
||||
self.leOutputFile.setPlaceholderText(
|
||||
self.tr('[Save to temporary file]'))
|
||||
|
||||
self.mOutputFieldTypeComboBox.blockSignals(True)
|
||||
for t in self.alg.type_names:
|
||||
self.mOutputFieldTypeComboBox.addItem(t)
|
||||
self.mOutputFieldTypeComboBox.blockSignals(False)
|
||||
self.builder.loadRecent('fieldcalc')
|
||||
|
||||
self.updateLayer(self.cmbInputLayer.currentLayer())
|
||||
|
||||
def initContext(self):
|
||||
exp_context = self.builder.expressionContext()
|
||||
exp_context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(self.layer))
|
||||
exp_context.lastScope().setVariable("row_number", 1)
|
||||
exp_context.setHighlightedVariables(["row_number"])
|
||||
self.builder.setExpressionContext(exp_context)
|
||||
|
||||
def updateLayer(self, layer):
|
||||
self.layer = layer
|
||||
self.builder.setLayer(self.layer)
|
||||
self.initContext()
|
||||
self.populateFields()
|
||||
|
||||
def setupSpinboxes(self, index):
|
||||
if index != 0:
|
||||
self.mOutputFieldPrecisionSpinBox.setEnabled(False)
|
||||
else:
|
||||
self.mOutputFieldPrecisionSpinBox.setEnabled(True)
|
||||
|
||||
if index == 0:
|
||||
self.mOutputFieldWidthSpinBox.setRange(1, 20)
|
||||
self.mOutputFieldWidthSpinBox.setValue(10)
|
||||
self.mOutputFieldPrecisionSpinBox.setRange(0, 15)
|
||||
self.mOutputFieldPrecisionSpinBox.setValue(3)
|
||||
elif index == 1:
|
||||
self.mOutputFieldWidthSpinBox.setRange(1, 10)
|
||||
self.mOutputFieldWidthSpinBox.setValue(10)
|
||||
elif index == 2:
|
||||
self.mOutputFieldWidthSpinBox.setRange(1, 255)
|
||||
self.mOutputFieldWidthSpinBox.setValue(80)
|
||||
else:
|
||||
self.mOutputFieldWidthSpinBox.setEnabled(False)
|
||||
self.mOutputFieldPrecisionSpinBox.setEnabled(False)
|
||||
|
||||
def selectFile(self):
|
||||
output = self.alg.parameterDefinition('OUTPUT')
|
||||
fileFilter = output.createFileFilter()
|
||||
|
||||
settings = QgsSettings()
|
||||
if settings.contains('/Processing/LastOutputPath'):
|
||||
path = settings.value('/Processing/LastOutputPath')
|
||||
else:
|
||||
path = ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER)
|
||||
lastEncoding = settings.value('/Processing/encoding', 'System')
|
||||
fileDialog = QgsEncodingFileDialog(self,
|
||||
self.tr('Save file'),
|
||||
path,
|
||||
fileFilter,
|
||||
lastEncoding)
|
||||
fileDialog.setFileMode(QFileDialog.AnyFile)
|
||||
fileDialog.setAcceptMode(QFileDialog.AcceptSave)
|
||||
fileDialog.setOption(QFileDialog.DontConfirmOverwrite, False)
|
||||
if fileDialog.exec_() == QDialog.Accepted:
|
||||
files = fileDialog.selectedFiles()
|
||||
encoding = str(fileDialog.encoding())
|
||||
output.encoding = encoding
|
||||
filename = str(files[0])
|
||||
selectedFileFilter = str(fileDialog.selectedNameFilter())
|
||||
if not filename.lower().endswith(
|
||||
tuple(re.findall("\\*(\\.[a-z]{1,10})", fileFilter))):
|
||||
ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter)
|
||||
if ext:
|
||||
filename = filename + ext.group(1)
|
||||
self.leOutputFile.setText(filename)
|
||||
settings.setValue('/Processing/LastOutputPath',
|
||||
os.path.dirname(filename))
|
||||
settings.setValue('/Processing/encoding', encoding)
|
||||
|
||||
def toggleExistingGroup(self, toggled):
|
||||
self.mUpdateExistingGroupBox.setChecked(not toggled)
|
||||
|
||||
def toggleNewGroup(self, toggled):
|
||||
self.mNewFieldGroupBox.setChecked(not toggled)
|
||||
|
||||
def populateFields(self):
|
||||
if self.layer is None:
|
||||
return
|
||||
|
||||
self.mExistingFieldComboBox.clear()
|
||||
fields = self.layer.fields()
|
||||
for f in fields:
|
||||
self.mExistingFieldComboBox.addItem(f.name())
|
||||
|
||||
def getParamValues(self):
|
||||
if self.mUpdateExistingGroupBox.isChecked():
|
||||
fieldName = self.mExistingFieldComboBox.currentText()
|
||||
else:
|
||||
fieldName = self.mOutputFieldNameLineEdit.text()
|
||||
|
||||
layer = self.cmbInputLayer.currentLayer()
|
||||
|
||||
context = dataobjects.createContext()
|
||||
|
||||
parameters = {}
|
||||
parameters['INPUT'] = layer
|
||||
parameters['FIELD_NAME'] = fieldName
|
||||
parameters['FIELD_TYPE'] = self.mOutputFieldTypeComboBox.currentIndex()
|
||||
parameters['FIELD_LENGTH'] = self.mOutputFieldWidthSpinBox.value()
|
||||
parameters['FIELD_PRECISION'] = self.mOutputFieldPrecisionSpinBox.value()
|
||||
parameters['NEW_FIELD'] = self.mNewFieldGroupBox.isChecked()
|
||||
parameters['FORMULA'] = self.builder.expressionText()
|
||||
output = QgsProcessingOutputLayerDefinition()
|
||||
if self.leOutputFile.text().strip():
|
||||
output.sink = QgsProperty.fromValue(self.leOutputFile.text().strip())
|
||||
else:
|
||||
output.sink = QgsProperty.fromValue('memory:')
|
||||
output.destinationProject = context.project()
|
||||
parameters['OUTPUT'] = output
|
||||
|
||||
ok, msg = self.alg.checkParameterValues(parameters, context)
|
||||
if not ok:
|
||||
QMessageBox.warning(
|
||||
self, self.tr('Unable to execute algorithm'), msg)
|
||||
return {}
|
||||
return parameters
|
||||
|
||||
def accept(self):
|
||||
keepOpen = ProcessingConfig.getSetting(ProcessingConfig.KEEP_DIALOG_OPEN)
|
||||
parameters = self.getParamValues()
|
||||
if parameters:
|
||||
with OverrideCursor(Qt.WaitCursor):
|
||||
self.feedback = FieldCalculatorFeedback(self)
|
||||
self.feedback.progressChanged.connect(self.setPercentage)
|
||||
|
||||
context = dataobjects.createContext()
|
||||
ProcessingLog.addToLog(self.alg.asPythonCommand(parameters, context))
|
||||
QgsGui.instance().processingRecentAlgorithmLog().push(self.alg.id())
|
||||
|
||||
self.executed, results = execute(self.alg, parameters, context, self.feedback)
|
||||
self.setPercentage(0)
|
||||
|
||||
if self.executed:
|
||||
handleAlgorithmResults(self.alg,
|
||||
context,
|
||||
self.feedback,
|
||||
not keepOpen,
|
||||
parameters)
|
||||
self._wasExecuted = self.executed or self._wasExecuted
|
||||
if not keepOpen:
|
||||
QDialog.reject(self)
|
||||
|
||||
def reject(self):
|
||||
self.executed = False
|
||||
QDialog.reject(self)
|
||||
|
||||
def setPercentage(self, i):
|
||||
self.progressBar.setValue(i)
|
||||
|
||||
def error(self, text):
|
||||
QMessageBox.critical(self, "Error", text)
|
||||
QgsMessageLog.logMessage(text, self.tr('Processing'), Qgis.Critical)
|
||||
|
||||
def wasExecuted(self):
|
||||
return self._wasExecuted
|
@ -915,6 +915,22 @@ tests:
|
||||
name: expected/field_calculator_points.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:fieldcalculator
|
||||
name: Test field calculator points (new API)
|
||||
params:
|
||||
FIELD_LENGTH: 10
|
||||
FIELD_PRECISION: 3
|
||||
FIELD_TYPE: 0
|
||||
FORMULA: "\"id2\" *2"
|
||||
INPUT:
|
||||
name: points.gml
|
||||
type: vector
|
||||
NEW_FIELD_NAME: test
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/field_calculator_points.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:advancedpythonfieldcalculator
|
||||
name: Test advanced python calculator
|
||||
params:
|
||||
|
@ -72,6 +72,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmextractzmvalues.cpp
|
||||
processing/qgsalgorithmextractvertices.cpp
|
||||
processing/qgsalgorithmextractspecificvertices.cpp
|
||||
processing/qgsalgorithmfieldcalculator.cpp
|
||||
processing/qgsalgorithmfiledownloader.cpp
|
||||
processing/qgsalgorithmfillnodata.cpp
|
||||
processing/qgsalgorithmfilter.cpp
|
||||
|
225
src/analysis/processing/qgsalgorithmfieldcalculator.cpp
Normal file
225
src/analysis/processing/qgsalgorithmfieldcalculator.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmfieldcalculator.h
|
||||
----------------------
|
||||
begin : September 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "qgsalgorithmfieldcalculator.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "fieldcalculator" );
|
||||
}
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Field calculator" );
|
||||
}
|
||||
|
||||
QStringList QgsFieldCalculatorAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "field,calculator,vector" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector table" );
|
||||
}
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "vectortable" );
|
||||
}
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::outputName() const
|
||||
{
|
||||
return QObject::tr( "Calculated" );
|
||||
}
|
||||
|
||||
QList<int> QgsFieldCalculatorAlgorithm::inputLayerTypes() const
|
||||
{
|
||||
return QList<int>() << QgsProcessing::TypeVector;
|
||||
}
|
||||
|
||||
QgsProcessingFeatureSource::Flag QgsFieldCalculatorAlgorithm::sourceFlags() const
|
||||
{
|
||||
return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
|
||||
}
|
||||
|
||||
void QgsFieldCalculatorAlgorithm::initParameters( const QVariantMap &configuration )
|
||||
{
|
||||
Q_UNUSED( configuration );
|
||||
|
||||
QStringList fieldTypes = QStringList( {QObject::tr( "Float" ), QObject::tr( "Integer" ), QObject::tr( "String" ), QObject::tr( "Date" ) } );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterField > existingFieldName = qgis::make_unique< QgsProcessingParameterField > ( QStringLiteral( "EXISTING_FIELD_NAME" ), QObject::tr( "Result in existing field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true );
|
||||
std::unique_ptr< QgsProcessingParameterString > newFieldName = qgis::make_unique< QgsProcessingParameterString > ( QStringLiteral( "NEW_FIELD_NAME" ), QObject::tr( "Result in new field" ), QVariant(), false, true );
|
||||
std::unique_ptr< QgsProcessingParameterEnum > fieldType = qgis::make_unique< QgsProcessingParameterEnum > ( QStringLiteral( "FIELD_TYPE" ), QObject::tr( "Result field type" ), fieldTypes, false, 0 );
|
||||
std::unique_ptr< QgsProcessingParameterNumber > fieldLength = qgis::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_LENGTH" ), QObject::tr( "Result field length" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
|
||||
std::unique_ptr< QgsProcessingParameterNumber > fieldPrecision = qgis::make_unique< QgsProcessingParameterNumber > ( QStringLiteral( "FIELD_PRECISION" ), QObject::tr( "Result field precision" ), QgsProcessingParameterNumber::Integer, QVariant( 0 ), false, 0 );
|
||||
std::unique_ptr< QgsProcessingParameterExpression > expression = qgis::make_unique< QgsProcessingParameterExpression> ( QStringLiteral( "FORMULA" ), QObject::tr( "Formula" ), QVariant(), QStringLiteral( "INPUT" ), false );
|
||||
|
||||
expression->setMetadata( QVariantMap( {{"inlineEditor", true}} ) );
|
||||
|
||||
addParameter( existingFieldName.release() );
|
||||
addParameter( newFieldName.release() );
|
||||
addParameter( fieldType.release() );
|
||||
addParameter( fieldLength.release() );
|
||||
addParameter( fieldPrecision.release() );
|
||||
addParameter( expression.release() );
|
||||
}
|
||||
|
||||
QgsFields QgsFieldCalculatorAlgorithm::outputFields( const QgsFields & ) const
|
||||
{
|
||||
return mFields;
|
||||
}
|
||||
|
||||
QString QgsFieldCalculatorAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm computes a new vector layer with the same features of the input layer, "
|
||||
"but either overwriting an existing attribute or adding an additional attribute. The values of this field"
|
||||
"are computed from each feature using an expression, based on the properties and attributes of the feature."
|
||||
"Note that selecting a value in \"Result in existing field\" will ignore all the rest of the "
|
||||
"field settings." );
|
||||
}
|
||||
|
||||
QgsFieldCalculatorAlgorithm *QgsFieldCalculatorAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsFieldCalculatorAlgorithm();
|
||||
}
|
||||
|
||||
|
||||
bool QgsFieldCalculatorAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
|
||||
if ( !source )
|
||||
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
|
||||
|
||||
QList<QVariant::Type> fieldTypes( {QVariant::Double, QVariant::Int, QVariant::String, QVariant::Date} );
|
||||
|
||||
// prepare fields
|
||||
const int fieldTypeIdx = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
|
||||
const int fieldLength = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
|
||||
const int fieldPrecision = parameterAsInt( parameters, QStringLiteral( "FIELD_PRECISION" ), context );
|
||||
const QString existingFieldName = parameterAsString( parameters, QStringLiteral( "EXISTING_FIELD_NAME" ), context );
|
||||
const QString newFieldName = parameterAsString( parameters, QStringLiteral( "NEW_FIELD_NAME" ), context );
|
||||
|
||||
QVariant::Type fieldType = fieldTypes[fieldTypeIdx];
|
||||
|
||||
// this is to keep backwards compatibility, "NEW_FIELD" flags what how "FIELD_NAME" should be treated
|
||||
// since they are not defined parameters, they should be accessed directly from `parameters`
|
||||
bool isNewField = parameters.value( QStringLiteral( "NEW_FIELD" ) ).toBool();
|
||||
QString fieldName = parameters.value( QStringLiteral( "FIELD_NAME" ) ).toString();
|
||||
|
||||
// In a perfect universe there would be only "EXISTING_FIELD_NAME" and "NEW_FIELD_NAME"
|
||||
if ( !parameters.contains( QStringLiteral( "NEW_FIELD" ) ) )
|
||||
{
|
||||
isNewField = existingFieldName.isEmpty();
|
||||
fieldName = isNewField ? newFieldName : existingFieldName;
|
||||
}
|
||||
|
||||
if ( fieldName.isEmpty() )
|
||||
throw QgsProcessingException( QObject::tr( "Field name must not be an empty string" ) );
|
||||
|
||||
const QgsField field(
|
||||
fieldName,
|
||||
fieldType,
|
||||
QString(),
|
||||
fieldLength,
|
||||
fieldPrecision
|
||||
);
|
||||
|
||||
mFields = source->fields();
|
||||
|
||||
int fieldIdx = mFields.lookupField( field.name() );
|
||||
|
||||
if ( isNewField || fieldIdx < 0 )
|
||||
mFields.append( field );
|
||||
|
||||
QString dest;
|
||||
|
||||
mFieldIdx = mFields.lookupField( field.name() );
|
||||
|
||||
// prepare expression
|
||||
QString expressionString = parameterAsString( parameters, QStringLiteral( "FORMULA" ), context );
|
||||
mExpressionContext = createExpressionContext( parameters, context, source.get() );
|
||||
mExpression = QgsExpression( expressionString );
|
||||
mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
|
||||
mDa.setEllipsoid( context.ellipsoid() );
|
||||
|
||||
mExpression.setGeomCalculator( &mDa );
|
||||
mExpression.setDistanceUnits( context.distanceUnit() );
|
||||
mExpression.setAreaUnits( context.areaUnit() );
|
||||
|
||||
if ( mExpression.hasParserError() )
|
||||
throw QgsProcessingException( QObject::tr( "Parser error with formula expression \"%2\": %3" )
|
||||
.arg( expressionString, mExpression.parserErrorString() ) );
|
||||
|
||||
mExpression.prepare( &mExpressionContext );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsFeatureList QgsFieldCalculatorAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
|
||||
{
|
||||
QgsAttributes attributes( mFields.size() );
|
||||
const QStringList fieldNames = mFields.names();
|
||||
for ( const QString &fieldName : fieldNames )
|
||||
{
|
||||
const int attributeIndex = feature.fieldNameIndex( fieldName );
|
||||
|
||||
if ( attributeIndex >= 0 )
|
||||
attributes[attributeIndex] = feature.attribute( fieldName );
|
||||
}
|
||||
|
||||
if ( mExpression.isValid() )
|
||||
{
|
||||
mExpressionContext.setFeature( feature );
|
||||
mExpressionContext.lastScope()->setVariable( QStringLiteral( "row_number" ), mRowNumber );
|
||||
|
||||
const QVariant value = mExpression.evaluate( &mExpressionContext );
|
||||
|
||||
if ( mExpression.hasEvalError() )
|
||||
{
|
||||
throw QgsProcessingException( QObject::tr( "Evaluation error in expression \"%1\": %2" )
|
||||
.arg( mExpression.expression(), mExpression.evalErrorString() ) );
|
||||
}
|
||||
|
||||
attributes[mFieldIdx] = value;
|
||||
attributes.append( value );
|
||||
}
|
||||
else
|
||||
{
|
||||
attributes.append( QVariant() );
|
||||
}
|
||||
|
||||
QgsFeature f = feature;
|
||||
f.setAttributes( attributes );
|
||||
mRowNumber++;
|
||||
return QgsFeatureList() << f;
|
||||
}
|
||||
|
||||
bool QgsFieldCalculatorAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
|
||||
{
|
||||
Q_UNUSED( layer )
|
||||
return false;
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
68
src/analysis/processing/qgsalgorithmfieldcalculator.h
Normal file
68
src/analysis/processing/qgsalgorithmfieldcalculator.h
Normal file
@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmfieldcalculator.h
|
||||
----------------------
|
||||
begin : September 2020
|
||||
copyright : (C) 2020 by Ivan Ivanov
|
||||
email : ivan@opengis.ch
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef QGSALGORITHMFIELDSCALCULATOR_H
|
||||
#define QGSALGORITHMFIELDSCALCULATOR_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis_sip.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native field calculator algorithm.
|
||||
*/
|
||||
class QgsFieldCalculatorAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
QgsFieldCalculatorAlgorithm() = default;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
QStringList tags() const override;
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QString shortHelpString() const override;
|
||||
QList<int> inputLayerTypes() const override;
|
||||
QgsFieldCalculatorAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString outputName() const override;
|
||||
QgsFields outputFields( const QgsFields &inputFields ) const override;
|
||||
QgsProcessingFeatureSource::Flag sourceFlags() const override;
|
||||
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
bool supportInPlaceEdit( const QgsMapLayer *layer ) const override;
|
||||
|
||||
private:
|
||||
QgsFields mFields;
|
||||
int mFieldIdx;
|
||||
QgsExpression mExpression;
|
||||
QgsExpressionContext mExpressionContext;
|
||||
QgsDistanceArea mDa;
|
||||
int mRowNumber;
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMFIELDSCALCULATOR_H
|
@ -68,6 +68,7 @@
|
||||
#include "qgsalgorithmextractvertices.h"
|
||||
#include "qgsalgorithmextractspecificvertices.h"
|
||||
#include "qgsalgorithmextractzmvalues.h"
|
||||
#include "qgsalgorithmfieldcalculator.h"
|
||||
#include "qgsalgorithmfiledownloader.h"
|
||||
#include "qgsalgorithmfillnodata.h"
|
||||
#include "qgsalgorithmfilter.h"
|
||||
@ -292,6 +293,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsExtractVerticesAlgorithm() );
|
||||
addAlgorithm( new QgsExtractSpecificVerticesAlgorithm() );
|
||||
addAlgorithm( new QgsExtractZValuesAlgorithm() );
|
||||
addAlgorithm( new QgsFieldCalculatorAlgorithm() );
|
||||
addAlgorithm( new QgsFileDownloaderAlgorithm() );
|
||||
addAlgorithm( new QgsFillNoDataAlgorithm() );
|
||||
addAlgorithm( new QgsFilterAlgorithm() );
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "qgssettings.h"
|
||||
#include "qgsexpressionlineedit.h"
|
||||
#include "qgsfieldexpressionwidget.h"
|
||||
#include "qgsexpressionbuilderwidget.h"
|
||||
#include "qgsprocessingmultipleselectiondialog.h"
|
||||
#include "qgslayoutmanager.h"
|
||||
#include "qgsproject.h"
|
||||
@ -1943,15 +1944,30 @@ QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
|
||||
}
|
||||
else
|
||||
{
|
||||
mFieldExpWidget = new QgsFieldExpressionWidget();
|
||||
mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
|
||||
mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
|
||||
mFieldExpWidget->registerExpressionContextGenerator( this );
|
||||
connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
|
||||
if ( expParam->metadata().value( QStringLiteral( "inlineEditor" ) ).toBool() )
|
||||
{
|
||||
emit widgetValueHasChanged( this );
|
||||
} );
|
||||
return mFieldExpWidget;
|
||||
mExpBuilderWidget = new QgsExpressionBuilderWidget();
|
||||
mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
|
||||
mExpBuilderWidget->init( createExpressionContext() );
|
||||
connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [ = ]( bool changed )
|
||||
{
|
||||
Q_UNUSED( changed );
|
||||
emit widgetValueHasChanged( this );
|
||||
} );
|
||||
return mExpBuilderWidget;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFieldExpWidget = new QgsFieldExpressionWidget();
|
||||
mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
|
||||
mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
|
||||
mFieldExpWidget->registerExpressionContextGenerator( this );
|
||||
connect( mFieldExpWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString & ) >( &QgsFieldExpressionWidget::fieldChanged ), this, [ = ]( const QString & )
|
||||
{
|
||||
emit widgetValueHasChanged( this );
|
||||
} );
|
||||
return mFieldExpWidget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2005,6 +2021,8 @@ void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const Qgs
|
||||
{
|
||||
if ( mFieldExpWidget )
|
||||
mFieldExpWidget->setLayer( nullptr );
|
||||
else if ( mExpBuilderWidget )
|
||||
mExpBuilderWidget->setLayer( nullptr );
|
||||
else if ( mExpLineEdit )
|
||||
mExpLineEdit->setLayer( nullptr );
|
||||
return;
|
||||
@ -2025,6 +2043,8 @@ void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const Qgs
|
||||
|
||||
if ( mFieldExpWidget )
|
||||
mFieldExpWidget->setLayer( layer );
|
||||
if ( mExpBuilderWidget )
|
||||
mExpBuilderWidget->setLayer( layer );
|
||||
else if ( mExpLineEdit )
|
||||
mExpLineEdit->setLayer( layer );
|
||||
}
|
||||
@ -2034,6 +2054,8 @@ void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value
|
||||
const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
|
||||
if ( mFieldExpWidget )
|
||||
mFieldExpWidget->setExpression( v );
|
||||
else if ( mExpBuilderWidget )
|
||||
mExpBuilderWidget->setExpressionText( v );
|
||||
else if ( mExpLineEdit )
|
||||
mExpLineEdit->setExpression( v );
|
||||
}
|
||||
@ -2042,6 +2064,8 @@ QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
|
||||
{
|
||||
if ( mFieldExpWidget )
|
||||
return mFieldExpWidget->expression();
|
||||
if ( mExpBuilderWidget )
|
||||
return mExpBuilderWidget->expressionText();
|
||||
else if ( mExpLineEdit )
|
||||
return mExpLineEdit->expression();
|
||||
else
|
||||
@ -2076,6 +2100,9 @@ const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer()
|
||||
if ( mFieldExpWidget && mFieldExpWidget->layer() )
|
||||
return mFieldExpWidget->layer();
|
||||
|
||||
if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
|
||||
return mExpBuilderWidget->layer();
|
||||
|
||||
return QgsAbstractProcessingParameterWidgetWrapper::linkedVectorLayer();
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ class QgsAuthConfigSelect;
|
||||
class QgsProcessingMatrixParameterPanel;
|
||||
class QgsFileWidget;
|
||||
class QgsFieldExpressionWidget;
|
||||
class QgsExpressionBuilderWidget;
|
||||
class QgsExpressionLineEdit;
|
||||
class QgsProcessingParameterEnum;
|
||||
class QgsLayoutComboBox;
|
||||
@ -677,6 +678,7 @@ class GUI_EXPORT QgsProcessingExpressionWidgetWrapper : public QgsAbstractProces
|
||||
private:
|
||||
|
||||
QgsFieldExpressionWidget *mFieldExpWidget = nullptr;
|
||||
QgsExpressionBuilderWidget *mExpBuilderWidget = nullptr;
|
||||
QgsExpressionLineEdit *mExpLineEdit = nullptr;
|
||||
std::unique_ptr< QgsVectorLayer > mParentLayer;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user