QGIS/python/plugins/processing/gui/ParametersPanel.py
Nyall Dawson 86794dabdc Fix interface for QgsProcessingParametersGenerator was modified for
the python subclasses only and no longer correctly overrides the
base class method
2021-12-16 11:15:34 +10:00

278 lines
12 KiB
Python

# -*- coding: utf-8 -*-
"""
***************************************************************************
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.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.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.FlagOptional:
desc += self.tr(' [optional]')
widget.setText(desc)
self.addParameterWidget(param, widget, stretch)
for output in self.algorithm().destinationParameterDefinitions():
if output.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if self.in_place and output.name() in (in_place_input_parameter_name, 'OUTPUT'):
continue
wrapper = QgsGui.processingGuiRegistry().createParameterWidgetWrapper(output, QgsProcessingGui.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.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.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)