mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-10-31 00:06:02 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			1858 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1858 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| """
 | |
| ***************************************************************************
 | |
|     wrappers.py - Standard parameters widget wrappers
 | |
|     ---------------------
 | |
|     Date                 : May 2016
 | |
|     Copyright            : (C) 2016 by Arnaud Morvan, Victor Olaya
 | |
|     Email                : arnaud dot morvan at camptocamp dot com
 | |
|                            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__ = 'Arnaud Morvan'
 | |
| __date__ = 'May 2016'
 | |
| __copyright__ = '(C) 2016, Arnaud Morvan'
 | |
| 
 | |
| import locale
 | |
| import os
 | |
| import re
 | |
| from functools import cmp_to_key
 | |
| from inspect import isclass
 | |
| from copy import deepcopy
 | |
| 
 | |
| from qgis.core import (
 | |
|     QgsApplication,
 | |
|     QgsUnitTypes,
 | |
|     QgsCoordinateReferenceSystem,
 | |
|     QgsExpression,
 | |
|     QgsExpressionContextGenerator,
 | |
|     QgsFieldProxyModel,
 | |
|     QgsMapLayerProxyModel,
 | |
|     QgsWkbTypes,
 | |
|     QgsSettings,
 | |
|     QgsProject,
 | |
|     QgsMapLayer,
 | |
|     QgsMapLayerType,
 | |
|     QgsVectorLayer,
 | |
|     QgsProcessing,
 | |
|     QgsProcessingUtils,
 | |
|     QgsProcessingParameterDefinition,
 | |
|     QgsProcessingParameterBoolean,
 | |
|     QgsProcessingParameterCrs,
 | |
|     QgsProcessingParameterExtent,
 | |
|     QgsProcessingParameterPoint,
 | |
|     QgsProcessingParameterFile,
 | |
|     QgsProcessingParameterMultipleLayers,
 | |
|     QgsProcessingParameterNumber,
 | |
|     QgsProcessingParameterDistance,
 | |
|     QgsProcessingParameterRasterLayer,
 | |
|     QgsProcessingParameterEnum,
 | |
|     QgsProcessingParameterString,
 | |
|     QgsProcessingParameterExpression,
 | |
|     QgsProcessingParameterVectorLayer,
 | |
|     QgsProcessingParameterMeshLayer,
 | |
|     QgsProcessingParameterField,
 | |
|     QgsProcessingParameterFeatureSource,
 | |
|     QgsProcessingParameterMapLayer,
 | |
|     QgsProcessingParameterBand,
 | |
|     QgsProcessingParameterMatrix,
 | |
|     QgsProcessingParameterDistance,
 | |
|     QgsProcessingFeatureSourceDefinition,
 | |
|     QgsProcessingOutputRasterLayer,
 | |
|     QgsProcessingOutputVectorLayer,
 | |
|     QgsProcessingOutputMapLayer,
 | |
|     QgsProcessingOutputMultipleLayers,
 | |
|     QgsProcessingOutputFile,
 | |
|     QgsProcessingOutputString,
 | |
|     QgsProcessingOutputNumber,
 | |
|     QgsProcessingModelChildParameterSource,
 | |
|     QgsProcessingModelAlgorithm,
 | |
|     QgsRasterDataProvider,
 | |
|     NULL,
 | |
|     Qgis)
 | |
| 
 | |
| from qgis.PyQt.QtWidgets import (
 | |
|     QCheckBox,
 | |
|     QComboBox,
 | |
|     QLabel,
 | |
|     QDialog,
 | |
|     QFileDialog,
 | |
|     QHBoxLayout,
 | |
|     QVBoxLayout,
 | |
|     QLineEdit,
 | |
|     QPlainTextEdit,
 | |
|     QToolButton,
 | |
|     QWidget,
 | |
| )
 | |
| from qgis.gui import (
 | |
|     QgsGui,
 | |
|     QgsExpressionLineEdit,
 | |
|     QgsExpressionBuilderDialog,
 | |
|     QgsFieldComboBox,
 | |
|     QgsFieldExpressionWidget,
 | |
|     QgsProjectionSelectionDialog,
 | |
|     QgsMapLayerComboBox,
 | |
|     QgsProjectionSelectionWidget,
 | |
|     QgsRasterBandComboBox,
 | |
|     QgsProcessingGui,
 | |
|     QgsAbstractProcessingParameterWidgetWrapper,
 | |
|     QgsProcessingMapLayerComboBox
 | |
| )
 | |
| from qgis.PyQt.QtCore import pyqtSignal, QObject, QVariant, Qt
 | |
| from qgis.utils import iface
 | |
| 
 | |
| from processing.core.ProcessingConfig import ProcessingConfig
 | |
| from processing.modeler.MultilineTextPanel import MultilineTextPanel
 | |
| 
 | |
| from processing.gui.NumberInputPanel import NumberInputPanel, ModelerNumberInputPanel, DistanceInputPanel
 | |
| from processing.gui.RangePanel import RangePanel
 | |
| from processing.gui.PointSelectionPanel import PointSelectionPanel
 | |
| from processing.gui.FileSelectionPanel import FileSelectionPanel
 | |
| from processing.gui.CheckboxesPanel import CheckboxesPanel
 | |
| from processing.gui.MultipleInputPanel import MultipleInputPanel
 | |
| from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
 | |
| from processing.gui.FixedTablePanel import FixedTablePanel
 | |
| from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel
 | |
| from processing.gui.ParameterGuiUtils import getFileFilter
 | |
| 
 | |
| from processing.tools import dataobjects
 | |
| 
 | |
| DIALOG_STANDARD = QgsProcessingGui.Standard
 | |
| DIALOG_BATCH = QgsProcessingGui.Batch
 | |
| DIALOG_MODELER = QgsProcessingGui.Modeler
 | |
| 
 | |
| 
 | |
| class InvalidParameterValue(Exception):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| dialogTypes = {"AlgorithmDialog": DIALOG_STANDARD,
 | |
|                "ModelerParametersDialog": DIALOG_MODELER,
 | |
|                "BatchAlgorithmDialog": DIALOG_BATCH}
 | |
| 
 | |
| 
 | |
| def getExtendedLayerName(layer):
 | |
|     authid = layer.crs().authid()
 | |
|     if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) and authid is not None:
 | |
|         return u'{} [{}]'.format(layer.name(), authid)
 | |
|     else:
 | |
|         return layer.name()
 | |
| 
 | |
| 
 | |
| class WidgetWrapper(QgsAbstractProcessingParameterWidgetWrapper):
 | |
| 
 | |
|     NOT_SET_OPTION = '~~~~!!!!NOT SET!!!!~~~~~~~'
 | |
| 
 | |
|     def __init__(self, param, dialog, row=0, col=0, **kwargs):
 | |
|         self.dialogType = dialogTypes.get(dialog.__class__.__name__, QgsProcessingGui.Standard)
 | |
|         super().__init__(param, self.dialogType)
 | |
| 
 | |
|         self.dialog = dialog
 | |
|         self.row = row
 | |
|         self.col = col
 | |
| 
 | |
|         self.widget = self.createWidget(**kwargs)
 | |
|         self.label = self.createLabel()
 | |
|         if param.defaultValue() is not None:
 | |
|             self.setValue(param.defaultValue())
 | |
| 
 | |
|     def comboValue(self, validator=None, combobox=None):
 | |
|         if combobox is None:
 | |
|             combobox = self.widget
 | |
|         idx = combobox.findText(combobox.currentText())
 | |
|         if idx < 0:
 | |
|             v = combobox.currentText().strip()
 | |
|             if validator is not None and not validator(v):
 | |
|                 raise InvalidParameterValue()
 | |
|             return v
 | |
|         if combobox.currentData() == self.NOT_SET_OPTION:
 | |
|             return None
 | |
|         elif combobox.currentData() is not None:
 | |
|             return combobox.currentData()
 | |
|         else:
 | |
|             return combobox.currentText()
 | |
| 
 | |
|     def createWidget(self, **kwargs):
 | |
|         pass
 | |
| 
 | |
|     def createLabel(self):
 | |
|         if self.dialogType == DIALOG_BATCH:
 | |
|             return None
 | |
|         desc = self.parameterDefinition().description()
 | |
|         if isinstance(self.parameterDefinition(), QgsProcessingParameterExtent):
 | |
|             desc += self.tr(' (xmin, xmax, ymin, ymax)')
 | |
|         if isinstance(self.parameterDefinition(), QgsProcessingParameterPoint):
 | |
|             desc += self.tr(' (x, y)')
 | |
|         if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|             desc += self.tr(' [optional]')
 | |
| 
 | |
|         label = QLabel(desc)
 | |
|         label.setToolTip(self.parameterDefinition().name())
 | |
|         return label
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         pass
 | |
| 
 | |
|     def value(self):
 | |
|         return None
 | |
| 
 | |
|     def widgetValue(self):
 | |
|         return self.value()
 | |
| 
 | |
|     def setWidgetValue(self, value, context):
 | |
|         self.setValue(value)
 | |
| 
 | |
|     def setComboValue(self, value, combobox=None):
 | |
|         if combobox is None:
 | |
|             combobox = self.widget
 | |
|         if isinstance(value, list):
 | |
|             if value:
 | |
|                 value = value[0]
 | |
|             else:
 | |
|                 value = None
 | |
|         values = [combobox.itemData(i) for i in range(combobox.count())]
 | |
|         try:
 | |
|             idx = values.index(value)
 | |
|             combobox.setCurrentIndex(idx)
 | |
|             return
 | |
|         except ValueError:
 | |
|             pass
 | |
|         if combobox.isEditable():
 | |
|             if value is not None:
 | |
|                 combobox.setEditText(str(value))
 | |
|         else:
 | |
|             combobox.setCurrentIndex(0)
 | |
| 
 | |
|     def refresh(self):
 | |
|         pass
 | |
| 
 | |
|     def getFileName(self, initial_value=''):
 | |
|         """Shows a file open dialog"""
 | |
|         settings = QgsSettings()
 | |
|         if os.path.isdir(initial_value):
 | |
|             path = initial_value
 | |
|         elif os.path.isdir(os.path.dirname(initial_value)):
 | |
|             path = os.path.dirname(initial_value)
 | |
|         elif settings.contains('/Processing/LastInputPath'):
 | |
|             path = str(settings.value('/Processing/LastInputPath'))
 | |
|         else:
 | |
|             path = ''
 | |
| 
 | |
|         # TODO: should use selectedFilter argument for default file format
 | |
|         filename, selected_filter = QFileDialog.getOpenFileName(self.widget, self.tr('Select File'),
 | |
|                                                                 path, getFileFilter(self.parameterDefinition()))
 | |
|         if filename:
 | |
|             settings.setValue('/Processing/LastInputPath',
 | |
|                               os.path.dirname(str(filename)))
 | |
|         return filename, selected_filter
 | |
| 
 | |
| 
 | |
| class BasicWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def createWidget(self):
 | |
|         return QLineEdit()
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         self.widget.setText(value)
 | |
| 
 | |
|     def value(self):
 | |
|         return self.widget.text()
 | |
| 
 | |
| 
 | |
| class BooleanWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("BooleanWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createLabel(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return None
 | |
|         else:
 | |
|             return super().createLabel()
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return QCheckBox()
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = QComboBox()
 | |
|             widget.addItem(self.tr('Yes'), True)
 | |
|             widget.addItem(self.tr('No'), False)
 | |
|             return widget
 | |
|         else:
 | |
|             widget = QComboBox()
 | |
|             widget.addItem(self.tr('Yes'), True)
 | |
|             widget.addItem(self.tr('No'), False)
 | |
|             bools = self.dialog.getAvailableValuesOfType(QgsProcessingParameterBoolean, None)
 | |
|             for b in bools:
 | |
|                 widget.addItem(self.dialog.resolveValueDescription(b), b)
 | |
|             return widget
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             self.widget.setChecked(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return self.widget.isChecked()
 | |
|         else:
 | |
|             return self.comboValue()
 | |
| 
 | |
| 
 | |
| class CrsWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("CrsWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_MODELER:
 | |
|             self.combo = QComboBox()
 | |
|             widget = QWidget()
 | |
|             layout = QHBoxLayout()
 | |
|             layout.setMargin(0)
 | |
|             layout.setContentsMargins(0, 0, 0, 0)
 | |
|             layout.setSpacing(1)
 | |
|             layout.addWidget(self.combo)
 | |
|             btn = QToolButton()
 | |
|             btn.setIcon(QgsApplication.getThemeIcon("mActionSetProjection.svg"))
 | |
|             btn.setToolTip(self.tr("Select CRS"))
 | |
|             btn.clicked.connect(self.selectProjection)
 | |
|             layout.addWidget(btn)
 | |
| 
 | |
|             widget.setLayout(layout)
 | |
|             self.combo.setEditable(True)
 | |
|             crss = self.dialog.getAvailableValuesOfType((QgsProcessingParameterCrs, QgsProcessingParameterString), QgsProcessingOutputString)
 | |
|             for crs in crss:
 | |
|                 self.combo.addItem(self.dialog.resolveValueDescription(crs), crs)
 | |
|             layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterRasterLayer,
 | |
|                                                            QgsProcessingParameterVectorLayer,
 | |
|                                                            QgsProcessingParameterMeshLayer,
 | |
|                                                            QgsProcessingParameterFeatureSource],
 | |
|                                                           [QgsProcessingOutputVectorLayer,
 | |
|                                                            QgsProcessingOutputRasterLayer,
 | |
|                                                            QgsProcessingOutputMapLayer])
 | |
|             for l in layers:
 | |
|                 self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(l), l)
 | |
|             if self.parameterDefinition().defaultValue():
 | |
|                 self.combo.setEditText(self.parameterDefinition().defaultValue())
 | |
|             return widget
 | |
|         else:
 | |
|             widget = QgsProjectionSelectionWidget()
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)
 | |
| 
 | |
|             if self.parameterDefinition().defaultValue():
 | |
|                 if self.parameterDefinition().defaultValue() == 'ProjectCrs':
 | |
|                     crs = QgsProject.instance().crs()
 | |
|                 else:
 | |
|                     crs = QgsCoordinateReferenceSystem(self.parameterDefinition().defaultValue())
 | |
|                 widget.setCrs(crs)
 | |
|             else:
 | |
|                 widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)
 | |
| 
 | |
|             widget.crsChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
| 
 | |
|     def selectProjection(self):
 | |
|         dialog = QgsProjectionSelectionDialog(self.widget)
 | |
|         current_crs = QgsCoordinateReferenceSystem(self.combo.currentText())
 | |
|         if current_crs.isValid():
 | |
|             dialog.setCrs(current_crs)
 | |
| 
 | |
|         if dialog.exec_():
 | |
|             self.setValue(dialog.crs().authid())
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_MODELER:
 | |
|             self.setComboValue(value, self.combo)
 | |
|         elif value == 'ProjectCrs':
 | |
|             self.widget.setCrs(QgsProject.instance().crs())
 | |
|         else:
 | |
|             self.widget.setCrs(QgsCoordinateReferenceSystem(value))
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_MODELER:
 | |
|             return self.comboValue(combobox=self.combo)
 | |
|         else:
 | |
|             crs = self.widget.crs()
 | |
|             if crs.isValid():
 | |
|                 return self.widget.crs().authid()
 | |
|             else:
 | |
|                 return None
 | |
| 
 | |
| 
 | |
| class ExtentWidgetWrapper(WidgetWrapper):
 | |
|     USE_MIN_COVERING_EXTENT = "[Use min covering extent]"
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             widget = ExtentSelectionPanel(self.dialog, self.parameterDefinition())
 | |
|             widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             widget = QComboBox()
 | |
|             widget.setEditable(True)
 | |
|             extents = self.dialog.getAvailableValuesOfType(QgsProcessingParameterExtent, (QgsProcessingOutputString))
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 widget.addItem(self.USE_MIN_COVERING_EXTENT, None)
 | |
|             layers = self.dialog.getAvailableValuesOfType([QgsProcessingParameterFeatureSource,
 | |
|                                                            QgsProcessingParameterRasterLayer,
 | |
|                                                            QgsProcessingParameterVectorLayer,
 | |
|                                                            QgsProcessingParameterMeshLayer],
 | |
|                                                           [QgsProcessingOutputRasterLayer,
 | |
|                                                            QgsProcessingOutputVectorLayer,
 | |
|                                                            QgsProcessingOutputMapLayer])
 | |
|             for ex in extents:
 | |
|                 widget.addItem(self.dialog.resolveValueDescription(ex), ex)
 | |
|             for l in layers:
 | |
|                 widget.addItem("Extent of " + self.dialog.resolveValueDescription(l), l)
 | |
|             if not self.parameterDefinition().defaultValue():
 | |
|                 widget.setEditText(self.parameterDefinition().defaultValue())
 | |
|             return widget
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self.widget.setExtentFromString(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             idx = self.widget.findText(self.widget.currentText())
 | |
|             if idx < 0:
 | |
|                 s = str(self.widget.currentText()).strip()
 | |
|                 if s:
 | |
|                     try:
 | |
|                         tokens = s.split(',')
 | |
|                         if len(tokens) != 4:
 | |
|                             raise InvalidParameterValue()
 | |
|                         for token in tokens:
 | |
|                             float(token)
 | |
|                     except:
 | |
|                         raise InvalidParameterValue()
 | |
|                 elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                     s = None
 | |
|                 else:
 | |
|                     raise InvalidParameterValue()
 | |
|                 return s
 | |
|             else:
 | |
|                 return self.widget.currentData()
 | |
| 
 | |
| 
 | |
| class PointWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("PointWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return PointSelectionPanel(self.dialog, self.parameterDefinition().defaultValue())
 | |
|         else:
 | |
|             item = QComboBox()
 | |
|             item.setEditable(True)
 | |
|             points = self.dialog.getAvailableValuesOfType((QgsProcessingParameterPoint, QgsProcessingParameterString), (QgsProcessingOutputString))
 | |
|             for p in points:
 | |
|                 item.addItem(self.dialog.resolveValueDescription(p), p)
 | |
|             item.setEditText(str(self.parameterDefinition().defaultValue()))
 | |
|             return item
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self.widget.setPointFromString(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             idx = self.widget.findText(self.widget.currentText())
 | |
|             if idx < 0:
 | |
|                 s = str(self.widget.currentText()).strip()
 | |
|                 if s:
 | |
|                     try:
 | |
|                         tokens = s.split(',')
 | |
|                         if len(tokens) != 2:
 | |
|                             raise InvalidParameterValue()
 | |
|                         for token in tokens:
 | |
|                             float(token)
 | |
|                     except:
 | |
|                         raise InvalidParameterValue()
 | |
|                 elif self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                     s = None
 | |
|                 else:
 | |
|                     raise InvalidParameterValue()
 | |
|                 return s
 | |
|             else:
 | |
|                 return self.widget.currentData()
 | |
| 
 | |
| 
 | |
| class FileWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("FileWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return FileSelectionPanel(self.parameterDefinition().behavior() == QgsProcessingParameterFile.Folder,
 | |
|                                       self.parameterDefinition().extension())
 | |
|         else:
 | |
|             self.combo = QComboBox()
 | |
|             self.combo.setEditable(True)
 | |
|             files = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, (QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
 | |
|             for f in files:
 | |
|                 self.combo.addItem(self.dialog.resolveValueDescription(f), f)
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 self.combo.setEditText("")
 | |
|             widget = QWidget()
 | |
|             layout = QHBoxLayout()
 | |
|             layout.setMargin(0)
 | |
|             layout.setContentsMargins(0, 0, 0, 0)
 | |
|             layout.setSpacing(6)
 | |
|             layout.addWidget(self.combo)
 | |
|             btn = QToolButton()
 | |
|             btn.setText('…')
 | |
|             btn.setToolTip(self.tr("Select file"))
 | |
|             btn.clicked.connect(self.selectFile)
 | |
|             layout.addWidget(btn)
 | |
|             widget.setLayout(layout)
 | |
|             return widget
 | |
| 
 | |
|     def selectFile(self):
 | |
|         settings = QgsSettings()
 | |
|         if os.path.isdir(os.path.dirname(self.combo.currentText())):
 | |
|             path = os.path.dirname(self.combo.currentText())
 | |
|         if settings.contains('/Processing/LastInputPath'):
 | |
|             path = settings.value('/Processing/LastInputPath')
 | |
|         else:
 | |
|             path = ''
 | |
| 
 | |
|         if self.parameterDefinition().extension():
 | |
|             filter = self.tr('{} files').format(
 | |
|                 self.parameterDefinition().extension().upper()) + ' (*.' + self.parameterDefinition().extension() + self.tr(
 | |
|                 ');;All files (*.*)')
 | |
|         else:
 | |
|             filter = self.tr('All files (*.*)')
 | |
| 
 | |
|         filename, selected_filter = QFileDialog.getOpenFileName(self.widget,
 | |
|                                                                 self.tr('Select File'), path,
 | |
|                                                                 filter)
 | |
|         if filename:
 | |
|             self.combo.setEditText(filename)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self.widget.setText(value)
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combo)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             return self.comboValue(combobox=self.combo)
 | |
| 
 | |
| 
 | |
| class FixedTableWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("FixedTableWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return FixedTablePanel(self.parameterDefinition())
 | |
|         else:
 | |
|             self.combobox = QComboBox()
 | |
|             values = self.dialog.getAvailableValuesOfType(QgsProcessingParameterMatrix)
 | |
|             for v in values:
 | |
|                 self.combobox.addItem(self.dialog.resolveValueDescription(v), v)
 | |
|             return self.combobox
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self.widget.setValue(value)
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combobox)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             return self.widget.table
 | |
|         else:
 | |
|             return self.comboValue(combobox=self.combobox)
 | |
| 
 | |
| 
 | |
| class MultipleLayerWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def _getOptions(self):
 | |
|         if self.parameterDefinition().layerType() == QgsProcessing.TypeVectorAnyGeometry:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeVector:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers],
 | |
|                                                            [QgsProcessing.TypeVector])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeVectorPoint:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers],
 | |
|                                                            [QgsProcessing.TypeVectorPoint,
 | |
|                                                             QgsProcessing.TypeVectorAnyGeometry])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeVectorLine:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers],
 | |
|                                                            [QgsProcessing.TypeVectorLine,
 | |
|                                                             QgsProcessing.TypeVectorAnyGeometry])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeVectorPolygon:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers],
 | |
|                                                            [QgsProcessing.TypeVectorPolygon,
 | |
|                                                             QgsProcessing.TypeVectorAnyGeometry])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeRaster:
 | |
|             options = self.dialog.getAvailableValuesOfType(
 | |
|                 (QgsProcessingParameterRasterLayer, QgsProcessingParameterMultipleLayers),
 | |
|                 [QgsProcessingOutputRasterLayer,
 | |
|                  QgsProcessingOutputMapLayer,
 | |
|                  QgsProcessingOutputMultipleLayers])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeMesh:
 | |
|             options = self.dialog.getAvailableValuesOfType(
 | |
|                 (QgsProcessingParameterMeshLayer, QgsProcessingParameterMultipleLayers),
 | |
|                 [])
 | |
|         elif self.parameterDefinition().layerType() == QgsProcessing.TypeMapLayer:
 | |
|             options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer,
 | |
|                                                             QgsProcessingParameterFeatureSource,
 | |
|                                                             QgsProcessingParameterVectorLayer,
 | |
|                                                             QgsProcessingParameterMeshLayer,
 | |
|                                                             QgsProcessingParameterMultipleLayers),
 | |
|                                                            [QgsProcessingOutputRasterLayer,
 | |
|                                                             QgsProcessingOutputVectorLayer,
 | |
|                                                             QgsProcessingOutputMapLayer,
 | |
|                                                             QgsProcessingOutputMultipleLayers])
 | |
|         else:
 | |
|             options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, QgsProcessingOutputFile)
 | |
|         options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt))
 | |
|         return options
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if self.parameterDefinition().layerType() == QgsProcessing.TypeFile:
 | |
|                 return MultipleInputPanel(datatype=QgsProcessing.TypeFile)
 | |
|             else:
 | |
|                 if self.parameterDefinition().layerType() == QgsProcessing.TypeRaster:
 | |
|                     options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
 | |
|                 elif self.parameterDefinition().layerType() == QgsProcessing.TypeMesh:
 | |
|                     options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
 | |
|                 elif self.parameterDefinition().layerType() in (QgsProcessing.TypeVectorAnyGeometry, QgsProcessing.TypeVector):
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|                 elif self.parameterDefinition().layerType() == QgsProcessing.TypeMapLayer:
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|                     options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
 | |
|                     options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
 | |
|                 else:
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
 | |
|                                                                         False)
 | |
|                 opts = [getExtendedLayerName(opt) for opt in options]
 | |
|                 return MultipleInputPanel(opts, datatype=self.parameterDefinition().layerType())
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
 | |
|             widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             options = [self.dialog.resolveValueDescription(opt) for opt in self._getOptions()]
 | |
|             return MultipleInputPanel(options, datatype=self.parameterDefinition().layerType())
 | |
| 
 | |
|     def refresh(self):
 | |
|         if self.parameterDefinition().layerType() != QgsProcessing.TypeFile:
 | |
|             if self.parameterDefinition().layerType() == QgsProcessing.TypeRaster:
 | |
|                 options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
 | |
|             elif self.parameterDefinition().layerType() == QgsProcessing.TypeMesh:
 | |
|                 options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
 | |
|             elif self.parameterDefinition().layerType() in (QgsProcessing.TypeVectorAnyGeometry, QgsProcessing.TypeVector):
 | |
|                 options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|             elif self.parameterDefinition().layerType() == QgsProcessing.TypeMapLayer:
 | |
|                 options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|                 options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
 | |
|                 options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
 | |
|             else:
 | |
|                 options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
 | |
|                                                                     False)
 | |
|             opts = [getExtendedLayerName(opt) for opt in options]
 | |
|             self.widget.updateForOptions(opts)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             pass  # TODO
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.setValue(value)
 | |
|         else:
 | |
|             options = self._getOptions()
 | |
| 
 | |
|             if not isinstance(value, (tuple, list)):
 | |
|                 value = [value]
 | |
| 
 | |
|             selected_options = []
 | |
|             for sel in value:
 | |
|                 if sel in options:
 | |
|                     selected_options.append(options.index(sel))
 | |
|                 elif isinstance(sel, QgsProcessingModelChildParameterSource):
 | |
|                     selected_options.append(sel.staticValue())
 | |
|                 else:
 | |
|                     selected_options.append(sel)
 | |
| 
 | |
|             self.widget.setSelectedItems(selected_options)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if self.parameterDefinition().layerType() == QgsProcessing.TypeFile:
 | |
|                 return self.widget.selectedoptions
 | |
|             else:
 | |
|                 if self.parameterDefinition().layerType() == QgsProcessing.TypeRaster:
 | |
|                     options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
 | |
|                 elif self.parameterDefinition().layerType() == QgsProcessing.TypeMesh:
 | |
|                     options = QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False)
 | |
|                 elif self.parameterDefinition().layerType() in (QgsProcessing.TypeVectorAnyGeometry, QgsProcessing.TypeVector):
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|                 elif self.parameterDefinition().layerType() == QgsProcessing.TypeMapLayer:
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
 | |
|                     options.extend(QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False))
 | |
|                     options.extend(QgsProcessingUtils.compatibleMeshLayers(QgsProject.instance(), False))
 | |
|                 else:
 | |
|                     options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.parameterDefinition().layerType()],
 | |
|                                                                         False)
 | |
|                 return [options[i] if isinstance(i, int) else i for i in self.widget.selectedoptions]
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.value()
 | |
|         else:
 | |
|             options = self._getOptions()
 | |
|             values = [options[i] if isinstance(i, int) else QgsProcessingModelChildParameterSource.fromStaticValue(i)
 | |
|                       for i in self.widget.selectedoptions]
 | |
|             if len(values) == 0 and not self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 raise InvalidParameterValue()
 | |
|             return values
 | |
| 
 | |
| 
 | |
| class NumberWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("NumberWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             widget = NumberInputPanel(self.parameterDefinition())
 | |
|             widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             return ModelerNumberInputPanel(self.parameterDefinition(), self.dialog)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         self.widget.setValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         return self.widget.getValue()
 | |
| 
 | |
|     def postInitialize(self, wrappers):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH) and self.parameterDefinition().isDynamic():
 | |
|             for wrapper in wrappers:
 | |
|                 if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName():
 | |
|                     self.widget.setDynamicLayer(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
 | |
|                     break
 | |
| 
 | |
|     def parentLayerChanged(self, wrapper):
 | |
|         self.widget.setDynamicLayer(wrapper.parameterValue())
 | |
| 
 | |
| 
 | |
| class DistanceWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("DistanceWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             widget = DistanceInputPanel(self.parameterDefinition())
 | |
|             widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             return ModelerNumberInputPanel(self.parameterDefinition(), self.dialog)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         self.widget.setValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         return self.widget.getValue()
 | |
| 
 | |
|     def postInitialize(self, wrappers):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             for wrapper in wrappers:
 | |
|                 if wrapper.parameterDefinition().name() == self.parameterDefinition().dynamicLayerParameterName():
 | |
|                     self.widget.setDynamicLayer(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.dynamicLayerChanged)
 | |
|                 if wrapper.parameterDefinition().name() == self.parameterDefinition().parentParameterName():
 | |
|                     self.widget.setUnitParameterValue(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.parentParameterChanged)
 | |
| 
 | |
|     def dynamicLayerChanged(self, wrapper):
 | |
|         self.widget.setDynamicLayer(wrapper.parameterValue())
 | |
| 
 | |
|     def parentParameterChanged(self, wrapper):
 | |
|         self.widget.setUnitParameterValue(wrapper.parameterValue())
 | |
| 
 | |
| 
 | |
| class RangeWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("RangeWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         widget = RangePanel(self.parameterDefinition())
 | |
|         widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|         return widget
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         self.widget.setValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         return self.widget.getValue()
 | |
| 
 | |
| 
 | |
| class MapLayerWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SELECTED = '[Not selected]'
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             self.combo = QgsProcessingMapLayerComboBox(self.parameterDefinition())
 | |
|             self.context = dataobjects.createContext()
 | |
| 
 | |
|             try:
 | |
|                 self.combo.setLayer(iface.activeLayer())
 | |
|             except:
 | |
|                 pass
 | |
| 
 | |
|             self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             self.combo.triggerFileSelection.connect(self.selectFile)
 | |
|             return self.combo
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
 | |
|             widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             self.combo = QComboBox()
 | |
|             layers = self.getAvailableLayers()
 | |
|             self.combo.setEditable(True)
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
 | |
|             for layer in layers:
 | |
|                 self.combo.addItem(self.dialog.resolveValueDescription(layer), layer)
 | |
| 
 | |
|             widget = QWidget()
 | |
|             layout = QHBoxLayout()
 | |
|             layout.setMargin(0)
 | |
|             layout.setContentsMargins(0, 0, 0, 0)
 | |
|             layout.setSpacing(6)
 | |
|             layout.addWidget(self.combo)
 | |
|             btn = QToolButton()
 | |
|             btn.setText('…')
 | |
|             btn.setToolTip(self.tr("Select file"))
 | |
|             btn.clicked.connect(self.selectFile)
 | |
|             layout.addWidget(btn)
 | |
|             widget.setLayout(layout)
 | |
|             return widget
 | |
| 
 | |
|     def getAvailableLayers(self):
 | |
|         return self.dialog.getAvailableValuesOfType(
 | |
|             [QgsProcessingParameterRasterLayer, QgsProcessingParameterMeshLayer, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterString],
 | |
|             [QgsProcessingOutputRasterLayer, QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile])
 | |
| 
 | |
|     def selectFile(self):
 | |
|         filename, selected_filter = self.getFileName(self.combo.currentText())
 | |
|         if filename:
 | |
|             if isinstance(self.combo, QgsProcessingMapLayerComboBox):
 | |
|                 self.combo.setValue(filename, self.context)
 | |
|             elif isinstance(self.combo, QgsMapLayerComboBox):
 | |
|                 items = self.combo.additionalItems()
 | |
|                 items.append(filename)
 | |
|                 self.combo.setAdditionalItems(items)
 | |
|                 self.combo.setCurrentIndex(self.combo.findText(filename))
 | |
|             else:
 | |
|                 self.combo.setEditText(filename)
 | |
|             self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if isinstance(value, str):
 | |
|                 layer = QgsProject.instance().mapLayer(value)
 | |
|                 if layer is not None:
 | |
|                     value = layer
 | |
|             self.combo.setValue(value, self.context)
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             self.widget.setValue(value)
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combo)
 | |
|         self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return self.combo.value()
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 if not bool(v):
 | |
|                     return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
|                 else:
 | |
|                     return os.path.exists(v)
 | |
| 
 | |
|             return self.comboValue(validator, combobox=self.combo)
 | |
| 
 | |
| 
 | |
| class RasterWidgetWrapper(MapLayerWidgetWrapper):
 | |
| 
 | |
|     def getAvailableLayers(self):
 | |
|         return self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer, QgsProcessingParameterString),
 | |
|                                                     (QgsProcessingOutputRasterLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
 | |
| 
 | |
|     def selectFile(self):
 | |
|         filename, selected_filter = self.getFileName(self.combo.currentText())
 | |
|         if filename:
 | |
|             filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition())
 | |
|             if isinstance(self.combo, QgsProcessingMapLayerComboBox):
 | |
|                 self.combo.setValue(filename, self.context)
 | |
|             elif isinstance(self.combo, QgsMapLayerComboBox):
 | |
|                 items = self.combo.additionalItems()
 | |
|                 items.append(filename)
 | |
|                 self.combo.setAdditionalItems(items)
 | |
|                 self.combo.setCurrentIndex(self.combo.findText(filename))
 | |
|             else:
 | |
|                 self.combo.setEditText(filename)
 | |
|             self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
| 
 | |
| class MeshWidgetWrapper(MapLayerWidgetWrapper):
 | |
| 
 | |
|     def getAvailableLayers(self):
 | |
|         return self.dialog.getAvailableValuesOfType((QgsProcessingParameterMeshLayer, QgsProcessingParameterString),
 | |
|                                                     ())
 | |
| 
 | |
|     def selectFile(self):
 | |
|         filename, selected_filter = self.getFileName(self.combo.currentText())
 | |
|         if filename:
 | |
|             if isinstance(self.combo, QgsProcessingMapLayerComboBox):
 | |
|                 self.combo.setValue(filename, self.context)
 | |
|             elif isinstance(self.combo, QgsMapLayerComboBox):
 | |
|                 items = self.combo.additionalItems()
 | |
|                 items.append(filename)
 | |
|                 self.combo.setAdditionalItems(items)
 | |
|                 self.combo.setCurrentIndex(self.combo.findText(filename))
 | |
|             else:
 | |
|                 self.combo.setEditText(filename)
 | |
|             self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
| 
 | |
| class EnumWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SELECTED = '[Not selected]'
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("EnumWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self, useCheckBoxes=False, columns=1):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self._useCheckBoxes = useCheckBoxes
 | |
|             if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
 | |
|                 return CheckboxesPanel(options=self.parameterDefinition().options(),
 | |
|                                        multiple=self.parameterDefinition().allowMultiple(),
 | |
|                                        columns=columns)
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 return MultipleInputPanel(options=self.parameterDefinition().options())
 | |
|             else:
 | |
|                 widget = QComboBox()
 | |
|                 for i, option in enumerate(self.parameterDefinition().options()):
 | |
|                     widget.addItem(option, i)
 | |
|                 if self.parameterDefinition().defaultValue():
 | |
|                     widget.setCurrentIndex(widget.findData(self.parameterDefinition().defaultValue()))
 | |
|                 return widget
 | |
|         else:
 | |
|             self.combobox = QComboBox()
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 self.combobox.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
 | |
|             for i, option in enumerate(self.parameterDefinition().options()):
 | |
|                 self.combobox.addItem(option, i)
 | |
|             values = self.dialog.getAvailableValuesOfType(QgsProcessingParameterEnum)
 | |
|             for v in values:
 | |
|                 self.combobox.addItem(self.dialog.resolveValueDescription(v), v)
 | |
|             return self.combobox
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
 | |
|                 self.widget.setValue(value)
 | |
|                 return
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 self.widget.setSelectedItems(value)
 | |
|             else:
 | |
|                 self.widget.setCurrentIndex(self.widget.findData(value))
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combobox)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
 | |
|                 return self.widget.value()
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 return self.widget.selectedoptions
 | |
|             else:
 | |
|                 return self.widget.currentData()
 | |
|         else:
 | |
|             return self.comboValue(combobox=self.combobox)
 | |
| 
 | |
| 
 | |
| class FeatureSourceWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SELECTED = '[Not selected]'
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             self.combo = QgsProcessingMapLayerComboBox(self.parameterDefinition())
 | |
|             self.context = dataobjects.createContext()
 | |
| 
 | |
|             try:
 | |
|                 if iface.activeLayer().type() == QgsMapLayerType.VectorLayer:
 | |
|                     self.combo.setLayer(iface.activeLayer())
 | |
|             except:
 | |
|                 pass
 | |
| 
 | |
|             self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             self.combo.triggerFileSelection.connect(self.selectFile)
 | |
|             return self.combo
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
 | |
|             widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             self.combo = QComboBox()
 | |
|             layers = self.dialog.getAvailableValuesOfType(
 | |
|                 (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer),
 | |
|                 (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputString, QgsProcessingOutputFile), self.parameterDefinition().dataTypes())
 | |
|             self.combo.setEditable(True)
 | |
|             for layer in layers:
 | |
|                 self.combo.addItem(self.dialog.resolveValueDescription(layer), layer)
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 self.combo.setEditText("")
 | |
| 
 | |
|             widget = QWidget()
 | |
|             layout = QHBoxLayout()
 | |
|             layout.setMargin(0)
 | |
|             layout.setContentsMargins(0, 0, 0, 0)
 | |
|             layout.setSpacing(2)
 | |
|             layout.addWidget(self.combo)
 | |
|             btn = QToolButton()
 | |
|             btn.setText('…')
 | |
|             btn.setToolTip(self.tr("Select file"))
 | |
|             btn.clicked.connect(self.selectFile)
 | |
|             layout.addWidget(btn)
 | |
|             widget.setLayout(layout)
 | |
|             return widget
 | |
| 
 | |
|     def selectFile(self):
 | |
|         filename, selected_filter = self.getFileName(self.combo.currentText())
 | |
|         if filename:
 | |
|             filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition())
 | |
|             if isinstance(self.combo, QgsProcessingMapLayerComboBox):
 | |
|                 self.combo.setValue(filename, self.context)
 | |
|             elif isinstance(self.combo, QgsMapLayerComboBox):
 | |
|                 items = self.combo.additionalItems()
 | |
|                 items.append(filename)
 | |
|                 self.combo.setAdditionalItems(items)
 | |
|                 self.combo.setCurrentIndex(self.combo.findText(filename))
 | |
|             else:
 | |
|                 self.combo.setEditText(filename)
 | |
|             self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if isinstance(value, str):
 | |
|                 layer = QgsProject.instance().mapLayer(value)
 | |
|                 if layer is not None:
 | |
|                     value = layer
 | |
|             self.combo.setValue(value, self.context)
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             self.widget.setValue(value)
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combo)
 | |
|         self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return self.combo.value()
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 if not bool(v):
 | |
|                     return self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
|                 else:
 | |
|                     return os.path.exists(v)
 | |
| 
 | |
|             if self.combo.currentText():
 | |
|                 return self.comboValue(validator, combobox=self.combo)
 | |
|             else:
 | |
|                 return None
 | |
| 
 | |
| 
 | |
| class StringWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__(*args, **kwargs)
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 widget = QPlainTextEdit()
 | |
|             else:
 | |
|                 self._lineedit = QLineEdit()
 | |
|                 widget = self._lineedit
 | |
| 
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = QLineEdit()
 | |
| 
 | |
|         else:
 | |
|             # strings, numbers, files and table fields are all allowed input types
 | |
|             strings = self.dialog.getAvailableValuesOfType(
 | |
|                 [QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterFile,
 | |
|                  QgsProcessingParameterField, QgsProcessingParameterExpression],
 | |
|                 [QgsProcessingOutputString, QgsProcessingOutputFile])
 | |
|             options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 widget = MultilineTextPanel(options)
 | |
|             else:
 | |
|                 widget = QComboBox()
 | |
|                 widget.setEditable(True)
 | |
|                 for desc, val in options:
 | |
|                     widget.addItem(desc, val)
 | |
|         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():
 | |
|                 if self.dialogType == DIALOG_STANDARD:
 | |
|                     self.setValue(str(exp.evaluate(context)))
 | |
|                 else:
 | |
|                     self.setValue(dlg.expressionText())
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 self.widget.setPlainText(value)
 | |
|             else:
 | |
|                 self._lineedit.setText(value)
 | |
| 
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             self.widget.setText(value)
 | |
| 
 | |
|         else:
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 self.widget.setValue(value)
 | |
|             else:
 | |
|                 self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 text = self.widget.toPlainText()
 | |
|             else:
 | |
|                 text = self._lineedit.text()
 | |
|             return text
 | |
| 
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.text()
 | |
| 
 | |
|         else:
 | |
|             if self.parameterDefinition().multiLine():
 | |
|                 value = self.widget.getValue()
 | |
|                 option = self.widget.getOption()
 | |
|                 if option == MultilineTextPanel.USE_TEXT:
 | |
|                     if value == '':
 | |
|                         if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                             return None
 | |
|                         else:
 | |
|                             raise InvalidParameterValue()
 | |
|                     else:
 | |
|                         return value
 | |
|                 else:
 | |
|                     return value
 | |
|             else:
 | |
|                 def validator(v):
 | |
|                     return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
| 
 | |
|                 return self.comboValue(validator)
 | |
| 
 | |
| 
 | |
| class ExpressionWidgetWrapper(WidgetWrapper):
 | |
| 
 | |
|     def __init__(self, param, dialog, row=0, col=0, **kwargs):
 | |
|         """
 | |
