30#include <QGraphicsSceneMouseEvent>
31#include <QGraphicsTextItem>
35#include "moc_qgsmodelgraphicsscene.cpp"
37using namespace Qt::StringLiterals;
41QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
42 : QGraphicsScene( parent )
44 setItemIndexMethod( QGraphicsScene::NoIndex );
46 connect(
this, &QgsModelGraphicsScene::componentChanged,
this, &QgsModelGraphicsScene::updateBounds );
49QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
54void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
59void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag,
bool on )
67void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event )
69 if ( event->button() != Qt::LeftButton )
71 QGraphicsScene::mousePressEvent( event );
74void QgsModelGraphicsScene::updateBounds()
80 const QList<QGraphicsItem *> constItems = items();
81 for ( QGraphicsItem *item : constItems )
83 QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item );
85 bounds = bounds.united( componentItem->sceneBoundingRect() );
88 if ( bounds.isValid() )
91 bounds.adjust( -SCENE_COMPONENT_MARGIN, -SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN );
92 bounds.setLeft( std::floor( bounds.left() ) );
93 bounds.setTop( std::floor( bounds.top() ) );
94 bounds.setRight( std::ceil( bounds.right() ) );
95 bounds.setBottom( std::ceil( bounds.bottom() ) );
98 setSceneRect( bounds );
101QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param )
const
103 return new QgsModelParameterGraphicItem( param, model,
nullptr );
106QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child )
const
108 return new QgsModelChildAlgorithmGraphicItem( child, model,
nullptr );
111QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output )
const
113 return new QgsModelOutputGraphicItem( output, model,
nullptr );
116QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem )
const
118 return new QgsModelCommentGraphicItem( comment, parentItem, model,
nullptr );
121QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box )
const
123 return new QgsModelGroupBoxGraphicItem( box, model,
nullptr );
126void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model,
QgsProcessingContext &context )
129 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
130 mGroupBoxItems.clear();
131 for (
const QgsProcessingModelGroupBox &box : boxes )
133 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
135 item->setPos( box.position().x(), box.position().y() );
136 mGroupBoxItems.insert( box.uuid(), item );
137 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
138 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
139 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
143 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
144 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
146 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
148 item->setPos( it.value().position().x(), it.value().position().y() );
149 mParameterItems.insert( it.value().parameterName(), item );
150 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
151 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
152 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
154 addCommentItemForComponent( model, it.value(), item );
158 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
162 for (
const QString &otherName : parameterLinks )
164 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
166 auto arrow = std::make_unique<QgsModelArrowItem>( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
167 arrow->setPenStyle( Qt::DotLine );
168 addItem( arrow.release() );
174 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
175 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
177 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
179 item->setPos( it.value().position().x(), it.value().position().y() );
181 const QString childId = it.value().childId();
182 item->setResults( mLastResult.childResults().value( childId ) );
183 mChildAlgorithmItems.insert( childId, item );
184 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
185 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
186 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
187 connect( item, &QgsModelChildAlgorithmGraphicItem::runFromHere,
this, [
this, childId] { emit runFromChild( childId ); } );
188 connect( item, &QgsModelChildAlgorithmGraphicItem::runSelected,
this, &QgsModelGraphicsScene::runSelected );
189 connect( item, &QgsModelChildAlgorithmGraphicItem::showPreviousResults,
this, [
this, childId] { emit showChildAlgorithmOutputs( childId ); } );
190 connect( item, &QgsModelChildAlgorithmGraphicItem::showLog,
this, [
this, childId] { emit showChildAlgorithmLog( childId ); } );
192 addCommentItemForComponent( model, it.value(), item );
196 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
200 if ( !it.value().algorithm() )
208 QList<QgsProcessingModelChildParameterSource> sources;
209 if ( it.value().parameterSources().contains( parameter->name() ) )
210 sources = it.value().parameterSources()[parameter->name()];
211 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
213 const QList<LinkSource> sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
214 for (
const LinkSource &link : sourceItems )
218 QgsModelArrowItem *arrow =
nullptr;
219 if ( link.linkIndex == -1 )
221 arrow =
new QgsModelArrowItem(
223 QgsModelArrowItem::Marker::NoMarker,
224 mChildAlgorithmItems.value( it.value().childId() ),
225 parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
226 parameter->isDestination() ? bottomIdx : topIdx,
227 QgsModelArrowItem::Marker::Circle
232 arrow =
new QgsModelArrowItem(
237 QgsModelArrowItem::Marker::NoMarker,
238 mChildAlgorithmItems.value( it.value().childId() ),
239 parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
240 parameter->isDestination() ? bottomIdx : topIdx,
242 QgsModelArrowItem::Marker::NoMarker
247 if ( QgsModelChildAlgorithmGraphicItem *childAlgItem = mChildAlgorithmItems.value( it.value().childId() ) )
249 QString layerId = childAlgItem->results().inputs().value( parameter->name() ).toString();
250 addFeatureCountItemForArrow( arrow, layerId );
254 if ( parameter->isDestination() )
260 const QList<QgsProcessingModelChildDependency> dependencies = it.value().dependencies();
261 for (
const QgsProcessingModelChildDependency &depend : dependencies )
263 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
266 new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead )
277 if ( output->name() == depend.conditionalBranch )
286 new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead )
293 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
295 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
296 QMap<QString, QgsModelComponentGraphicItem *> outputItems;
300 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
301 const double outputOffsetX = algItem->size().width();
302 double outputOffsetY = 1.5 * algItem->size().height();
304 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
306 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
308 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
309 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
310 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
315 QPointF pos = outputIt.value().position();
318 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
319 outputOffsetY += 1.5 * outputIt.value().size().height();
324 if ( it.value().algorithm() )
329 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
339 item->component()->setPosition( pos );
340 outputItems.insert( outputIt.value().childOutputName(), item );
341 QgsModelArrowItem *arrow =
new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle );
344 if ( QgsModelChildAlgorithmGraphicItem *childItem = mChildAlgorithmItems.value( it.value().childId() ) )
346 QString layerId = childItem->results().outputs().value( outputIt.value().childOutputName() ).toString();
347 addFeatureCountItemForArrow( arrow, layerId );
350 addCommentItemForComponent( model, outputIt.value(), item );
352 mOutputItems.insert( it.value().childId(), outputItems );
356QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
358 QList<QgsModelComponentGraphicItem *> componentItemList;
360 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
361 for ( QGraphicsItem *item : graphicsItemList )
363 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
365 componentItemList.push_back( componentItem );
369 return componentItemList;
372QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position )
const
375 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
377 for ( QGraphicsItem *graphicsItem : itemList )
379 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
381 return componentItem;
387QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem(
const QString &uuid )
389 return mGroupBoxItems.value( uuid );
392QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::childAlgorithmItem(
const QString &childId )
394 return mChildAlgorithmItems.value( childId );
397QgsModelComponentGraphicItem *QgsModelGraphicsScene::parameterItem(
const QString &name )
399 return mParameterItems.value( name );
402QgsModelComponentGraphicItem *QgsModelGraphicsScene::outputItem(
const QString &childId,
const QString &childOutputName )
404 auto it = mOutputItems.constFind( childId );
405 if ( it == mOutputItems.constEnd() )
408 auto outputIt = it->constFind( childOutputName );
409 if ( outputIt == it->constEnd() )
412 return outputIt.value();
415void QgsModelGraphicsScene::selectAll()
418 QgsModelComponentGraphicItem *focusedItem =
nullptr;
419 const QList<QGraphicsItem *> itemList = items();
420 for ( QGraphicsItem *graphicsItem : itemList )
422 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
424 componentItem->setSelected(
true );
426 focusedItem = componentItem;
429 emit selectedItemChanged( focusedItem );
432void QgsModelGraphicsScene::deselectAll()
437 const QList<QGraphicsItem *> selectedItemList = selectedItems();
438 for ( QGraphicsItem *item : selectedItemList )
440 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
442 componentItem->setSelected(
false );
445 emit selectedItemChanged(
nullptr );
448void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
453 item->setSelected(
true );
455 emit selectedItemChanged( item );
460 mLastResult = result;
463 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
465 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
467 item->setResults( it.value() );
471 mLastResultCount.clear();
473 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
475 QVariantMap inputs = childResults.value( it.key() ).inputs();
476 for (
auto inputIt = inputs.constBegin(); inputIt != inputs.constEnd(); inputIt++ )
480 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
483 mLastResultCount.insert( inputs.value( inputIt.key() ).toString(), vl->
featureCount() );
488 QVariantMap outputs = childResults.value( it.key() ).outputs();
489 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); outputIt++ )
493 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
496 mLastResultCount.insert( outputs.value( outputIt.key() ).toString(), vl->
featureCount() );
502 emit requestRebuildRequired();
505QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue(
506 QgsProcessingModelAlgorithm *model,
const QVariant &value,
const QString &childId,
QgsProcessingContext &context
509 QList<QgsModelGraphicsScene::LinkSource> res;
510 if ( value.userType() == QMetaType::Type::QVariantList )
512 const QVariantList list = value.toList();
513 for (
const QVariant &v : list )
514 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
516 else if ( value.userType() == QMetaType::Type::QStringList )
518 const QStringList list = value.toStringList();
519 for (
const QString &v : list )
520 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
522 else if ( value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
524 const QgsProcessingModelChildParameterSource source = value.value<QgsProcessingModelChildParameterSource>();
525 switch ( source.source() )
530 l.item = mParameterItems.value( source.parameterName() );
531 l.edge = Qt::BottomEdge;
539 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
546 if ( output->name() == source.outputName() )
550 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
553 l.item = mChildAlgorithmItems.value( source.outputChildId() );
554 l.edge = Qt::BottomEdge;
557 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
559 QString short_message = tr(
"Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
560 QString long_message = tr(
"Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
561 QString title( tr(
"Algorithm link error" ) );
563 showWarning(
const_cast<QString &
>( short_message ),
const_cast<QString &
>( title ),
const_cast<QString &
>( long_message ) );
578 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, &context );
580 const QSet<QString> vars = exp.referencedVariables();
581 for (
const QString &v : vars )
583 if ( variables.contains( v ) )
585 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
600void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model,
const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
602 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
605 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
606 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
607 addItem( commentItem );
608 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
609 connect( commentItem, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
610 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
612 auto arrow = std::make_unique<QgsModelArrowItem>( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
613 arrow->setPenStyle( Qt::DotLine );
614 addItem( arrow.release() );
618void QgsModelGraphicsScene::addFeatureCountItemForArrow( QgsModelArrowItem *arrow,
const QString &layerId )
620 if ( mFlags & FlagHideFeatureCount )
623 if ( !mLastResultCount.contains( layerId ) )
628 QString numberFeatureText = u
"[%1]"_s.arg( mLastResultCount.value( layerId ) );
629 QgsModelDesignerFeatureCountGraphicItem *featureCount =
new QgsModelDesignerFeatureCountGraphicItem( arrow, numberFeatureText );
630 addItem( featureCount );
639void QgsModelGraphicsScene::setMessageBar(
QgsMessageBar *messageBar )
641 mMessageBar = messageBar;
644void QgsModelGraphicsScene::showWarning(
const QString &shortMessage,
const QString &title,
const QString &longMessage,
Qgis::MessageLevel level )
const
647 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
648 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, title, longMessage] {
654 messageWidget->layout()->addWidget( detailsButton );
655 mMessageBar->clearWidgets();
656 mMessageBar->pushWidget( messageWidget, level, 0 );
659void QgsModelGraphicsScene::requestRebuildRequired()
661 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").
Base class for all map layer types.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
A generic message view for displaying QGIS messages.
void setMessage(const QString &message, Qgis::StringFormat format) override
Sets message, it won't be displayed until.
void setTitle(const QString &title) override
Sets title for the messages.
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.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
Represents a vector layer which manages a vector based dataset.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
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.