Skip to content

Commit 4f4b831

Browse files
authoredMar 1, 2018
Merge pull request #6504 from m-kuhn/processingParametersRegistry
More processing parameters in modeller
2 parents 9e955ce + b67813b commit 4f4b831

File tree

12 files changed

+347
-165
lines changed

12 files changed

+347
-165
lines changed
 

‎python/core/processing/qgsprocessingprovider.sip.in

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,17 @@ Returns the matching algorithm by ``name``, or a None if no matching
204204
algorithm is contained by this provider.
205205

206206
.. seealso:: :py:func:`algorithms`
207+
%End
208+
209+
virtual QgsProcessingParameterDefinition *createParameter( const QString &type, const QString &name ) /Factory/;
210+
%Docstring
211+
Returns a new parameter from of the given type and name.
212+
This should be reimplemented by providers that implement custom types.
213+
If the provider does not implement the parameter with ``type``, a None will be returned.
214+
215+
By default, this returns a None.
216+
217+
.. versionadded:: 3.2
207218
%End
208219

209220
signals:

‎python/plugins/processing/algs/qgis/FieldsMapper.py

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -54,49 +54,8 @@ def tags(self):
5454
return self.tr('attributes,table').split(',')
5555

5656
def initParameters(self, config=None):
57-
58-
class ParameterFieldsMapping(QgsProcessingParameterDefinition):
59-
60-
def __init__(self, name, description, parentLayerParameterName='INPUT'):
61-
super().__init__(name, description)
62-
self._parentLayerParameter = parentLayerParameterName
63-
64-
def clone(self):
65-
copy = ParameterFieldsMapping(self.name(), self.description(), self._parentLayerParameter)
66-
return copy
67-
68-
def type(self):
69-
return 'fields_mapping'
70-
71-
def checkValueIsAcceptable(self, value, context=None):
72-
if not isinstance(value, list):
73-
return False
74-
for field_def in value:
75-
if not isinstance(field_def, dict):
76-
return False
77-
if 'name' not in field_def.keys():
78-
return False
79-
if 'type' not in field_def.keys():
80-
return False
81-
if 'expression' not in field_def.keys():
82-
return False
83-
return True
84-
85-
def valueAsPythonString(self, value, context):
86-
return str(value)
87-
88-
def asScriptCode(self):
89-
raise NotImplementedError()
90-
91-
@classmethod
92-
def fromScriptCode(cls, name, description, isOptional, definition):
93-
raise NotImplementedError()
94-
95-
def parentLayerParameter(self):
96-
return self._parentLayerParameter
97-
98-
fields_mapping = ParameterFieldsMapping(self.FIELDS_MAPPING,
99-
description=self.tr('Fields mapping'))
57+
fields_mapping = FieldsMapper.ParameterFieldsMapping(self.FIELDS_MAPPING,
58+
description=self.tr('Fields mapping'))
10059
fields_mapping.setMetadata({
10160
'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'
10261
})
@@ -181,3 +140,47 @@ def processFeature(self, feature, context, feedback):
181140
feature.setAttributes(attributes)
182141
self._row_number += 1
183142
return [feature]
143+
144+
class ParameterFieldsMapping(QgsProcessingParameterDefinition):
145+
146+
def __init__(self, name, description='', parentLayerParameterName='INPUT'):
147+
super().__init__(name, description)
148+
self._parentLayerParameter = parentLayerParameterName
149+
150+
def clone(self):
151+
copy = FieldsMapper.ParameterFieldsMapping(self.name(), self.description(), self._parentLayerParameter)
152+
return copy
153+
154+
def type(self):
155+
return self.typeName()
156+
157+
@staticmethod
158+
def typeName():
159+
return 'fields_mapping'
160+
161+
def checkValueIsAcceptable(self, value, context=None):
162+
if not isinstance(value, list):
163+
return False
164+
for field_def in value:
165+
if not isinstance(field_def, dict):
166+
return False
167+
if 'name' not in field_def.keys():
168+
return False
169+
if 'type' not in field_def.keys():
170+
return False
171+
if 'expression' not in field_def.keys():
172+
return False
173+
return True
174+
175+
def valueAsPythonString(self, value, context):
176+
return str(value)
177+
178+
def asScriptCode(self):
179+
raise NotImplementedError()
180+
181+
@classmethod
182+
def fromScriptCode(cls, name, description, isOptional, definition):
183+
raise NotImplementedError()
184+
185+
def parentLayerParameter(self):
186+
return self._parentLayerParameter