|         .. deprecated:: 3.4
 | |
|         Do not use, will be removed in QGIS 4.0
 | |
|         """
 | |
| 
 | |
|         from warnings import warn
 | |
|         warn("StringWidgetWrapper is deprecated and will be removed in QGIS 4.0", DeprecationWarning)
 | |
| 
 | |
|         super().__init__(param, dialog, row, col, **kwargs)
 | |
|         self.context = dataobjects.createContext()
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().parentLayerParameterName():
 | |
|                 widget = QgsFieldExpressionWidget()
 | |
|             else:
 | |
|                 widget = QgsExpressionLineEdit()
 | |
|             if self.parameterDefinition().defaultValue():
 | |
|                 widget.setExpression(self.parameterDefinition().defaultValue())
 | |
|         else:
 | |
|             strings = self.dialog.getAvailableValuesOfType(
 | |
|                 [QgsProcessingParameterExpression, QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterDistance],
 | |
|                 (QgsProcessingOutputString, QgsProcessingOutputNumber))
 | |
|             options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
 | |
|             widget = QComboBox()
 | |
|             widget.setEditable(True)
 | |
|             for desc, val in options:
 | |
|                 widget.addItem(desc, val)
 | |
|             widget.setEditText(self.parameterDefinition().defaultValue() or "")
 | |
|         return widget
 | |
| 
 | |
|     def postInitialize(self, wrappers):
 | |
|         for wrapper in wrappers:
 | |
|             if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
 | |
|                 if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|                     self.setLayer(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.parentLayerChanged)
 | |
|                 break
 | |
| 
 | |
|     def parentLayerChanged(self, wrapper):
 | |
|         self.setLayer(wrapper.parameterValue())
 | |
| 
 | |
|     def setLayer(self, layer):
 | |
|         if isinstance(layer, QgsProcessingFeatureSourceDefinition):
 | |
|             layer, ok = layer.source.valueAsString(self.context.expressionContext())
 | |
|         if isinstance(layer, str):
 | |
|             layer = QgsProcessingUtils.mapLayerFromString(layer, self.context)
 | |
|         self.widget.setLayer(layer)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             self.widget.setExpression(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             try:
 | |
|                 return self.widget.asExpression()
 | |
|             except:
 | |
|                 return self.widget.expression()
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
| 
 | |
|             return self.comboValue(validator)
 | |
| 
 | |
| 
 | |
| class VectorLayerWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SELECTED = '[Not selected]'
 | |
| 
 | |
|     def createWidget(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             self.combo = QgsProcessingMapLayerComboBox(self.parameterDefinition())
 | |
|             self.context = dataobjects.createContext()
 | |
| 
 | |
|             try:
 | |
|                 if iface.activeLayer().type() == QgsMapLayerType.VectorLayer:
 | |
|                     self.combo.setLayer(iface.activeLayer())
 | |
|             except:
 | |
|                 pass
 | |
| 
 | |
|             self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             self.combo.triggerFileSelection.connect(self.selectFile)
 | |
|             return self.combo
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog)
 | |
|             widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             self.combo = QComboBox()
 | |
|             self.combo.setEditable(True)
 | |
|             tables = self.dialog.getAvailableValuesOfType((QgsProcessingParameterVectorLayer, QgsProcessingParameterString),
 | |
|                                                           (QgsProcessingOutputVectorLayer, QgsProcessingOutputMapLayer, QgsProcessingOutputFile, QgsProcessingOutputString))
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 self.combo.addItem(self.NOT_SELECTED, self.NOT_SET_OPTION)
 | |
|             for table in tables:
 | |
|                 self.combo.addItem(self.dialog.resolveValueDescription(table), table)
 | |
| 
 | |
|             widget = QWidget()
 | |
|             layout = QHBoxLayout()
 | |
|             layout.setMargin(0)
 | |
|             layout.setContentsMargins(0, 0, 0, 0)
 | |
|             layout.setSpacing(6)
 | |
|             layout.addWidget(self.combo)
 | |
|             btn = QToolButton()
 | |
|             btn.setText('…')
 | |
|             btn.setToolTip(self.tr("Select file"))
 | |
|             btn.clicked.connect(self.selectFile)
 | |
|             layout.addWidget(btn)
 | |
|             widget.setLayout(layout)
 | |
|             return widget
 | |
| 
 | |
|     def selectFile(self):
 | |
|         filename, selected_filter = self.getFileName(self.combo.currentText())
 | |
|         if filename:
 | |
|             filename = dataobjects.getRasterSublayer(filename, self.parameterDefinition())
 | |
|             if isinstance(self.combo, QgsProcessingMapLayerComboBox):
 | |
|                 self.combo.setValue(filename, self.context)
 | |
|             elif isinstance(self.combo, QgsMapLayerComboBox):
 | |
|                 items = self.combo.additionalItems()
 | |
|                 items.append(filename)
 | |
|                 self.combo.setAdditionalItems(items)
 | |
|                 self.combo.setCurrentIndex(self.combo.findText(filename))
 | |
|             else:
 | |
|                 self.combo.setEditText(filename)
 | |
|             self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             if isinstance(value, str):
 | |
|                 layer = QgsProject.instance().mapLayer(value)
 | |
|                 if layer is not None:
 | |
|                     value = layer
 | |
|             self.combo.setValue(value, self.context)
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.setValue(value)
 | |
|         else:
 | |
|             self.setComboValue(value, combobox=self.combo)
 | |
|         self.widgetValueHasChanged.emit(self)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType == DIALOG_STANDARD:
 | |
|             return self.combo.value()
 | |
|         elif self.dialogType == DIALOG_BATCH:
 | |
|             return self.widget.getValue()
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
| 
 | |
|             return self.comboValue(validator, combobox=self.combo)
 | |
| 
 | |
| 
 | |
| class TableFieldWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SET = '[Not set]'
 | |
| 
 | |
|     def __init__(self, param, dialog, row=0, col=0, **kwargs):
 | |
|         super().__init__(param, dialog, row, col, **kwargs)
 | |
|         self.context = dataobjects.createContext()
 | |
| 
 | |
|     def createWidget(self):
 | |
|         self._layer = None
 | |
|         self.parent_file_based_layers = {}
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 return MultipleInputPanel(options=[])
 | |
|             else:
 | |
|                 widget = QgsFieldComboBox()
 | |
|                 widget.setAllowEmptyFieldName(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional)
 | |
|                 widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|                 if self.parameterDefinition().dataType() == QgsProcessingParameterField.Numeric:
 | |
|                     widget.setFilters(QgsFieldProxyModel.Numeric)
 | |
|                 elif self.parameterDefinition().dataType() == QgsProcessingParameterField.String:
 | |
|                     widget.setFilters(QgsFieldProxyModel.String)
 | |
|                 elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DateTime:
 | |
|                     widget.setFilters(QgsFieldProxyModel.Date | QgsFieldProxyModel.Time)
 | |
|                 return widget
 | |
|         else:
 | |
|             widget = QComboBox()
 | |
|             widget.setEditable(True)
 | |
|             fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterField, QgsProcessingParameterString],
 | |
|                                                           [QgsProcessingOutputString])
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 widget.addItem(self.NOT_SET, self.NOT_SET_OPTION)
 | |
|             for f in fields:
 | |
|                 widget.addItem(self.dialog.resolveValueDescription(f), f)
 | |
|             widget.setToolTip(
 | |
|                 self.tr(
 | |
|                     'Input parameter, or name of field (separate field names with ; for multiple field parameters)'))
 | |
|             return widget
 | |
| 
 | |
|     def postInitialize(self, wrappers):
 | |
|         for wrapper in wrappers:
 | |
|             if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
 | |
|                 if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|                     self.setLayer(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
 | |
|                 break
 | |
| 
 | |
|     def parentValueChanged(self, wrapper):
 | |
|         value = wrapper.parameterValue()
 | |
|         if isinstance(value, str) and value in self.parent_file_based_layers:
 | |
|             self.setLayer(self.parent_file_based_layers[value])
 | |
|         else:
 | |
|             self.setLayer(value)
 | |
|             if isinstance(value, str):
 | |
|                 self.parent_file_based_layers[value] = self._layer
 | |
| 
 | |
|     def setLayer(self, layer):
 | |
|         if isinstance(layer, QgsProcessingFeatureSourceDefinition):
 | |
|             layer, ok = layer.source.valueAsString(self.context.expressionContext())
 | |
|         if isinstance(layer, str):
 | |
|             if not layer:  # empty string
 | |
|                 layer = None
 | |
|             else:
 | |
|                 layer = QgsProcessingUtils.mapLayerFromString(layer, self.context)
 | |
|                 if not isinstance(layer, QgsVectorLayer) or not layer.isValid():
 | |
|                     self.dialog.messageBar().clearWidgets()
 | |
|                     self.dialog.messageBar().pushMessage("", self.tr("Could not load selected layer/table. Dependent field could not be populated"),
 | |
|                                                          level=Qgis.Warning, duration=5)
 | |
|                     return
 | |
| 
 | |
|         self._layer = layer
 | |
| 
 | |
|         self.refreshItems()
 | |
| 
 | |
|     def refreshItems(self):
 | |
|         if self.parameterDefinition().allowMultiple():
 | |
|             self.widget.updateForOptions(self.getFields())
 | |
|         else:
 | |
|             self.widget.setLayer(self._layer)
 | |
|             self.widget.setCurrentIndex(0)
 | |
|         if self.parameterDefinition().defaultValue() is not None:
 | |
|             self.setValue(self.parameterDefinition().defaultValue())
 | |
| 
 | |
|     def getFields(self):
 | |
|         if self._layer is None:
 | |
|             return []
 | |
|         fieldTypes = []
 | |
|         if self.parameterDefinition().dataType() == QgsProcessingParameterField.String:
 | |
|             fieldTypes = [QVariant.String]
 | |
|         elif self.parameterDefinition().dataType() == QgsProcessingParameterField.Numeric:
 | |
|             fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong,
 | |
|                           QVariant.UInt, QVariant.ULongLong]
 | |
|         elif self.parameterDefinition().dataType() == QgsProcessingParameterField.DateTime:
 | |
|             fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime]
 | |
| 
 | |
|         fieldNames = []
 | |
|         for field in self._layer.fields():
 | |
|             if not fieldTypes or field.type() in fieldTypes:
 | |
|                 fieldNames.append(str(field.name()))
 | |
|         return fieldNames
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 options = self.widget.options
 | |
|                 selected = []
 | |
|                 if isinstance(value, str):
 | |
|                     value = value.split(';')
 | |
| 
 | |
|                 for v in value:
 | |
|                     for i, opt in enumerate(options):
 | |
|                         if opt == v:
 | |
|                             selected.append(i)
 | |
|                         # case insensitive check - only do if matching case value is not present
 | |
|                         elif v not in options and opt.lower() == v.lower():
 | |
|                             selected.append(i)
 | |
| 
 | |
|                 self.widget.setSelectedItems(selected)
 | |
|             else:
 | |
|                 self.widget.setField(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 return [self.widget.options[i] for i in self.widget.selectedoptions]
 | |
|             else:
 | |
|                 f = self.widget.currentField()
 | |
|                 if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional and not f:
 | |
|                     return None
 | |
|                 return f
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
| 
 | |
|             return self.comboValue(validator)
 | |
| 
 | |
| 
 | |
| class BandWidgetWrapper(WidgetWrapper):
 | |
|     NOT_SET = '[Not set]'
 | |
| 
 | |
|     def __init__(self, param, dialog, row=0, col=0, **kwargs):
 | |
|         super().__init__(param, dialog, row, col, **kwargs)
 | |
|         self.context = dataobjects.createContext()
 | |
| 
 | |
|     def createWidget(self):
 | |
|         self._layer = None
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 return MultipleInputPanel(options=[])
 | |
|             widget = QgsRasterBandComboBox()
 | |
|             widget.setShowNotSetOption(self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional)
 | |
|             widget.bandChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
 | |
|             return widget
 | |
|         else:
 | |
|             widget = QComboBox()
 | |
|             widget.setEditable(True)
 | |
|             fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterBand, QgsProcessingParameterDistance, QgsProcessingParameterNumber],
 | |
|                                                           [QgsProcessingOutputNumber])
 | |
|             if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional:
 | |
|                 widget.addItem(self.NOT_SET, self.NOT_SET_OPTION)
 | |
|             for f in fields:
 | |
|                 widget.addItem(self.dialog.resolveValueDescription(f), f)
 | |
|             return widget
 | |
| 
 | |
|     def postInitialize(self, wrappers):
 | |
|         for wrapper in wrappers:
 | |
|             if wrapper.parameterDefinition().name() == self.parameterDefinition().parentLayerParameterName():
 | |
|                 if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|                     self.setLayer(wrapper.parameterValue())
 | |
|                     wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
 | |
|                 break
 | |
| 
 | |
|     def parentValueChanged(self, wrapper):
 | |
|         self.setLayer(wrapper.parameterValue())
 | |
| 
 | |
|     def setLayer(self, layer):
 | |
|         if isinstance(layer, QgsProcessingParameterRasterLayer):
 | |
|             layer, ok = layer.source.valueAsString(self.context.expressionContext())
 | |
|         if isinstance(layer, str):
 | |
|             layer = QgsProcessingUtils.mapLayerFromString(layer, self.context)
 | |
|         self._layer = layer
 | |
|         self.refreshItems()
 | |
| 
 | |
|     def getBands(self):
 | |
|         bands = []
 | |
| 
 | |
|         if self._layer is not None:
 | |
|             provider = self._layer.dataProvider()
 | |
|             for band in range(1, provider.bandCount() + 1):
 | |
|                 name = provider.generateBandName(band)
 | |
|                 interpretation = provider.colorInterpretationName(band)
 | |
|                 if interpretation != "Undefined":
 | |
|                     name = name + ' ({})'.format(interpretation)
 | |
|                 bands.append(name)
 | |
|         return bands
 | |
| 
 | |
|     def refreshItems(self):
 | |
|         if self.param.allowMultiple():
 | |
|             self.widget.setSelectedItems([])
 | |
|             self.widget.updateForOptions(self.getBands())
 | |
|         else:
 | |
|             self.widget.setLayer(self._layer)
 | |
|             self.widget.setCurrentIndex(0)
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         if value is None or value == NULL:
 | |
|             return
 | |
| 
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 options = self.widget.options
 | |
|                 selected = []
 | |
|                 if isinstance(value, str):
 | |
|                     value = value.split(';')
 | |
| 
 | |
|                 for v in value:
 | |
|                     for i, opt in enumerate(options):
 | |
|                         match = re.search('(?:\\A|[^0-9]){}(?:\\Z|[^0-9]|)'.format(v), opt)
 | |
|                         if match:
 | |
|                             selected.append(i)
 | |
| 
 | |
|                 self.widget.setSelectedItems(selected)
 | |
|             else:
 | |
|                 self.widget.setBand(value)
 | |
|         else:
 | |
|             self.setComboValue(value)
 | |
| 
 | |
|     def value(self):
 | |
|         if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
 | |
|             if self.parameterDefinition().allowMultiple():
 | |
|                 bands = []
 | |
|                 for i in self.widget.selectedoptions:
 | |
|                     match = re.search('(?:\\A|[^0-9])([0-9]+)(?:\\Z|[^0-9]|)', self.widget.options[i])
 | |
|                     if match:
 | |
|                         bands.append(match.group(1))
 | |
|                 return bands
 | |
|             else:
 | |
|                 f = self.widget.currentBand()
 | |
|                 if self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional and not f:
 | |
|                     return None
 | |
|             return f
 | |
|         else:
 | |
|             def validator(v):
 | |
|                 return bool(v) or self.parameterDefinition().flags() & QgsProcessingParameterDefinition.FlagOptional
 | |
| 
 | |
|             return self.comboValue(validator)
 | |
| 
 | |
| 
 | |
| class WidgetWrapperFactory:
 | |
| 
 | |
|     """
 | |
