28#include <QGraphicsSceneMouseEvent>
31#include "moc_qgsmodelgraphicsscene.cpp"
35QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
36 : QGraphicsScene( parent )
38 setItemIndexMethod( QGraphicsScene::NoIndex );
40 connect(
this, &QgsModelGraphicsScene::componentChanged,
this, &QgsModelGraphicsScene::updateBounds );
43QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
48void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
53void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag,
bool on )
61void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event )
63 if ( event->button() != Qt::LeftButton )
65 QGraphicsScene::mousePressEvent( event );
68void QgsModelGraphicsScene::updateBounds()
74 const QList<QGraphicsItem *> constItems = items();
75 for ( QGraphicsItem *item : constItems )
77 QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item );
79 bounds = bounds.united( componentItem->sceneBoundingRect() );
82 if ( bounds.isValid() )
84 bounds.adjust( -SCENE_COMPONENT_MARGIN, -SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN );
87 setSceneRect( bounds );
90QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param )
const
92 return new QgsModelParameterGraphicItem( param, model,
nullptr );
95QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child )
const
97 return new QgsModelChildAlgorithmGraphicItem( child, model,
nullptr );
100QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output )
const
102 return new QgsModelOutputGraphicItem( output, model,
nullptr );
105QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem )
const
107 return new QgsModelCommentGraphicItem( comment, parentItem, model,
nullptr );
110QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box )
const
112 return new QgsModelGroupBoxGraphicItem( box, model,
nullptr );
115void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model,
QgsProcessingContext &context )
118 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
119 mGroupBoxItems.clear();
120 for (
const QgsProcessingModelGroupBox &box : boxes )
122 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
124 item->setPos( box.position().x(), box.position().y() );
125 mGroupBoxItems.insert( box.uuid(), item );
126 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
127 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
128 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
132 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
133 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
135 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
137 item->setPos( it.value().position().x(), it.value().position().y() );
138 mParameterItems.insert( it.value().parameterName(), item );
139 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
140 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
141 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
143 addCommentItemForComponent( model, it.value(), item );
147 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
151 for (
const QString &otherName : parameterLinks )
153 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
155 auto arrow = std::make_unique<QgsModelArrowItem>( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
156 arrow->setPenStyle( Qt::DotLine );
157 addItem( arrow.release() );
163 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
164 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
166 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
168 item->setPos( it.value().position().x(), it.value().position().y() );
170 const QString childId = it.value().childId();
171 item->setResults( mLastResult.childResults().value( childId ) );
172 mChildAlgorithmItems.insert( childId, item );
173 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
174 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
175 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
176 connect( item, &QgsModelChildAlgorithmGraphicItem::runFromHere,
this, [
this, childId] {
177 emit runFromChild( childId );
179 connect( item, &QgsModelChildAlgorithmGraphicItem::runSelected,
this, &QgsModelGraphicsScene::runSelected );
180 connect( item, &QgsModelChildAlgorithmGraphicItem::showPreviousResults,
this, [
this, childId] {
181 emit showChildAlgorithmOutputs( childId );
183 connect( item, &QgsModelChildAlgorithmGraphicItem::showLog,
this, [
this, childId] {
184 emit showChildAlgorithmLog( childId );
187 addCommentItemForComponent( model, it.value(), item );
191 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
195 if ( !it.value().algorithm() )
203 QList<QgsProcessingModelChildParameterSource> sources;
204 if ( it.value().parameterSources().contains( parameter->name() ) )
205 sources = it.value().parameterSources()[parameter->name()];
206 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
208 const QList<LinkSource> sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
209 for (
const LinkSource &link : sourceItems )
213 QgsModelArrowItem *arrow =
nullptr;
214 if ( link.linkIndex == -1 )
216 arrow =
new QgsModelArrowItem( link.item, QgsModelArrowItem::Marker::NoMarker, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx, QgsModelArrowItem::Marker::Circle );
220 arrow =
new QgsModelArrowItem( link.item, link.edge, link.linkIndex,
true, QgsModelArrowItem::Marker::NoMarker, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx,
true, QgsModelArrowItem::Marker::NoMarker );
225 if ( parameter->isDestination() )
231 const QList<QgsProcessingModelChildDependency> dependencies = it.value().dependencies();
232 for (
const QgsProcessingModelChildDependency &depend : dependencies )
234 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
236 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
246 if ( output->name() == depend.conditionalBranch )
254 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
260 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
262 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
263 QMap<QString, QgsModelComponentGraphicItem *> outputItems;
267 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
268 const double outputOffsetX = algItem->size().width();
269 double outputOffsetY = 1.5 * algItem->size().height();
271 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
273 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
275 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
276 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
277 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
282 QPointF pos = outputIt.value().position();
285 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
286 outputOffsetY += 1.5 * outputIt.value().size().height();
291 if ( it.value().algorithm() )
296 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
306 item->component()->setPosition( pos );
307 outputItems.insert( outputIt.key(), item );
308 addItem(
new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle ) );
310 addCommentItemForComponent( model, outputIt.value(), item );
312 mOutputItems.insert( it.value().childId(), outputItems );
316QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
318 QList<QgsModelComponentGraphicItem *> componentItemList;
320 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
321 for ( QGraphicsItem *item : graphicsItemList )
323 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
325 componentItemList.push_back( componentItem );
329 return componentItemList;
332QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position )
const
335 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
337 for ( QGraphicsItem *graphicsItem : itemList )
339 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
341 return componentItem;
347QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem(
const QString &uuid )
349 return mGroupBoxItems.value( uuid );
352QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::childAlgorithmItem(
const QString &childId )
354 return mChildAlgorithmItems.value( childId );
357QgsModelComponentGraphicItem *QgsModelGraphicsScene::parameterItem(
const QString &name )
359 return mParameterItems.value( name );
362void QgsModelGraphicsScene::selectAll()
365 QgsModelComponentGraphicItem *focusedItem =
nullptr;
366 const QList<QGraphicsItem *> itemList = items();
367 for ( QGraphicsItem *graphicsItem : itemList )
369 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
371 componentItem->setSelected(
true );
373 focusedItem = componentItem;
376 emit selectedItemChanged( focusedItem );
379void QgsModelGraphicsScene::deselectAll()
384 const QList<QGraphicsItem *> selectedItemList = selectedItems();
385 for ( QGraphicsItem *item : selectedItemList )
387 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
389 componentItem->setSelected(
false );
392 emit selectedItemChanged(
nullptr );
395void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
400 item->setSelected(
true );
402 emit selectedItemChanged( item );
407 mLastResult = result;
410 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
412 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
414 item->setResults( it.value() );
419QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model,
const QVariant &value,
const QString &childId,
QgsProcessingContext &context )
const
421 QList<QgsModelGraphicsScene::LinkSource> res;
422 if ( value.userType() == QMetaType::Type::QVariantList )
424 const QVariantList list = value.toList();
425 for (
const QVariant &v : list )
426 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
428 else if ( value.userType() == QMetaType::Type::QStringList )
430 const QStringList list = value.toStringList();
431 for (
const QString &v : list )
432 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
434 else if ( value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
436 const QgsProcessingModelChildParameterSource source = value.value<QgsProcessingModelChildParameterSource>();
437 switch ( source.source() )
442 l.item = mParameterItems.value( source.parameterName() );
443 l.edge = Qt::BottomEdge;
451 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
458 if ( output->name() == source.outputName() )
462 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
465 l.item = mChildAlgorithmItems.value( source.outputChildId() );
466 l.edge = Qt::BottomEdge;
469 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
471 QString short_message = tr(
"Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
472 QString long_message = tr(
"Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
473 QString title( tr(
"Algorithm link error" ) );
475 showWarning(
const_cast<QString &
>( short_message ),
const_cast<QString &
>( title ),
const_cast<QString &
>( long_message ) );
490 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, &context );
492 const QSet<QString> vars = exp.referencedVariables();
493 for (
const QString &v : vars )
495 if ( variables.contains( v ) )
497 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
512void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model,
const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
514 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
517 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
518 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
519 addItem( commentItem );
520 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
521 connect( commentItem, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
522 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
524 auto arrow = std::make_unique<QgsModelArrowItem>( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
525 arrow->setPenStyle( Qt::DotLine );
526 addItem( arrow.release() );
534void QgsModelGraphicsScene::setMessageBar(
QgsMessageBar *messageBar )
536 mMessageBar = messageBar;
539void QgsModelGraphicsScene::showWarning(
const QString &shortMessage,
const QString &title,
const QString &longMessage,
Qgis::MessageLevel level )
const
542 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
543 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, title, longMessage] {
549 messageWidget->layout()->addWidget( detailsButton );
550 mMessageBar->clearWidgets();
551 mMessageBar->pushWidget( messageWidget, level, 0 );
554void QgsModelGraphicsScene::requestRebuildRequired()
556 emit rebuildRequired();
MessageLevel
Level for messages This will be used both for message log and message bar in application.
@ Warning
Warning message.
@ ExpressionText
Parameter value is taken from a text with expressions, evaluated just before the algorithm runs.
@ ModelOutput
Parameter value is linked to an output parameter for the model.
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
@ ModelParameter
Parameter value is taken from a parent model parameter.
@ StaticValue
Parameter value is a static value.
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
@ Hidden
Parameter is hidden and should not be shown to users.
Handles parsing and evaluation of expressions (formerly called "search strings").
Represents an item shown within a QgsMessageBar widget.
A bar for displaying non-blocking messages to the user.
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
Creates message bar item widget containing a message text to be displayed on the bar.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
A generic message view for displaying QGIS messages.
void setTitle(const QString &title) override
Sets title for the messages.
void setMessage(const QString &message, MessageType msgType) override
Sets message, it won't be displayed until.
void showMessage(bool blocking=true) override
display the message to the user and deletes itself
Contains information about the context in which a processing algorithm is executed.
Encapsulates the results of running a Processing model.
QMap< QString, QgsProcessingModelChildAlgorithmResult > childResults() const
Returns the map of child algorithm results.
Base class for the definition of processing outputs.
Base class for the definition of processing parameters.
virtual QStringList dependsOnOtherParameters() const
Returns a list of other parameter names on which this parameter is dependent (e.g.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QList< const QgsProcessingOutputDefinition * > QgsProcessingOutputDefinitions
List of processing parameters.
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.