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() )
90 bounds.adjust( -SCENE_COMPONENT_MARGIN, -SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN, SCENE_COMPONENT_MARGIN );
93 setSceneRect( bounds );
96QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param )
const
98 return new QgsModelParameterGraphicItem( param, model,
nullptr );
101QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child )
const
103 return new QgsModelChildAlgorithmGraphicItem( child, model,
nullptr );
106QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output )
const
108 return new QgsModelOutputGraphicItem( output, model,
nullptr );
111QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem )
const
113 return new QgsModelCommentGraphicItem( comment, parentItem, model,
nullptr );
116QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box )
const
118 return new QgsModelGroupBoxGraphicItem( box, model,
nullptr );
121void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model,
QgsProcessingContext &context )
124 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
125 mGroupBoxItems.clear();
126 for (
const QgsProcessingModelGroupBox &box : boxes )
128 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
130 item->setPos( box.position().x(), box.position().y() );
131 mGroupBoxItems.insert( box.uuid(), item );
132 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
133 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
134 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
138 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
139 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
141 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
143 item->setPos( it.value().position().x(), it.value().position().y() );
144 mParameterItems.insert( it.value().parameterName(), item );
145 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
146 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
147 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
149 addCommentItemForComponent( model, it.value(), item );
153 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
157 for (
const QString &otherName : parameterLinks )
159 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
161 auto arrow = std::make_unique<QgsModelArrowItem>( mParameterItems.value( otherName ), QgsModelArrowItem::Marker::Circle, mParameterItems.value( it.key() ), QgsModelArrowItem::Marker::ArrowHead );
162 arrow->setPenStyle( Qt::DotLine );
163 addItem( arrow.release() );
169 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
170 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
172 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
174 item->setPos( it.value().position().x(), it.value().position().y() );
176 const QString childId = it.value().childId();
177 item->setResults( mLastResult.childResults().value( childId ) );
178 mChildAlgorithmItems.insert( childId, item );
179 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
180 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
181 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
182 connect( item, &QgsModelChildAlgorithmGraphicItem::runFromHere,
this, [
this, childId] {
183 emit runFromChild( childId );
185 connect( item, &QgsModelChildAlgorithmGraphicItem::runSelected,
this, &QgsModelGraphicsScene::runSelected );
186 connect( item, &QgsModelChildAlgorithmGraphicItem::showPreviousResults,
this, [
this, childId] {
187 emit showChildAlgorithmOutputs( childId );
189 connect( item, &QgsModelChildAlgorithmGraphicItem::showLog,
this, [
this, childId] {
190 emit showChildAlgorithmLog( childId );
193 addCommentItemForComponent( model, it.value(), item );
197 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
201 if ( !it.value().algorithm() )
209 QList<QgsProcessingModelChildParameterSource> sources;
210 if ( it.value().parameterSources().contains( parameter->name() ) )
211 sources = it.value().parameterSources()[parameter->name()];
212 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
214 const QList<LinkSource> sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
215 for (
const LinkSource &link : sourceItems )
219 QgsModelArrowItem *arrow =
nullptr;
220 if ( link.linkIndex == -1 )
222 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 );
226 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 );
230 if ( QgsModelChildAlgorithmGraphicItem *childAlgItem = mChildAlgorithmItems.value( it.value().childId() ) )
232 QString layerId = childAlgItem->results().inputs().value( parameter->name() ).toString();
233 addFeatureCountItemForArrow( arrow, layerId );
237 if ( parameter->isDestination() )
243 const QList<QgsProcessingModelChildDependency> dependencies = it.value().dependencies();
244 for (
const QgsProcessingModelChildDependency &depend : dependencies )
246 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
248 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
258 if ( output->name() == depend.conditionalBranch )
266 addItem(
new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead ) );
272 for (
auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
274 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
275 QMap<QString, QgsModelComponentGraphicItem *> outputItems;
279 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
280 const double outputOffsetX = algItem->size().width();
281 double outputOffsetY = 1.5 * algItem->size().height();
283 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
285 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
287 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
288 connect( item, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
289 connect( item, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
294 QPointF pos = outputIt.value().position();
297 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
298 outputOffsetY += 1.5 * outputIt.value().size().height();
303 if ( it.value().algorithm() )
308 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
318 item->component()->setPosition( pos );
319 outputItems.insert( outputIt.key(), item );
320 QgsModelArrowItem *arrow =
new QgsModelArrowItem( mChildAlgorithmItems[it.value().childId()], Qt::BottomEdge, idx, QgsModelArrowItem::Marker::Circle, item, QgsModelArrowItem::Marker::Circle );
323 if ( QgsModelChildAlgorithmGraphicItem *childItem = mChildAlgorithmItems.value( it.value().childId() ) )
325 QString layerId = childItem->results().outputs().value( outputIt.value().childOutputName() ).toString();
326 addFeatureCountItemForArrow( arrow, layerId );
329 addCommentItemForComponent( model, outputIt.value(), item );
331 mOutputItems.insert( it.value().childId(), outputItems );
335QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
337 QList<QgsModelComponentGraphicItem *> componentItemList;
339 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
340 for ( QGraphicsItem *item : graphicsItemList )
342 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
344 componentItemList.push_back( componentItem );
348 return componentItemList;
351QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position )
const
354 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
356 for ( QGraphicsItem *graphicsItem : itemList )
358 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
360 return componentItem;
366QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem(
const QString &uuid )
368 return mGroupBoxItems.value( uuid );
371QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::childAlgorithmItem(
const QString &childId )
373 return mChildAlgorithmItems.value( childId );
376QgsModelComponentGraphicItem *QgsModelGraphicsScene::parameterItem(
const QString &name )
378 return mParameterItems.value( name );
381void QgsModelGraphicsScene::selectAll()
384 QgsModelComponentGraphicItem *focusedItem =
nullptr;
385 const QList<QGraphicsItem *> itemList = items();
386 for ( QGraphicsItem *graphicsItem : itemList )
388 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
390 componentItem->setSelected(
true );
392 focusedItem = componentItem;
395 emit selectedItemChanged( focusedItem );
398void QgsModelGraphicsScene::deselectAll()
403 const QList<QGraphicsItem *> selectedItemList = selectedItems();
404 for ( QGraphicsItem *item : selectedItemList )
406 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
408 componentItem->setSelected(
false );
411 emit selectedItemChanged(
nullptr );
414void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
419 item->setSelected(
true );
421 emit selectedItemChanged( item );
426 mLastResult = result;
429 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
431 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
433 item->setResults( it.value() );
437 mLastResultCount.clear();
439 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
441 QVariantMap inputs = childResults.value( it.key() ).inputs();
442 for (
auto inputIt = inputs.constBegin(); inputIt != inputs.constEnd(); inputIt++ )
446 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
449 mLastResultCount.insert( inputs.value( inputIt.key() ).toString(), vl->
featureCount() );
454 QVariantMap outputs = childResults.value( it.key() ).outputs();
455 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); outputIt++ )
459 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
462 mLastResultCount.insert( outputs.value( outputIt.key() ).toString(), vl->
featureCount() );
468 emit requestRebuildRequired();
471QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model,
const QVariant &value,
const QString &childId,
QgsProcessingContext &context )
const
473 QList<QgsModelGraphicsScene::LinkSource> res;
474 if ( value.userType() == QMetaType::Type::QVariantList )
476 const QVariantList list = value.toList();
477 for (
const QVariant &v : list )
478 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
480 else if ( value.userType() == QMetaType::Type::QStringList )
482 const QStringList list = value.toStringList();
483 for (
const QString &v : list )
484 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
486 else if ( value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
488 const QgsProcessingModelChildParameterSource source = value.value<QgsProcessingModelChildParameterSource>();
489 switch ( source.source() )
494 l.item = mParameterItems.value( source.parameterName() );
495 l.edge = Qt::BottomEdge;
503 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
510 if ( output->name() == source.outputName() )
514 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
517 l.item = mChildAlgorithmItems.value( source.outputChildId() );
518 l.edge = Qt::BottomEdge;
521 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
523 QString short_message = tr(
"Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
524 QString long_message = tr(
"Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
525 QString title( tr(
"Algorithm link error" ) );
527 showWarning(
const_cast<QString &
>( short_message ),
const_cast<QString &
>( title ),
const_cast<QString &
>( long_message ) );
542 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, &context );
544 const QSet<QString> vars = exp.referencedVariables();
545 for (
const QString &v : vars )
547 if ( variables.contains( v ) )
549 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
564void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model,
const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
566 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
569 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
570 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
571 addItem( commentItem );
572 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
573 connect( commentItem, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
574 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
576 auto arrow = std::make_unique<QgsModelArrowItem>( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
577 arrow->setPenStyle( Qt::DotLine );
578 addItem( arrow.release() );
582void QgsModelGraphicsScene::addFeatureCountItemForArrow( QgsModelArrowItem *arrow,
const QString &layerId )
584 if ( mFlags & FlagHideFeatureCount )
587 if ( !mLastResultCount.contains( layerId ) )
592 QString numberFeatureText = u
"[%1]"_s.arg( mLastResultCount.value( layerId ) );
593 QgsModelDesignerFeatureCountGraphicItem *featureCount =
new QgsModelDesignerFeatureCountGraphicItem( arrow, numberFeatureText );
594 addItem( featureCount );
603void QgsModelGraphicsScene::setMessageBar(
QgsMessageBar *messageBar )
605 mMessageBar = messageBar;
608void QgsModelGraphicsScene::showWarning(
const QString &shortMessage,
const QString &title,
const QString &longMessage,
Qgis::MessageLevel level )
const
611 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
612 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, title, longMessage] {
618 messageWidget->layout()->addWidget( detailsButton );
619 mMessageBar->clearWidgets();
620 mMessageBar->pushWidget( messageWidget, level, 0 );
623void QgsModelGraphicsScene::requestRebuildRequired()
625 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())
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.
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.