|     Factory for parameter widget wrappers
 | |
|     """
 | |
| 
 | |
|     @staticmethod
 | |
|     def create_wrapper(param, dialog, row=0, col=0):
 | |
|         wrapper_metadata = param.metadata().get('widget_wrapper', None)
 | |
|         # VERY messy logic here to avoid breaking 3.0 API which allowed metadata "widget_wrapper" value to be either
 | |
|         # a string name of a class OR a dict.
 | |
|         # TODO QGIS 4.0 -- require widget_wrapper to be a dict.
 | |
|         if wrapper_metadata and (not isinstance(wrapper_metadata, dict) or wrapper_metadata.get('class', None) is not None):
 | |
|             return WidgetWrapperFactory.create_wrapper_from_metadata(param, dialog, row, col)
 | |
|         else:
 | |
|             # try from c++ registry first
 | |
|             class_type = dialog.__class__.__name__
 | |
|             if class_type == 'ModelerParametersDialog':
 | |
|                 wrapper = QgsGui.processingGuiRegistry().createModelerParameterWidget(dialog.model,
 | |
|                                                                                       dialog.childId,
 | |
|                                                                                       param,
 | |
|                                                                                       dialog.context)
 | |
|             else:
 | |
|                 dialog_type = dialogTypes.get(class_type,
 | |
|                                               QgsProcessingGui.Standard)
 | |
|                 wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(param, dialog_type)
 | |
|             if wrapper is not None:
 | |
|                 wrapper.setDialog(dialog)
 | |
|                 return wrapper
 | |
| 
 | |
|             # fallback to Python registry
 | |
|             return WidgetWrapperFactory.create_wrapper_from_class(param, dialog, row, col)
 | |
| 
 | |
|     @staticmethod
 | |
|     def create_wrapper_from_metadata(param, dialog, row=0, col=0):
 | |
|         wrapper = param.metadata().get('widget_wrapper', None)
 | |
|         params = {}
 | |
|         # wrapper metadata should be a dict with class key
 | |
|         if isinstance(wrapper, dict):
 | |
|             params = deepcopy(wrapper)
 | |
|             wrapper = params.pop('class')
 | |
|         # wrapper metadata should be a class path
 | |
|         if isinstance(wrapper, str):
 | |
|             tokens = wrapper.split('.')
 | |
|             mod = __import__('.'.join(tokens[:-1]), fromlist=[tokens[-1]])
 | |
|             wrapper = getattr(mod, tokens[-1])
 | |
|         # or directly a class object
 | |
|         if isclass(wrapper):
 | |
|             wrapper = wrapper(param, dialog, row, col, **params)
 | |
|         # or a wrapper instance
 | |
|         return wrapper
 | |
| 
 | |
|     @staticmethod
 | |
|     def create_wrapper_from_class(param, dialog, row=0, col=0):
 | |
|         wrapper = None
 | |
|         if param.type() == 'boolean':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = BooleanWidgetWrapper
 | |
|         elif param.type() == 'crs':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = CrsWidgetWrapper
 | |
|         elif param.type() == 'extent':
 | |
|             wrapper = ExtentWidgetWrapper
 | |
|         elif param.type() == 'point':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = PointWidgetWrapper
 | |
|         elif param.type() == 'file':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = FileWidgetWrapper
 | |
|         elif param.type() == 'multilayer':
 | |
|             wrapper = MultipleLayerWidgetWrapper
 | |
|         elif param.type() == 'number':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = NumberWidgetWrapper
 | |
|         elif param.type() == 'distance':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = DistanceWidgetWrapper
 | |
|         elif param.type() == 'raster':
 | |
|             wrapper = RasterWidgetWrapper
 | |
|         elif param.type() == 'enum':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = EnumWidgetWrapper
 | |
|         elif param.type() == 'string':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = StringWidgetWrapper
 | |
|         elif param.type() == 'expression':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = ExpressionWidgetWrapper
 | |
|         elif param.type() == 'vector':
 | |
|             wrapper = VectorLayerWidgetWrapper
 | |
|         elif param.type() == 'field':
 | |
|             wrapper = TableFieldWidgetWrapper
 | |
|         elif param.type() == 'source':
 | |
|             wrapper = FeatureSourceWidgetWrapper
 | |
|         elif param.type() == 'band':
 | |
|             wrapper = BandWidgetWrapper
 | |
|         elif param.type() == 'layer':
 | |
|             wrapper = MapLayerWidgetWrapper
 | |
|         elif param.type() == 'range':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = RangeWidgetWrapper
 | |
|         elif param.type() == 'matrix':
 | |
|             # deprecated, moved to c++
 | |
|             wrapper = FixedTableWidgetWrapper
 | |
|         elif param.type() == 'mesh':
 | |
|             wrapper = MeshWidgetWrapper
 | |
|         else:
 | |
|             assert False, param.type()
 | |
|         return wrapper(param, dialog, row, col)
 |