QGIS/python/plugins/processing/gui/ParametersPanel.py
2024-11-29 15:38:02 +01:00

300 lines
12 KiB
Python

"""
***************************************************************************
ParametersPanel.py
---------------------
Date : August 2012
Copyright : (C) 2012 by Victor Olaya
(C) 2013 by CS Systemes d'information (CS SI)
Email : volayaf at gmail dot com
otb at c-s dot fr (CS SI)
Contributors : Victor Olaya
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Victor Olaya"
__date__ = "August 2012"
__copyright__ = "(C) 2012, Victor Olaya"
from qgis.core import (
QgsProcessingParameterDefinition,
QgsProcessingParameterExtent,
QgsProject,
QgsProcessingModelAlgorithm,
QgsProcessingOutputLayerDefinition,
)
from qgis.gui import (
QgsProcessingContextGenerator,
QgsProcessingParameterWidgetContext,
QgsProcessingParametersWidget,
QgsGui,
QgsProcessingGui,
QgsProcessingParametersGenerator,
QgsProcessingHiddenWidgetWrapper,
)
from qgis.utils import iface
from processing.gui.wrappers import WidgetWrapperFactory, WidgetWrapper
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
from processing.tools.dataobjects import createContext
class ParametersPanel(QgsProcessingParametersWidget):
def __init__(self, parent, alg, in_place=False, active_layer=None):
super().__init__(alg, parent)
self.in_place = in_place
self.active_layer = active_layer
self.wrappers = {}
self.extra_parameters = {}
self.processing_context = createContext()
class ContextGenerator(QgsProcessingContextGenerator):
def __init__(self, context):
super().__init__()
self.processing_context = context
def processingContext(self):
return self.processing_context
self.context_generator = ContextGenerator(self.processing_context)
self.initWidgets()
QgsProject.instance().layerWasAdded.connect(self.layerRegistryChanged)
QgsProject.instance().layersWillBeRemoved.connect(self.layerRegistryChanged)
def layerRegistryChanged(self, layers):
for wrapper in list(self.wrappers.values()):
try:
wrapper.refresh()
except AttributeError:
pass
def initWidgets(self):
super().initWidgets()
widget_context = QgsProcessingParameterWidgetContext()
widget_context.setProject(QgsProject.instance())
if iface is not None:
widget_context.setMapCanvas(iface.mapCanvas())
widget_context.setBrowserModel(iface.browserModel())
widget_context.setActiveLayer(iface.activeLayer())
widget_context.setMessageBar(self.parent().messageBar())
if isinstance(self.algorithm(), QgsProcessingModelAlgorithm):
widget_context.setModel(self.algorithm())
in_place_input_parameter_name = "INPUT"
if hasattr(self.algorithm(), "inputParameterName"):
in_place_input_parameter_name = self.algorithm().inputParameterName()
# Create widgets and put them in layouts
for param in self.algorithm().parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
if param.isDestination():
continue
else:
if self.in_place and param.name() in (
in_place_input_parameter_name,
"OUTPUT",
):
# don't show the input/output parameter widgets in in-place mode
# we still need to CREATE them, because other wrappers may need to interact
# with them (e.g. those parameters which need the input layer for field
# selections/crs properties/etc)
self.wrappers[param.name()] = QgsProcessingHiddenWidgetWrapper(
param, QgsProcessingGui.WidgetType.Standard, self
)
self.wrappers[param.name()].setLinkedVectorLayer(self.active_layer)
continue
wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent())
wrapper.setWidgetContext(widget_context)
wrapper.registerProcessingContextGenerator(self.context_generator)
wrapper.registerProcessingParametersGenerator(self)
self.wrappers[param.name()] = wrapper
# For compatibility with 3.x API, we need to check whether the wrapper is
# the deprecated WidgetWrapper class. If not, it's the newer
# QgsAbstractProcessingParameterWidgetWrapper class
# TODO QGIS 4.0 - remove
is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper)
stretch = 0
if not is_python_wrapper:
widget = wrapper.createWrappedWidget(self.processing_context)
stretch = wrapper.stretch()
else:
widget = wrapper.widget
if widget is not None:
if is_python_wrapper:
widget.setToolTip(param.toolTip())
label = None
if not is_python_wrapper:
label = wrapper.createWrappedLabel()
else:
label = wrapper.label
if label is not None:
self.addParameterLabel(param, label)
elif is_python_wrapper:
desc = param.description()
if isinstance(param, QgsProcessingParameterExtent):
desc += self.tr(" (xmin, xmax, ymin, ymax)")
if (
param.flags()
& QgsProcessingParameterDefinition.Flag.FlagOptional
):
desc += self.tr(" [optional]")
widget.setText(desc)
self.addParameterWidget(param, widget, stretch)
for output in self.algorithm().destinationParameterDefinitions():
if output.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
if self.in_place and output.name() in (
in_place_input_parameter_name,
"OUTPUT",
):
continue
wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(
output, QgsProcessingGui.WidgetType.Standard
)
wrapper.setWidgetContext(widget_context)
wrapper.registerProcessingContextGenerator(self.context_generator)
wrapper.registerProcessingParametersGenerator(self)
self.wrappers[output.name()] = wrapper
label = wrapper.createWrappedLabel()
if label is not None:
self.addOutputLabel(label)
widget = wrapper.createWrappedWidget(self.processing_context)
self.addOutputWidget(widget, wrapper.stretch())
# def skipOutputChanged(widget, checkbox, skipped):
# TODO
# enabled = not skipped
#
# # Do not try to open formats that are write-only.
# value = widget.value()
# if value and isinstance(value, QgsProcessingOutputLayerDefinition) and isinstance(output, (
# QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
# filename = value.sink.staticValue()
# if filename not in ('memory:', ''):
# path, ext = os.path.splitext(filename)
# format = QgsVectorFileWriter.driverForExtension(ext)
# drv = gdal.GetDriverByName(format)
# if drv:
# if drv.GetMetadataItem(gdal.DCAP_OPEN) is None:
# enabled = False
#
# checkbox.setEnabled(enabled)
# checkbox.setChecked(enabled)
for wrapper in list(self.wrappers.values()):
wrapper.postInitialize(list(self.wrappers.values()))
def createProcessingParameters(
self, flags=QgsProcessingParametersGenerator.Flags()
):
include_default = not (
flags & QgsProcessingParametersGenerator.Flag.SkipDefaultValueParameters
)
parameters = {}
for p, v in self.extra_parameters.items():
parameters[p] = v
for param in self.algorithm().parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
continue
if not param.isDestination():
try:
wrapper = self.wrappers[param.name()]
except KeyError:
continue
# For compatibility with 3.x API, we need to check whether the wrapper is
# the deprecated WidgetWrapper class. If not, it's the newer
# QgsAbstractProcessingParameterWidgetWrapper class
# TODO QGIS 4.0 - remove
if issubclass(wrapper.__class__, WidgetWrapper):
widget = wrapper.widget
else:
widget = wrapper.wrappedWidget()
if (
not isinstance(wrapper, QgsProcessingHiddenWidgetWrapper)
and widget is None
):
continue
value = wrapper.parameterValue()
if param.defaultValue() != value or include_default:
parameters[param.name()] = value
if not param.checkValueIsAcceptable(value):
raise AlgorithmDialogBase.InvalidParameterValue(param, widget)
else:
if self.in_place and param.name() == "OUTPUT":
parameters[param.name()] = "memory:"
continue
try:
wrapper = self.wrappers[param.name()]
except KeyError:
continue
widget = wrapper.wrappedWidget()
value = wrapper.parameterValue()
dest_project = None
if wrapper.customProperties().get("OPEN_AFTER_RUNNING"):
dest_project = QgsProject.instance()
if value and isinstance(value, QgsProcessingOutputLayerDefinition):
value.destinationProject = dest_project
if value and (param.defaultValue() != value or include_default):
parameters[param.name()] = value
context = createContext()
ok, error = param.isSupportedOutputValue(value, context)
if not ok:
raise AlgorithmDialogBase.InvalidOutputExtension(widget, error)
return self.algorithm().preprocessParameters(parameters)
def setParameters(self, parameters):
self.extra_parameters = {}
for param in self.algorithm().parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.Flag.FlagHidden:
if param.name() in parameters:
self.extra_parameters[param.name()] = parameters[param.name()]
continue
if not param.name() in parameters:
continue
value = parameters[param.name()]
wrapper = self.wrappers[param.name()]
wrapper.setParameterValue(value, self.processing_context)