QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgsmodelgraphicsscene.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmodelgraphicsscene.cpp
3 ----------------------------------
4 Date : March 2020
5 Copyright : (C) 2020 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsmessagebar.h"
19#include "qgsmessagebaritem.h"
20#include "qgsmessagelog.h"
21#include "qgsmessageviewer.h"
22#include "qgsmodelarrowitem.h"
24#include "qgsmodelgraphicitem.h"
28#include "qgsvectorlayer.h"
29
30#include <QGraphicsSceneMouseEvent>
31#include <QGraphicsTextItem>
32#include <QPushButton>
33#include <QString>
34
35#include "moc_qgsmodelgraphicsscene.cpp"
36
37using namespace Qt::StringLiterals;
38
40
41QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
42 : QGraphicsScene( parent )
43{
44 setItemIndexMethod( QGraphicsScene::NoIndex );
45
46 connect( this, &QgsModelGraphicsScene::componentChanged, this, &QgsModelGraphicsScene::updateBounds );
47}
48
49QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
50{
51 return mModel;
52}
53
54void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
55{
56 mModel = model;
57}
58
59void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag, bool on )
60{
61 if ( on )
62 mFlags |= flag;
63 else
64 mFlags &= ~flag;
65}
66
67void QgsModelGraphicsScene::mousePressEvent( QGraphicsSceneMouseEvent *event )
68{
69 if ( event->button() != Qt::LeftButton )
70 return;
71 QGraphicsScene::mousePressEvent( event );
72}
73
74void QgsModelGraphicsScene::updateBounds()
75{
76 //start with an empty rectangle
77 QRectF bounds;
78
79 //add all items
80 const QList<QGraphicsItem *> constItems = items();
81 for ( QGraphicsItem *item : constItems )
82 {
83 QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item );
84 if ( componentItem )
85 bounds = bounds.united( componentItem->sceneBoundingRect() );
86 }
87
88 if ( bounds.isValid() )
89 {
90 // Add a margin and ensure bounds are rounded to integer-like values
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() ) );
96 }
97
98 setSceneRect( bounds );
99}
100
101QgsModelComponentGraphicItem *QgsModelGraphicsScene::createParameterGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelParameter *param ) const
102{
103 return new QgsModelParameterGraphicItem( param, model, nullptr );
104}
105
106QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::createChildAlgGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelChildAlgorithm *child ) const
107{
108 return new QgsModelChildAlgorithmGraphicItem( child, model, nullptr );
109}
110
111QgsModelComponentGraphicItem *QgsModelGraphicsScene::createOutputGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelOutput *output ) const
112{
113 return new QgsModelOutputGraphicItem( output, model, nullptr );
114}
115
116QgsModelComponentGraphicItem *QgsModelGraphicsScene::createCommentGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem ) const
117{
118 return new QgsModelCommentGraphicItem( comment, parentItem, model, nullptr );
119}
120
121QgsModelComponentGraphicItem *QgsModelGraphicsScene::createGroupBoxGraphicItem( QgsProcessingModelAlgorithm *model, QgsProcessingModelGroupBox *box ) const
122{
123 return new QgsModelGroupBoxGraphicItem( box, model, nullptr );
124}
125
126void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, QgsProcessingContext &context )
127{
128 // model group boxes
129 const QList<QgsProcessingModelGroupBox> boxes = model->groupBoxes();
130 mGroupBoxItems.clear();
131 for ( const QgsProcessingModelGroupBox &box : boxes )
132 {
133 QgsModelComponentGraphicItem *item = createGroupBoxGraphicItem( model, box.clone() );
134 addItem( item );
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 );
140 }
141
142 // model input parameters
143 const QMap<QString, QgsProcessingModelParameter> params = model->parameterComponents();
144 for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
145 {
146 QgsModelComponentGraphicItem *item = createParameterGraphicItem( model, it.value().clone() );
147 addItem( item );
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 );
153
154 addCommentItemForComponent( model, it.value(), item );
155 }
156
157 // input dependency arrows
158 for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
159 {
160 const QgsProcessingParameterDefinition *parameterDef = model->parameterDefinition( it.key() );
161 const QStringList parameterLinks = parameterDef->dependsOnOtherParameters();
162 for ( const QString &otherName : parameterLinks )
163 {
164 if ( mParameterItems.contains( it.key() ) && mParameterItems.contains( otherName ) )
165 {
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() );
169 }
170 }
171 }
172
173 // child algorithms
174 const QMap<QString, QgsProcessingModelChildAlgorithm> childAlgs = model->childAlgorithms();
175 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
176 {
177 QgsModelChildAlgorithmGraphicItem *item = createChildAlgGraphicItem( model, it.value().clone() );
178 addItem( item );
179 item->setPos( it.value().position().x(), it.value().position().y() );
180
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 ); } );
191
192 addCommentItemForComponent( model, it.value(), item );
193 }
194
195 // arrows linking child algorithms
196 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
197 {
198 int topIdx = 0;
199 int bottomIdx = 0;
200 if ( !it.value().algorithm() )
201 continue;
202
203 const QgsProcessingParameterDefinitions parameters = it.value().algorithm()->parameterDefinitions();
204 for ( const QgsProcessingParameterDefinition *parameter : parameters )
205 {
206 if ( !( parameter->flags() & Qgis::ProcessingParameterFlag::Hidden ) )
207 {
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 ) )
212 {
213 const QList<LinkSource> sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
214 for ( const LinkSource &link : sourceItems )
215 {
216 if ( !link.item )
217 continue;
218 QgsModelArrowItem *arrow = nullptr;
219 if ( link.linkIndex == -1 )
220 {
221 arrow = new QgsModelArrowItem(
222 link.item,
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
228 );
229 }
230 else
231 {
232 arrow = new QgsModelArrowItem(
233 link.item,
234 link.edge,
235 link.linkIndex,
236 true,
237 QgsModelArrowItem::Marker::NoMarker,
238 mChildAlgorithmItems.value( it.value().childId() ),
239 parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge,
240 parameter->isDestination() ? bottomIdx : topIdx,
241 true,
242 QgsModelArrowItem::Marker::NoMarker
243 );
244 }
245 addItem( arrow );
246
247 if ( QgsModelChildAlgorithmGraphicItem *childAlgItem = mChildAlgorithmItems.value( it.value().childId() ) )
248 {
249 QString layerId = childAlgItem->results().inputs().value( parameter->name() ).toString();
250 addFeatureCountItemForArrow( arrow, layerId );
251 }
252 }
253 }
254 if ( parameter->isDestination() )
255 bottomIdx++;
256 else
257 topIdx++;
258 }
259 }
260 const QList<QgsProcessingModelChildDependency> dependencies = it.value().dependencies();
261 for ( const QgsProcessingModelChildDependency &depend : dependencies )
262 {
263 if ( depend.conditionalBranch.isEmpty() || !model->childAlgorithm( depend.childId ).algorithm() )
264 {
265 addItem(
266 new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead )
267 );
268 }
269 else
270 {
271 // find branch link point
272 const QgsProcessingOutputDefinitions outputs = model->childAlgorithm( depend.childId ).algorithm()->outputDefinitions();
273 int i = 0;
274 bool found = false;
275 for ( const QgsProcessingOutputDefinition *output : outputs )
276 {
277 if ( output->name() == depend.conditionalBranch )
278 {
279 found = true;
280 break;
281 }
282 i++;
283 }
284 if ( found )
285 addItem(
286 new QgsModelArrowItem( mChildAlgorithmItems.value( depend.childId ), Qt::BottomEdge, i, QgsModelArrowItem::Marker::Circle, mChildAlgorithmItems.value( it.value().childId() ), QgsModelArrowItem::Marker::ArrowHead )
287 );
288 }
289 }
290 }
291
292 // and finally the model outputs
293 for ( auto it = childAlgs.constBegin(); it != childAlgs.constEnd(); ++it )
294 {
295 const QMap<QString, QgsProcessingModelOutput> outputs = it.value().modelOutputs();
296 QMap<QString, QgsModelComponentGraphicItem *> outputItems;
297
298 // offsets from algorithm item needed to correctly place output items
299 // which does not have valid position assigned (https://github.com/qgis/QGIS/issues/48132)
300 QgsProcessingModelComponent *algItem = mChildAlgorithmItems[it.value().childId()]->component();
301 const double outputOffsetX = algItem->size().width();
302 double outputOffsetY = 1.5 * algItem->size().height();
303
304 for ( auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); ++outputIt )
305 {
306 QgsModelComponentGraphicItem *item = createOutputGraphicItem( model, outputIt.value().clone() );
307 addItem( item );
308 connect( item, &QgsModelComponentGraphicItem::requestModelRepaint, this, &QgsModelGraphicsScene::rebuildRequired );
309 connect( item, &QgsModelComponentGraphicItem::changed, this, &QgsModelGraphicsScene::componentChanged );
310 connect( item, &QgsModelComponentGraphicItem::aboutToChange, this, &QgsModelGraphicsScene::componentAboutToChange );
311
312 // if output added not at the same time as algorithm then it does not have
313 // valid position and will be placed at (0,0). We need to calculate better position.
314 // See https://github.com/qgis/QGIS/issues/48132.
315 QPointF pos = outputIt.value().position();
316 if ( pos.isNull() )
317 {
318 pos = algItem->position() + QPointF( outputOffsetX, outputOffsetY );
319 outputOffsetY += 1.5 * outputIt.value().size().height();
320 }
321 int idx = -1;
322 int i = 0;
323 // find the actual index of the linked output from the child algorithm it comes from
324 if ( it.value().algorithm() )
325 {
326 const QgsProcessingOutputDefinitions sourceChildAlgOutputs = it.value().algorithm()->outputDefinitions();
327 for ( const QgsProcessingOutputDefinition *childAlgOutput : sourceChildAlgOutputs )
328 {
329 if ( childAlgOutput->name() == outputIt.value().childOutputName() )
330 {
331 idx = i;
332 break;
333 }
334 i++;
335 }
336 }
337
338 item->setPos( pos );
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 );
342 addItem( arrow );
343
344 if ( QgsModelChildAlgorithmGraphicItem *childItem = mChildAlgorithmItems.value( it.value().childId() ) )
345 {
346 QString layerId = childItem->results().outputs().value( outputIt.value().childOutputName() ).toString();
347 addFeatureCountItemForArrow( arrow, layerId );
348 }
349
350 addCommentItemForComponent( model, outputIt.value(), item );
351 }
352 mOutputItems.insert( it.value().childId(), outputItems );
353 }
354}
355
356QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
357{
358 QList<QgsModelComponentGraphicItem *> componentItemList;
359
360 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
361 for ( QGraphicsItem *item : graphicsItemList )
362 {
363 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
364 {
365 componentItemList.push_back( componentItem );
366 }
367 }
368
369 return componentItemList;
370}
371
372QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position ) const
373{
374 //get a list of items which intersect the specified position, in descending z order
375 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
376
377 for ( QGraphicsItem *graphicsItem : itemList )
378 {
379 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
380 {
381 return componentItem;
382 }
383 }
384 return nullptr;
385}
386
387QgsModelComponentGraphicItem *QgsModelGraphicsScene::groupBoxItem( const QString &uuid )
388{
389 return mGroupBoxItems.value( uuid );
390}
391
392QgsModelChildAlgorithmGraphicItem *QgsModelGraphicsScene::childAlgorithmItem( const QString &childId )
393{
394 return mChildAlgorithmItems.value( childId );
395}
396
397QgsModelComponentGraphicItem *QgsModelGraphicsScene::parameterItem( const QString &name )
398{
399 return mParameterItems.value( name );
400}
401
402QgsModelComponentGraphicItem *QgsModelGraphicsScene::outputItem( const QString &childId, const QString &childOutputName )
403{
404 auto it = mOutputItems.constFind( childId );
405 if ( it == mOutputItems.constEnd() )
406 return nullptr;
407
408 auto outputIt = it->constFind( childOutputName );
409 if ( outputIt == it->constEnd() )
410 return nullptr;
411
412 return outputIt.value();
413}
414
415void QgsModelGraphicsScene::selectAll()
416{
417 //select all items in scene
418 QgsModelComponentGraphicItem *focusedItem = nullptr;
419 const QList<QGraphicsItem *> itemList = items();
420 for ( QGraphicsItem *graphicsItem : itemList )
421 {
422 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( graphicsItem ) )
423 {
424 componentItem->setSelected( true );
425 if ( !focusedItem )
426 focusedItem = componentItem;
427 }
428 }
429 emit selectedItemChanged( focusedItem );
430}
431
432void QgsModelGraphicsScene::deselectAll()
433{
434 //we can't use QGraphicsScene::clearSelection, as that emits no signals
435 //and we don't know which items are being deselected
436 //instead, do the clear selection manually...
437 const QList<QGraphicsItem *> selectedItemList = selectedItems();
438 for ( QGraphicsItem *item : selectedItemList )
439 {
440 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
441 {
442 componentItem->setSelected( false );
443 }
444 }
445 emit selectedItemChanged( nullptr );
446}
447
448void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item )
449{
450 whileBlocking( this )->deselectAll();
451 if ( item )
452 {
453 item->setSelected( true );
454 }
455 emit selectedItemChanged( item );
456}
457
458void QgsModelGraphicsScene::setLastRunResult( const QgsProcessingModelResult &result, QgsProcessingContext &context )
459{
460 mLastResult = result;
461
462 const auto childResults = mLastResult.childResults();
463 for ( auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
464 {
465 if ( QgsModelChildAlgorithmGraphicItem *item = mChildAlgorithmItems.value( it.key() ) )
466 {
467 item->setResults( it.value() );
468 }
469 }
470
471 mLastResultCount.clear();
472 // Match inputs and outputs to corresponding layer and get feature counts if possible
473 for ( auto it = childResults.constBegin(); it != childResults.constEnd(); ++it )
474 {
475 QVariantMap inputs = childResults.value( it.key() ).inputs();
476 for ( auto inputIt = inputs.constBegin(); inputIt != inputs.constEnd(); inputIt++ )
477 {
478 if ( QgsMapLayer *resultMapLayer = QgsProcessingUtils::mapLayerFromString( inputs.value( inputIt.key() ).toString(), context, false ) )
479 {
480 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
481 if ( vl && vl->featureCount() >= 0 )
482 {
483 mLastResultCount.insert( inputs.value( inputIt.key() ).toString(), vl->featureCount() );
484 }
485 }
486 }
487
488 QVariantMap outputs = childResults.value( it.key() ).outputs();
489 for ( auto outputIt = outputs.constBegin(); outputIt != outputs.constEnd(); outputIt++ )
490 {
491 if ( QgsMapLayer *resultMapLayer = QgsProcessingUtils::mapLayerFromString( outputs.value( outputIt.key() ).toString(), context, false ) )
492 {
493 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( resultMapLayer );
494 if ( vl && vl->featureCount() >= 0 )
495 {
496 mLastResultCount.insert( outputs.value( outputIt.key() ).toString(), vl->featureCount() );
497 }
498 }
499 }
500 }
501
502 emit requestRebuildRequired();
503}
504
505QList<QgsModelGraphicsScene::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue(
506 QgsProcessingModelAlgorithm *model, const QVariant &value, const QString &childId, QgsProcessingContext &context
507) const
508{
509 QList<QgsModelGraphicsScene::LinkSource> res;
510 if ( value.userType() == QMetaType::Type::QVariantList )
511 {
512 const QVariantList list = value.toList();
513 for ( const QVariant &v : list )
514 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
515 }
516 else if ( value.userType() == QMetaType::Type::QStringList )
517 {
518 const QStringList list = value.toStringList();
519 for ( const QString &v : list )
520 res.append( linkSourcesForParameterValue( model, v, childId, context ) );
521 }
522 else if ( value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
523 {
524 const QgsProcessingModelChildParameterSource source = value.value<QgsProcessingModelChildParameterSource>();
525 switch ( source.source() )
526 {
528 {
529 LinkSource l;
530 l.item = mParameterItems.value( source.parameterName() );
531 l.edge = Qt::BottomEdge;
532 l.linkIndex = 0;
533
534 res.append( l );
535 break;
536 }
538 {
539 if ( !model->childAlgorithm( source.outputChildId() ).algorithm() )
540 break;
541
542 const QgsProcessingOutputDefinitions outputs = model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions();
543 int i = 0;
544 for ( const QgsProcessingOutputDefinition *output : outputs )
545 {
546 if ( output->name() == source.outputName() )
547 break;
548 i++;
549 }
550 if ( mChildAlgorithmItems.contains( source.outputChildId() ) )
551 {
552 LinkSource l;
553 l.item = mChildAlgorithmItems.value( source.outputChildId() );
554 l.edge = Qt::BottomEdge;
555
556 // do sanity check of linked index
557 if ( i >= model->childAlgorithm( source.outputChildId() ).algorithm()->outputDefinitions().length() )
558 {
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" ) );
562 if ( messageBar() )
563 showWarning( const_cast<QString &>( short_message ), const_cast<QString &>( title ), const_cast<QString &>( long_message ) );
564 else
565 QgsMessageLog::logMessage( long_message, "QgsModelGraphicsScene", Qgis::MessageLevel::Warning, true );
566 break;
567 }
568
569 l.linkIndex = i;
570 res.append( l );
571 }
572
573 break;
574 }
575
577 {
578 const QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = model->variablesForChildAlgorithm( childId, &context );
579 const QgsExpression exp( source.expression() );
580 const QSet<QString> vars = exp.referencedVariables();
581 for ( const QString &v : vars )
582 {
583 if ( variables.contains( v ) )
584 {
585 res.append( linkSourcesForParameterValue( model, QVariant::fromValue( variables.value( v ).source ), childId, context ) );
586 }
587 }
588 break;
589 }
590
594 break;
595 }
596 }
597 return res;
598}
599
600void QgsModelGraphicsScene::addCommentItemForComponent( QgsProcessingModelAlgorithm *model, const QgsProcessingModelComponent &component, QgsModelComponentGraphicItem *parentItem )
601{
602 if ( mFlags & FlagHideComments || !component.comment() || component.comment()->description().isEmpty() )
603 return;
604
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 );
611
612 auto arrow = std::make_unique<QgsModelArrowItem>( parentItem, QgsModelArrowItem::Circle, commentItem, QgsModelArrowItem::Circle );
613 arrow->setPenStyle( Qt::DotLine );
614 addItem( arrow.release() );
615}
616
617
618void QgsModelGraphicsScene::addFeatureCountItemForArrow( QgsModelArrowItem *arrow, const QString &layerId )
619{
620 if ( mFlags & FlagHideFeatureCount )
621 return;
622
623 if ( !mLastResultCount.contains( layerId ) )
624 {
625 return;
626 }
627
628 QString numberFeatureText = u"[%1]"_s.arg( mLastResultCount.value( layerId ) );
629 QgsModelDesignerFeatureCountGraphicItem *featureCount = new QgsModelDesignerFeatureCountGraphicItem( arrow, numberFeatureText );
630 addItem( featureCount );
631}
632
633
634QgsMessageBar *QgsModelGraphicsScene::messageBar() const
635{
636 return mMessageBar;
637}
638
639void QgsModelGraphicsScene::setMessageBar( QgsMessageBar *messageBar )
640{
641 mMessageBar = messageBar;
642}
643
644void QgsModelGraphicsScene::showWarning( const QString &shortMessage, const QString &title, const QString &longMessage, Qgis::MessageLevel level ) const
645{
646 QgsMessageBarItem *messageWidget = QgsMessageBar::createMessage( QString(), shortMessage );
647 QPushButton *detailsButton = new QPushButton( tr( "Details" ) );
648 connect( detailsButton, &QPushButton::clicked, detailsButton, [detailsButton, title, longMessage] {
649 QgsMessageViewer *dialog = new QgsMessageViewer( detailsButton );
650 dialog->setTitle( title );
651 dialog->setMessage( longMessage, Qgis::StringFormat::Html );
652 dialog->showMessage();
653 } );
654 messageWidget->layout()->addWidget( detailsButton );
655 mMessageBar->clearWidgets();
656 mMessageBar->pushWidget( messageWidget, level, 0 );
657}
658
659void QgsModelGraphicsScene::requestRebuildRequired()
660{
661 emit rebuildRequired();
662}
663
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:160
@ Warning
Warning message.
Definition qgis.h:162
@ Html
HTML message.
Definition qgis.h:177
@ ExpressionText
Parameter value is taken from a text with expressions, evaluated just before the algorithm runs.
Definition qgis.h:3969
@ ModelOutput
Parameter value is linked to an output parameter for the model.
Definition qgis.h:3970
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
Definition qgis.h:3966
@ ModelParameter
Parameter value is taken from a parent model parameter.
Definition qgis.h:3965
@ StaticValue
Parameter value is a static value.
Definition qgis.h:3967
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
Definition qgis.h:3968
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:3881
Handles parsing and evaluation of expressions (formerly called "search strings").
Base class for all map layer types.
Definition qgsmaplayer.h:83
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.
Definition qgis.h:6880
QList< const QgsProcessingOutputDefinition * > QgsProcessingOutputDefinitions
List of processing parameters.
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.