‎python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
from qgis.core import (QgsApplication,
3737
QgsProcessingProvider)
3838

39+
from PyQt5.QtCore import QCoreApplication
40+
3941
from processing.script import ScriptUtils
4042

4143
from .QgisAlgorithm import QgisAlgorithm
@@ -154,6 +156,7 @@
154156

155157

156158
class QgisAlgorithmProvider(QgsProcessingProvider):
159+
fieldMappingParameterName = QCoreApplication.translate('Processing', 'Fields Mapper')
157160

158161
def __init__(self):
159162
super().__init__()
@@ -317,5 +320,29 @@ def loadAlgorithms(self):
317320
for a in self.externalAlgs:
318321
self.addAlgorithm(a)
319322

323+
def load(self):
324+
success = super().load()
325+
326+
from processing.core.Processing import Processing
327+
328+
if success:
329+
Processing.registerParameter(
330+
'Fields Mapper',
331+
self.fieldMappingParameterName,
332+
parameter=FieldsMapper.ParameterFieldsMapping,
333+
metadata={'widget_wrapper': 'processing.algs.qgis.ui.FieldsMappingPanel.FieldsMappingWidgetWrapper'}
334+
)
335+
336+
return success
337+
338+
def unload(self):
339+
super().unload()
340+
from processing.core.Processing import Processing
341+
Processing.unregisterParameter(self.fieldMappingParameterName)
342+
343+
def createParameter(self, type, name):
344+
if type == 'fields_mapping':
345+
return FieldsMapper.ParameterFieldsMapping(name)
346+
320347
def supportsNonFileBasedOutput(self):
321348
return True

‎python/plugins/processing/algs/qgis/ui/FieldsMappingPanel.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
QVariant,
3737
Qt,
3838
pyqtSlot,
39+
QCoreApplication
3940
)
4041
from qgis.PyQt.QtWidgets import (
4142
QComboBox,
@@ -45,6 +46,8 @@
4546
QMessageBox,
4647
QSpinBox,
4748
QStyledItemDelegate,
49+
QWidget,
50+
QVBoxLayout
4851
)
4952

5053
from qgis.core import (
@@ -58,8 +61,9 @@
5861
)
5962
from qgis.gui import QgsFieldExpressionWidget
6063

61-
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_MODELER
64+
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD, DIALOG_MODELER, DIALOG_BATCH
6265
from processing.tools import dataobjects
66+
from processing.algs.qgis.FieldsMapper import FieldsMapper
6367

6468

6569
pluginPath = os.path.dirname(__file__)
@@ -141,7 +145,10 @@ def columnCount(self, parent=QModelIndex()):
141145
def rowCount(self, parent=QModelIndex()):
142146
if parent.isValid():
143147
return 0
144-
return self._mapping.__len__()
148+
try:
149+
return len(self._mapping)
150+
except TypeError:
151+
return 0
145152

146153
def headerData(self, section, orientation, role=Qt.DisplayRole):
147154
if role == Qt.DisplayRole:
@@ -473,9 +480,31 @@ def __init__(self, *args, **kwargs):
473480
self._layer = None
474481

475482
def createWidget(self):
476-
panel = FieldsMappingPanel()
477-
panel.dialogType = self.dialogType
478-
return panel
483+
self.panel = FieldsMappingPanel()
484+
self.panel.dialogType = self.dialogType
485+
486+
if self.dialogType == DIALOG_MODELER:
487+
self.combobox = QComboBox()
488+
self.combobox.addItem(QCoreApplication.translate('Processing', '[Preconfigure]'), None)
489+
fieldsMappingInputs = self.dialog.getAvailableValuesOfType(FieldsMapper.ParameterFieldsMapping)
490+
for input in fieldsMappingInputs:
491+
self.combobox.addItem(self.dialog.resolveValueDescription(input), input)
492+
493+
def updatePanelEnabledState():
494+
if self.combobox.currentData() is None:
495+
self.panel.setEnabled(True)
496+
else:
497+
self.panel.setEnabled(False)
498+
499+
self.combobox.currentIndexChanged.connect(updatePanelEnabledState)
500+
501+
widget = QWidget()
502+
widget.setLayout(QVBoxLayout())
503+
widget.layout().addWidget(self.combobox)
504+
widget.layout().addWidget(self.panel)
505+
return widget
506+
else:
507+
return self.panel
479508

