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

280 lines
10 KiB
Python

"""
***************************************************************************
ModelerGraphicItem.py
---------------------
Date : August 2012
Copyright : (C) 2012 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Victor Olaya"
__date__ = "August 2012"
__copyright__ = "(C) 2012, Victor Olaya"
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (
QgsProcessingParameterDefinition,
QgsProcessingModelOutput,
QgsProcessingModelAlgorithm,
QgsProject,
Qgis,
)
from qgis.gui import (
QgsProcessingParameterDefinitionDialog,
QgsProcessingParameterWidgetContext,
QgsModelParameterGraphicItem,
QgsModelChildAlgorithmGraphicItem,
QgsModelOutputGraphicItem,
QgsProcessingContextGenerator,
)
from processing.modeler.ModelerParameterDefinitionDialog import (
ModelerParameterDefinitionDialog,
)
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
from processing.tools.dataobjects import createContext
from qgis.utils import iface
class ModelerInputGraphicItem(QgsModelParameterGraphicItem):
"""
IMPORTANT! This is intentionally a MINIMAL class, only containing code which HAS TO BE HERE
because it contains Python code for compatibility with deprecated methods ONLY.
Don't add anything here -- edit the c++ base class instead!
"""
def __init__(self, element, model):
super().__init__(element, model, None)
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)
def create_widget_context(self):
"""
Returns a new widget context for use in the model editor
"""
widget_context = QgsProcessingParameterWidgetContext()
widget_context.setProject(QgsProject.instance())
if iface is not None:
widget_context.setMapCanvas(iface.mapCanvas())
widget_context.setActiveLayer(iface.activeLayer())
widget_context.setModel(self.model())
return widget_context
def edit(self, edit_comment=False):
existing_param = self.model().parameterDefinition(
self.component().parameterName()
)
old_name = existing_param.name()
old_description = existing_param.description()
comment = self.component().comment().description()
comment_color = self.component().comment().color()
new_param = None
if ModelerParameterDefinitionDialog.use_legacy_dialog(param=existing_param):
# boo, old api
dlg = ModelerParameterDefinitionDialog(self.model(), param=existing_param)
dlg.setComments(comment)
dlg.setCommentColor(comment_color)
if edit_comment:
dlg.switchToCommentTab()
if dlg.exec():
new_param = dlg.param
comment = dlg.comments()
comment_color = dlg.commentColor()
else:
# yay, use new API!
context = createContext()
widget_context = self.create_widget_context()
dlg = QgsProcessingParameterDefinitionDialog(
type=existing_param.type(),
context=context,
widgetContext=widget_context,
definition=existing_param,
algorithm=self.model(),
)
dlg.setComments(comment)
dlg.setCommentColor(comment_color)
dlg.registerProcessingContextGenerator(self.context_generator)
if edit_comment:
dlg.switchToCommentTab()
if dlg.exec():
new_param = dlg.createParameter(existing_param.name())
comment = dlg.comments()
comment_color = dlg.commentColor()
safeName = QgsProcessingModelAlgorithm.safeName(new_param.description())
new_param.setName(safeName.lower())
if new_param is not None:
self.aboutToChange.emit(self.tr("Edit {}").format(new_param.description()))
self.model().removeModelParameter(self.component().parameterName())
if new_param.description() != old_description:
# only update name if user has changed the description -- we don't force this, as it may cause
# unwanted name updates which could potentially break the model's API
name = new_param.name()
base_name = name
i = 2
while self.model().parameterDefinition(name):
name = base_name + str(i)
i += 1
new_param.setName(name)
self.model().changeParameterName(old_name, new_param.name())
self.component().setParameterName(new_param.name())
self.component().setDescription(new_param.name())
self.component().comment().setDescription(comment)
self.component().comment().setColor(comment_color)
self.model().addModelParameter(new_param, self.component())
self.setLabel(new_param.description())
self.requestModelRepaint.emit()
self.changed.emit()
def editComponent(self):
self.edit()
def editComment(self):
self.edit(edit_comment=True)
class ModelerChildAlgorithmGraphicItem(QgsModelChildAlgorithmGraphicItem):
"""
IMPORTANT! This is intentionally a MINIMAL class, only containing code which HAS TO BE HERE
because it contains Python code for compatibility with deprecated methods ONLY.
Don't add anything here -- edit the c++ base class instead!
"""
def __init__(self, element, model):
super().__init__(element, model, None)
def edit(self, edit_comment=False):
elemAlg = self.component().algorithm()
dlg = ModelerParametersDialog(
elemAlg,
self.model(),
self.component().childId(),
self.component().configuration(),
)
dlg.setComments(self.component().comment().description())
dlg.setCommentColor(self.component().comment().color())
if edit_comment:
dlg.switchToCommentTab()
if dlg.exec():
alg = dlg.createAlgorithm()
alg.setChildId(self.component().childId())
alg.copyNonDefinitionPropertiesFromModel(self.model())
self.aboutToChange.emit(self.tr("Edit {}").format(alg.description()))
self.model().setChildAlgorithm(alg)
self.requestModelRepaint.emit()
self.changed.emit()
res, errors = self.model().validateChildAlgorithm(alg.childId())
if not res:
self.scene().showWarning(
QCoreApplication.translate(
"ModelerGraphicItem", "Algorithm “{}” is invalid"
).format(alg.description()),
self.tr("Algorithm is Invalid"),
QCoreApplication.translate(
"ModelerGraphicItem",
"<p>The “{}” algorithm is invalid, because:</p><ul><li>{}</li></ul>",
).format(alg.description(), "</li><li>".join(errors)),
level=Qgis.MessageLevel.Warning,
)
else:
self.scene().messageBar().clearWidgets()
def editComponent(self):
self.edit()
def editComment(self):
self.edit(edit_comment=True)
class ModelerOutputGraphicItem(QgsModelOutputGraphicItem):
"""
IMPORTANT! This is intentionally a MINIMAL class, only containing code which HAS TO BE HERE
because it contains Python code for compatibility with deprecated methods ONLY.
Don't add anything here -- edit the c++ base class instead!
"""
def __init__(self, element, model):
super().__init__(element, model, None)
def edit(self, edit_comment=False):
child_alg = self.model().childAlgorithm(self.component().childId())
dlg = ModelerParameterDefinitionDialog(
self.model(),
param=self.model().modelParameterFromChildIdAndOutputName(
self.component().childId(), self.component().name()
),
)
dlg.setComments(self.component().comment().description())
dlg.setCommentColor(self.component().comment().color())
if edit_comment:
dlg.switchToCommentTab()
if dlg.exec():
model_outputs = child_alg.modelOutputs()
model_output = QgsProcessingModelOutput(
model_outputs[self.component().name()]
)
del model_outputs[self.component().name()]
model_output.setName(dlg.param.description())
model_output.setDescription(dlg.param.description())
model_output.setDefaultValue(dlg.param.defaultValue())
model_output.setMandatory(
not (
dlg.param.flags()
& QgsProcessingParameterDefinition.Flag.FlagOptional
)
)
model_output.comment().setDescription(dlg.comments())
model_output.comment().setColor(dlg.commentColor())
model_outputs[model_output.name()] = model_output
child_alg.setModelOutputs(model_outputs)
self.aboutToChange.emit(
self.tr("Edit {}").format(model_output.description())
)
self.model().updateDestinationParameters()
self.requestModelRepaint.emit()
self.changed.emit()
def editComponent(self):
self.edit()
def editComment(self):
self.edit(edit_comment=True)