26 #include <QGraphicsSceneMouseEvent>
27 #include <QPushButton>
31 QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
32 : QGraphicsScene( parent )
34 setItemIndexMethod( QGraphicsScene::NoIndex );
37 QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
42 void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
47 void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag,
bool on )
55 void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event )
57 if ( event->button() != Qt::LeftButton )
59 QGraphicsScene::mousePressEvent( event );
62 QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param )
const
64 return new QgsModelParameterGraphicItem( param, model,
nullptr );
67 QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child )
const
69 return new QgsModelChildAlgorithmGraphicItem( child, model,
nullptr );
72 QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output )
const
74 return new QgsModelOutputGraphicItem( output, model,
nullptr );
77 QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem )
const
79 return new QgsModelCommentGraphicItem( comment, parentItem, model,
nullptr );
82 QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box )
const
84 return new QgsModelGroupBoxGraphicItem( box, model,
nullptr );
87 void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model,
QgsProcessingContext &context )
90 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
91 mGroupBoxItems.clear();
92 for (
const QgsProcessingModelGroupBox &box : boxes )
94 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
96 item->setPos( box.position().x(), box.position().y() );
97 mGroupBoxItems.insert( box.uuid(), item );
98 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
99 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
100 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
104 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
105 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
107 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
109 item->setPos( it.value().position().x(), it.value().position().y() );
110 mParameterItems.insert( it.value().parameterName(), item );
111 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
112 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
113 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
115 addCommentItemForComponent( model, it.value(), item );
119 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
123 for (
const QString &otherName : parameterLinks )
125 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
127 std::unique_ptr< QgsModelArrowItem > arrow = std::make_unique< QgsModelArrowItem >( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
128 arrow->setPenStyle( Qt::DotLine );
129 addItem( arrow.release() );
135 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
136 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
138 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
140 item->setPos( it.value().position().x(), it.value().position().y() );
141 item->setResults( mChildResults.value( it.value().childId() ).toMap() );
142 item->setInputs( mChildInputs.value( it.value().childId() ).toMap() );
143 mChildAlgorithmItems.insert( it.value().childId(), item );
144 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
145 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
146 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
148 addCommentItemForComponent( model, it.value(), item );
152 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
156 if ( !it.value().algorithm() )
164 QList< QgsProcessingModelChildParameterSource > sources;
165 if ( it.value().parameterSources().contains( parameter->name() ) )
166 sources = it.value().parameterSources()[parameter->name()];
167 for (
const QgsProcessingModelChildParameterSource &source : sources )
169 const QList< LinkSource > sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
170 for (
const LinkSource &link : sourceItems )
174 QgsModelArrowItem *arrow =
nullptr;
175 if ( link.linkIndex == -1 )
176 arrow =
new QgsModelArrowItem( link.item, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx, QgsModelArrowItem::Marker::Circle );
178 arrow =
new QgsModelArrowItem( link.item, link.edge, link.linkIndex,
true, QgsModelArrowItem::Marker::Circle,
179 mChildAlgorithmItems.value( it.value().childId() ),
180 parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
181 parameter->isDestination() ? bottomIdx : topIdx,
183 QgsModelArrowItem::Marker::Circle );
187 if ( parameter->isDestination() )
193 const QList< QgsProcessingModelChildDependency > dependencies = it.value().dependencies();
194 for (
const QgsProcessingModelChildDependency &depend : dependencies )
196 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
198 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
208 if ( output->name() == depend.conditionalBranch )
216 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
222 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
224 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
225 QMap< QString, QgsModelComponentGraphicItem * > outputItems;
229 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
230 const double outputOffsetX = algItem->size().width();
231 double outputOffsetY = 1.5 * algItem->size().height();
233 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
235 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
237 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
238 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
239 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
244 QPointF pos = outputIt.value().position();
247 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
248 outputOffsetY += 1.5 * outputIt.value().size().height();
253 if ( it.value().algorithm() )
258 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
268 outputItems.insert( outputIt.key(), item );
269 addItem(
new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle ) );
271 addCommentItemForComponent( model, outputIt.value(), item );
273 mOutputItems.insert( it.value().childId(), outputItems );
277 QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
279 QList<QgsModelComponentGraphicItem *> componentItemList;
281 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
282 for ( QGraphicsItem *item : graphicsItemList )
284 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
286 componentItemList.push_back( componentItem );
290 return componentItemList;
293 QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position )
const
296 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
298 for ( QGraphicsItem *graphicsItem : itemList )
300 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
302 return componentItem;
308 QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem(
const QString &uuid )
310 return mGroupBoxItems.value( uuid );
313 void QgsModelGraphicsScene::selectAll()
316 QgsModelComponentGraphicItem *focusedItem =
nullptr;
317 const QList<QGraphicsItem *> itemList = items();
318 for ( QGraphicsItem *graphicsItem : itemList )
320 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
322 componentItem->setSelected(
true );
324 focusedItem = componentItem;
327 emit selectedItemChanged( focusedItem );
330 void QgsModelGraphicsScene::deselectAll()
335 const QList<QGraphicsItem *> selectedItemList = selectedItems();
336 for ( QGraphicsItem *item : selectedItemList )
338 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
340 componentItem->setSelected(
false );
343 emit selectedItemChanged(
nullptr );
346 void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
351 item->setSelected(
true );
353 emit selectedItemChanged( item );
356 void QgsModelGraphicsScene::setChildAlgorithmResults(
const QVariantMap &results )
358 mChildResults = results;
360 for (
auto it = mChildResults.constBegin(); it != mChildResults.constEnd(); ++it )
362 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
364 item->setResults( it.value().toMap() );
369 void QgsModelGraphicsScene::setChildAlgorithmInputs(
const QVariantMap &inputs )
371 mChildInputs = inputs;
373 for (
auto it = mChildInputs.constBegin(); it != mChildInputs.constEnd(); ++it )
375 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
377 item->setInputs( it.value().toMap() );
382 QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model,
const QVariant &value,
const QString &childId,
QgsProcessingContext &context )
const
384 QList<QgsModelGraphicsScene::LinkSource> res;
385 if ( value.type() == QVariant::List )
387 const QVariantList list = value.toList();
388 for (
const QVariant &v : list )
389 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
391 else if ( value.type() == QVariant::StringList )
393 const QStringList list = value.toStringList();
394 for (
const QString &v : list )
395 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
397 else if ( value.canConvert< QgsProcessingModelChildParameterSource >() )
399 const QgsProcessingModelChildParameterSource source = value.value< QgsProcessingModelChildParameterSource >();
400 switch ( source.source() )
402 case QgsProcessingModelChildParameterSource::ModelParameter:
405 l.item = mParameterItems.value( source.parameterName() );
409 case QgsProcessingModelChildParameterSource::ChildOutput:
411 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
418 if ( output->name() == source.outputName() )
422 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
425 l.item = mChildAlgorithmItems.value( source.outputChildId() );
426 l.edge = Qt::BottomEdge;
429 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
431 QString short_message = tr(
"Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
432 QString long_message = tr(
"Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
433 QString title( tr(
"Algorithm link error" ) );
435 showWarning(
const_cast<QString &
>( short_message ),
const_cast<QString &
>( title ),
const_cast<QString &
>( long_message ) );
448 case QgsProcessingModelChildParameterSource::Expression:
450 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, context );
452 const QSet<QString> vars = exp.referencedVariables();
453 for (
const QString &v : vars )
455 if ( variables.contains( v ) )
457 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
463 case QgsProcessingModelChildParameterSource::StaticValue:
464 case QgsProcessingModelChildParameterSource::ExpressionText:
465 case QgsProcessingModelChildParameterSource::ModelOutput:
472 void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model,
const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
474 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
477 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
478 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
479 addItem( commentItem );
480 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
481 connect( commentItem, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
482 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
484 std::unique_ptr< QgsModelArrowItem > arrow = std::make_unique< QgsModelArrowItem >( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
485 arrow->setPenStyle( Qt::DotLine );
486 addItem( arrow.release() );
494 void QgsModelGraphicsScene::setMessageBar(
QgsMessageBar *messageBar )
496 mMessageBar = messageBar;
499 void QgsModelGraphicsScene::showWarning(
const QString &shortMessage,
const QString &title,
const QString &longMessage,
Qgis::MessageLevel level )
const
502 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
503 connect( detailsButton, &QPushButton::clicked, detailsButton, [ = ]
505 QgsMessageViewer *dialog =
new QgsMessageViewer( detailsButton );
506 dialog->setTitle( title );
508 dialog->showMessage();
510 messageWidget->layout()->addWidget( detailsButton );
511 mMessageBar->clearWidgets();
512 mMessageBar->pushWidget( messageWidget, level, 0 );