480509
def postInitialize(self, wrappers):
481510
for wrapper in wrappers:
@@ -506,10 +535,16 @@ def setLayer(self, layer):
506535
if not isinstance(layer, QgsVectorLayer):
507536
layer = None
508537
self._layer = layer
509-
self.widget.setLayer(self._layer)
538+
self.panel.setLayer(self._layer)
510539

511540
def setValue(self, value):
512-
self.widget.setValue(value)
541+
self.panel.setValue(value)
513542

514543
def value(self):
515-
return self.widget.value()
544+
if self.dialogType == DIALOG_MODELER:
545+
if self.combobox.currentData() is None:
546+
return self.panel.value()
547+
else:
548+
return self.comboValue(combobox=self.combobox)
549+
else:
550+
return self.panel.value()

‎python/plugins/processing/core/Processing.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
QgsProcessingOutputMapLayer,
4646
QgsProcessingOutputMultipleLayers)
4747

48+
from .parameters import initializeParameters
49+
4850
import processing
4951
from processing.core.ProcessingConfig import ProcessingConfig
5052
from processing.gui.MessageBarProgress import MessageBarProgress
@@ -67,6 +69,7 @@
6769

6870
class Processing(object):
6971
BASIC_PROVIDERS = []
72+
REGISTERED_PARAMETERS = dict()
7073

7174
@staticmethod
7275
def activateProvider(providerOrName, activate=True):
@@ -97,6 +100,7 @@ def initialize():
97100
if QgsApplication.processingRegistry().addProvider(p):
98101
Processing.BASIC_PROVIDERS.append(p)
99102
# And initialize
103+
initializeParameters()
100104
ProcessingConfig.initialize()
101105
ProcessingConfig.readSettings()
102106
RenderingStyles.loadStyles()
@@ -107,6 +111,40 @@ def deinitialize():
107111
QgsApplication.processingRegistry().removeProvider(p)
108112

109113
Processing.BASIC_PROVIDERS = []
114+
Processing.REGISTERED_PARAMETERS = dict()
115+
116+
@staticmethod
117+
def registerParameter(id, name, parameter, metadata=dict(), description=None, exposeToModeller=True):
118+
"""Register a new parameter.
119+
The ``name`` is a human readable translated string, the ``parameter`` is a class type with the base class ``qgis.core.QgsProcessingParameterDefinition``,
120+
the ``metadata`` is a dictionary with additional metadata, mainly used for widget wrappers.
121+
"""
122+
Processing.REGISTERED_PARAMETERS[id] = {
123+
'name': name,
124+
'parameter': parameter,
125+
'metadata': metadata,
126+
'description': description,
127+
'exposeToModeller': exposeToModeller
128+
}
129+
130+
@staticmethod
131+
def unregisterParameter(name):
132+
"""Unregister a registered parameter with the given name.
133+
"""
134+
del Processing.REGISTERED_PARAMETERS[name]
135+
136+
@staticmethod
137+
def registeredParameters():
138+
"""Returns a dict of registered parameters. The key of the dict is the id of the parameter.
139+
Each entry is itself a dict with the keys
140+
141+
- name: The human readable name of the parameter
142+
- parameter: The class of the parameter
143+
- metadata: Additional metadata for the parameter, mainly used for widget wrappers
144+
- description: A longer description for the parameter, suitable for tooltips etc
145+
- exposeToModeller: A boolean indicating if the parameter is available as model parameter input
146+
"""
147+
return Processing.REGISTERED_PARAMETERS
110148

111149
@staticmethod
112150
def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=None):

0 commit comments

Comments
 (0)