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.value().childOutputName(), 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 );
381QgsModelComponentGraphicItem *QgsModelGraphicsScene::outputItem(
const QString &childId,
const QString &childOutputName )
383 auto it = mOutputItems.constFind( childId );
384 if ( it == mOutputItems.constEnd() )
387 auto outputIt = it->constFind( childOutputName );
388 if ( outputIt == it->constEnd() )
391 return outputIt.value();
394void QgsModelGraphicsScene::selectAll()
397 QgsModelComponentGraphicItem *focusedItem =
nullptr;
398 const QList<QGraphicsItem *> itemList = items();
399 for ( QGraphicsItem *graphicsItem : itemList )
401 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( graphicsItem ) )
403 componentItem->setSelected(
true );
405 focusedItem = componentItem;
408 emit selectedItemChanged( focusedItem );
411void QgsModelGraphicsScene::deselectAll()
416 const QList<QGraphicsItem *> selectedItemList = selectedItems();
417 for ( QGraphicsItem *item : selectedItemList )
419 if ( QgsModelComponentGraphicItem *componentItem =
dynamic_cast<QgsModelComponentGraphicItem *
>( item ) )
421 componentItem->setSelected(
false );
424 emit selectedItemChanged(
nullptr );
427void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
432 item->setSelected(
true );
434 emit selectedItemChanged( item );
439 mLastResult = result;
442 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
444 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
446 item->setResults( it.value() );
450 mLastResultCount.clear();
452 for (
auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
454 QVariantMap inputs = childResults.value( it.key() ).inputs();
455 for (
auto inputIt = inputs.constBegin(); inputIt != inputs.constEnd(); inputIt++ )
459 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
462 mLastResultCount.insert( inputs.value( inputIt.key() ).toString(), vl->
featureCount() );
467 QVariantMap outputs = childResults.value( it.key() ).outputs();
468 for (
auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); outputIt++ )
472 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
475 mLastResultCount.insert( outputs.value( outputIt.key() ).toString(), vl->
featureCount() );
481 emit requestRebuildRequired();
484QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model,
const QVariant &value,
const QString &childId,
QgsProcessingContext &context )
const
486 QList<QgsModelGraphicsScene::LinkSource> res;
487 if ( value.userType() == QMetaType::Type::QVariantList )
489 const QVariantList list = value.toList();
490 for (
const QVariant &v : list )
491 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
493 else if ( value.userType() == QMetaType::Type::QStringList )
495 const QStringList list = value.toStringList();
496 for (
const QString &v : list )
497 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
499 else if ( value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
501 const QgsProcessingModelChildParameterSource source = value.value<QgsProcessingModelChildParameterSource>();
502 switch ( source.source() )
507 l.item = mParameterItems.value( source.parameterName() );
508 l.edge = Qt::BottomEdge;
516 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
523 if ( output->name() == source.outputName() )
527 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
530 l.item = mChildAlgorithmItems.value( source.outputChildId() );
531 l.edge = Qt::BottomEdge;
534 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
536 QString short_message = tr(
"Check output links for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
537 QString long_message = tr(
"Cannot link output for alg: %1" ).arg( model->childAlgorithm( source.outputChildId() ).algorithm()->name() );
538 QString title( tr(
"Algorithm link error" ) );
540 showWarning(
const_cast<QString &
>( short_message ),
const_cast<QString &
>( title ),
const_cast<QString &
>( long_message ) );
555 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, &context );
557 const QSet<QString> vars = exp.referencedVariables();
558 for (
const QString &v : vars )
560 if ( variables.contains( v ) )
562 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
577void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model,
const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
579 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
582 QgsModelComponentGraphicItem *commentItem = createCommentGraphicItem( model, component.comment()->clone(), parentItem );
583 commentItem->setPos( component.comment()->position().x(), component.comment()->position().y() );
584 addItem( commentItem );
585 connect( commentItem, &QgsModelComponentGraphicItem::requestModelRepaint,
this, &QgsModelGraphicsScene::rebuildRequired );
586 connect( commentItem, &QgsModelComponentGraphicItem::changed,
this, &QgsModelGraphicsScene::componentChanged );
587 connect( commentItem, &QgsModelComponentGraphicItem::aboutToChange,
this, &QgsModelGraphicsScene::componentAboutToChange );
589 auto arrow = std::make_unique<QgsModelArrowItem>( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
590 arrow->setPenStyle( Qt::DotLine );
591 addItem( arrow.release() );
595void QgsModelGraphicsScene::addFeatureCountItemForArrow( QgsModelArrowItem *arrow,
const QString &layerId )
597 if ( mFlags & FlagHideFeatureCount )
600 if ( !mLastResultCount.contains( layerId ) )
605 QString numberFeatureText = u
"[%1]"_s.arg( mLastResultCount.value( layerId ) );
606 QgsModelDesignerFeatureCountGraphicItem *featureCount =
new QgsModelDesignerFeatureCountGraphicItem( arrow, numberFeatureText );
607 addItem( featureCount );
616void QgsModelGraphicsScene::setMessageBar(
QgsMessageBar *messageBar )
618 mMessageBar = messageBar;
621void QgsModelGraphicsScene::showWarning(
const QString &shortMessage,
const QString &title,
const QString &longMessage,
Qgis::MessageLevel level )
const
624 QPushButton *detailsButton =
new QPushButton( tr(
"Details" ) );
625 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, title, longMessage] {
631 messageWidget->layout()->addWidget( detailsButton );
632 mMessageBar->clearWidgets();
633 mMessageBar->pushWidget( messageWidget, level, 0 );
636void QgsModelGraphicsScene::requestRebuildRequired()
638 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.