QGIS API Documentation 4.3.0-Master (550e9e0643d)
Loading...
Searching...
No Matches
qgsmodelcomponentgraphicitem.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmodelcomponentgraphicitem.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 "qgsapplication.h"
19#include "qgsmessagelog.h"
20#include "qgsmodelgraphicitem.h"
25#include "qgsmodelviewtool.h"
33
34#include <QApplication>
35#include <QGraphicsSceneHoverEvent>
36#include <QMenu>
37#include <QMessageBox>
38#include <QPainter>
39#include <QPalette>
40#include <QPicture>
41#include <QString>
42#include <QSvgRenderer>
43
44#include "moc_qgsmodelcomponentgraphicitem.cpp"
45
46using namespace Qt::StringLiterals;
47
49
50QgsModelComponentGraphicItem::QgsModelComponentGraphicItem( QgsProcessingModelComponent *component, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
51 : QGraphicsObject( parent )
52 , mComponent( component )
53 , mModel( model )
54{
55 setAcceptHoverEvents( true );
56 setFlag( QGraphicsItem::ItemIsSelectable, true );
57 setFlag( QGraphicsItem::ItemSendsGeometryChanges, true );
58 setZValue( QgsModelGraphicsScene::ZValues::ModelComponent );
59
60 mFont.setPixelSize( 12 );
61
62 QSvgRenderer svg( QgsApplication::iconPath( u"mActionEditModelComponent.svg"_s ) );
63 QPicture editPicture;
64 QPainter painter( &editPicture );
65 svg.render( &painter );
66 painter.end();
67 mEditButton = new QgsModelDesignerFlatButtonGraphicItem( this, editPicture, QPointF( 0, 0 ) );
68 connect( mEditButton, &QgsModelDesignerFlatButtonGraphicItem::clicked, this, &QgsModelComponentGraphicItem::editComponent );
69
70 QSvgRenderer svg2( QgsApplication::iconPath( u"mActionDeleteModelComponent.svg"_s ) );
71 QPicture deletePicture;
72 painter.begin( &deletePicture );
73 svg2.render( &painter );
74 painter.end();
75 mDeleteButton = new QgsModelDesignerFlatButtonGraphicItem( this, deletePicture, QPointF( 0, 0 ) );
76 connect( mDeleteButton, &QgsModelDesignerFlatButtonGraphicItem::clicked, this, &QgsModelComponentGraphicItem::deleteComponent );
77
78 updateButtonPositions();
79}
80
81QgsModelComponentGraphicItem::Flags QgsModelComponentGraphicItem::flags() const
82{
83 return QgsModelComponentGraphicItem::Flags();
84}
85
86QgsModelComponentGraphicItem::~QgsModelComponentGraphicItem() = default;
87
88QgsProcessingModelComponent *QgsModelComponentGraphicItem::component()
89{
90 return mComponent.get();
91}
92
93const QgsProcessingModelComponent *QgsModelComponentGraphicItem::component() const
94{
95 return mComponent.get();
96}
97
98QgsProcessingModelAlgorithm *QgsModelComponentGraphicItem::model()
99{
100 return mModel;
101}
102
103const QgsProcessingModelAlgorithm *QgsModelComponentGraphicItem::model() const
104{
105 return mModel;
106}
107
108QgsModelGraphicsView *QgsModelComponentGraphicItem::view()
109{
110 if ( scene()->views().isEmpty() )
111 return nullptr;
112
113 return qobject_cast<QgsModelGraphicsView *>( scene()->views().first() );
114}
115
116QFont QgsModelComponentGraphicItem::font() const
117{
118 return mFont;
119}
120
121void QgsModelComponentGraphicItem::setFont( const QFont &font )
122{
123 mFont = font;
124 update();
125}
126
127void QgsModelComponentGraphicItem::moveComponentBy( qreal dx, qreal dy )
128{
129 setPos( mComponent->position().x() + dx, mComponent->position().y() + dy );
130 mComponent->setPosition( pos() );
131
132 emit aboutToChange( tr( "Move %1" ).arg( mComponent->description() ) );
133 updateStoredComponentPosition( pos(), mComponent->size() );
134 emit changed();
135
136 emit sizePositionChanged();
137 emit updateArrowPaths();
138}
139
140void QgsModelComponentGraphicItem::previewItemMove( qreal dx, qreal dy )
141{
142 setPos( mComponent->position().x() + dx, mComponent->position().y() + dy );
143 emit updateArrowPaths();
144}
145
146void QgsModelComponentGraphicItem::setItemRect( QRectF rect )
147{
148 rect = rect.normalized();
149
150 if ( rect.width() < MIN_COMPONENT_WIDTH )
151 rect.setWidth( MIN_COMPONENT_WIDTH );
152 if ( rect.height() < MIN_COMPONENT_HEIGHT )
153 rect.setHeight( MIN_COMPONENT_HEIGHT );
154
155 setPos( rect.center() );
156 prepareGeometryChange();
157
158 emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );
159
160 mComponent->setPosition( pos() );
161 mComponent->setSize( rect.size() );
162 updateStoredComponentPosition( pos(), mComponent->size() );
163
164 updateButtonPositions();
165 emit changed();
166
167 emit updateArrowPaths();
168 emit sizePositionChanged();
169}
170
171QRectF QgsModelComponentGraphicItem::previewItemRectChange( QRectF rect )
172{
173 rect = rect.normalized();
174
175 if ( rect.width() < MIN_COMPONENT_WIDTH )
176 rect.setWidth( MIN_COMPONENT_WIDTH );
177 if ( rect.height() < MIN_COMPONENT_HEIGHT )
178 rect.setHeight( MIN_COMPONENT_HEIGHT );
179
180 setPos( rect.center() );
181 prepareGeometryChange();
182
183 mTempSize = rect.size();
184
185 updateButtonPositions();
186 emit updateArrowPaths();
187
188 return rect;
189}
190
191void QgsModelComponentGraphicItem::finalizePreviewedItemRectChange( QRectF )
192{
193 mComponent->setPosition( pos() );
194 prepareGeometryChange();
195 mComponent->setSize( mTempSize );
196 mTempSize = QSizeF();
197
198 emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );
199 updateStoredComponentPosition( pos(), mComponent->size() );
200
201 updateButtonPositions();
202
203 emit changed();
204
205 emit sizePositionChanged();
206 emit updateArrowPaths();
207}
208
209void QgsModelComponentGraphicItem::modelHoverEnterEvent( QgsModelViewMouseEvent *event )
210{
211 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
212 updateToolTip( mapFromScene( event->modelPoint() ) );
213}
214
215void QgsModelComponentGraphicItem::modelHoverMoveEvent( QgsModelViewMouseEvent *event )
216{
217 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
218 updateToolTip( mapFromScene( event->modelPoint() ) );
219}
220
221void QgsModelComponentGraphicItem::modelHoverLeaveEvent( QgsModelViewMouseEvent * )
222{
223 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
224 {
225 setToolTip( QString() );
226 if ( mIsHovering )
227 {
228 mIsHovering = false;
229 update();
230 emit repaintArrows();
231 }
232 }
233}
234
235void QgsModelComponentGraphicItem::modelDoubleClickEvent( QgsModelViewMouseEvent * )
236{
237 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
238 editComponent();
239}
240
241void QgsModelComponentGraphicItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent * )
242{
243 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
244 editComponent();
245}
246
247void QgsModelComponentGraphicItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
248{
249 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
250 updateToolTip( event->pos() );
251}
252
253void QgsModelComponentGraphicItem::hoverMoveEvent( QGraphicsSceneHoverEvent *event )
254{
255 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
256 updateToolTip( event->pos() );
257}
258
259void QgsModelComponentGraphicItem::hoverLeaveEvent( QGraphicsSceneHoverEvent * )
260{
261 modelHoverLeaveEvent( nullptr );
262}
263
264QVariant QgsModelComponentGraphicItem::itemChange( QGraphicsItem::GraphicsItemChange change, const QVariant &value )
265{
266 switch ( change )
267 {
268 case QGraphicsItem::ItemSelectedChange:
269 {
270 emit repaintArrows();
271 break;
272 }
273
274 case QGraphicsItem::ItemSceneChange:
275 {
276 if ( !mInitialized )
277 {
278 // ideally would be in constructor, but cannot call virtual methods from that...
279 if ( linkPointCount( Qt::TopEdge ) )
280 {
281 mExpandTopButton = new QgsModelDesignerFoldButtonGraphicItem( this, mComponent->linksCollapsed( Qt::TopEdge ), QPointF( 0, 0 ) );
282 connect( mExpandTopButton, &QgsModelDesignerFoldButtonGraphicItem::folded, this, [this]( bool folded ) { fold( Qt::TopEdge, folded ); } );
283
284 for ( int idx = 0; idx < linkPointCount( Qt::TopEdge ); ++idx )
285 {
286 mInSockets.append( new QgsModelDesignerSocketGraphicItem( this, mComponent.get(), idx, QPointF( 0, 0 ), Qt::TopEdge ) );
287 }
288 }
289 if ( linkPointCount( Qt::BottomEdge ) )
290 {
291 mExpandBottomButton = new QgsModelDesignerFoldButtonGraphicItem( this, mComponent->linksCollapsed( Qt::BottomEdge ), QPointF( 0, 0 ) );
292 connect( mExpandBottomButton, &QgsModelDesignerFoldButtonGraphicItem::folded, this, [this]( bool folded ) { fold( Qt::BottomEdge, folded ); } );
293
294 for ( int idx = 0; idx < linkPointCount( Qt::BottomEdge ); ++idx )
295 {
296 mOutSockets.append( new QgsModelDesignerSocketGraphicItem( this, mComponent.get(), idx, QPointF( 0, 0 ), Qt::BottomEdge ) );
297 }
298 }
299 mInitialized = true;
300 updateButtonPositions();
301 }
302 break;
303 }
304
305 default:
306 break;
307 }
308
309 return QGraphicsObject::itemChange( change, value );
310}
311
312QRectF QgsModelComponentGraphicItem::boundingRect() const
313{
314 const QFontMetricsF fm( mFont );
315 const int linksAbove = linkPointCount( Qt::TopEdge );
316 const int linksBelow = linkPointCount( Qt::BottomEdge );
317
318 const double hUp = linksAbove == 0 ? 0 : fm.height() * 1.2 * ( ( mComponent->linksCollapsed( Qt::TopEdge ) ? 0 : linksAbove ) + 2 );
319 const double hDown = linksBelow == 0 ? 0 : fm.height() * 1.2 * ( ( mComponent->linksCollapsed( Qt::BottomEdge ) ? 0 : linksBelow ) + 2 );
320
321 double outlineSize = 0;
322 if ( outlineColor().isValid() )
323 {
324 outlineSize = RECT_OUTLINE_SIZE + 0.5; // 0.5 for antialiasing
325 }
326
327 return QRectF(
328 -( itemSize().width() ) / 2 - RECT_PEN_SIZE - outlineSize,
329 -( itemSize().height() ) / 2 - hUp - RECT_PEN_SIZE - outlineSize,
330 itemSize().width() + 2 * RECT_PEN_SIZE + outlineSize * 2,
331 itemSize().height() + hDown + hUp + 2 * RECT_PEN_SIZE + outlineSize * 2
332 );
333}
334
335bool QgsModelComponentGraphicItem::contains( const QPointF &point ) const
336{
337 const QRectF paintingBounds = boundingRect();
338 if ( point.x() < paintingBounds.left() + RECT_PEN_SIZE )
339 return false;
340 if ( point.x() > paintingBounds.right() - RECT_PEN_SIZE )
341 return false;
342 if ( point.y() < paintingBounds.top() + RECT_PEN_SIZE )
343 return false;
344 if ( point.y() > paintingBounds.bottom() - RECT_PEN_SIZE )
345 return false;
346
347 return true;
348}
349
350void QgsModelComponentGraphicItem::paintBackground( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
351{
352 const QRectF rect = itemRect();
353 QColor color;
354 QColor stroke;
355 if ( mComponent->color().isValid() )
356 {
357 color = mComponent->color();
358 switch ( state() )
359 {
360 case Selected:
361 color = color.darker( 110 );
362 break;
363 case Hover:
364 color = color.darker( 105 );
365 break;
366
367 case Normal:
368 break;
369 }
370 stroke = color.darker( 110 );
371 }
372 else
373 {
374 color = fillColor( state() );
375 stroke = strokeColor( state() );
376 }
377
378 paintOutline( painter, option, widget );
379
380 QPen strokePen = QPen( stroke, 0 ); // 0 width "cosmetic" pen
381 strokePen.setStyle( strokeStyle( state() ) );
382 painter->setPen( strokePen );
383 painter->setBrush( QBrush( color, Qt::SolidPattern ) );
384 painter->drawRect( rect );
385}
386
387void QgsModelComponentGraphicItem::paintOutline( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * )
388{
389 const QColor outline = outlineColor();
390 if ( outline.isValid() )
391 {
392 // outline may be sub-pixel sized, which looks ugly without antialiasing.
393 const bool wasAntiAliased = painter->testRenderHint( QPainter::RenderHint::Antialiasing );
394 painter->setRenderHint( QPainter::RenderHint::Antialiasing );
395 QPen strokePen = QPen( outline, RECT_OUTLINE_SIZE );
396 strokePen.setJoinStyle( Qt::MiterJoin );
397 strokePen.setStyle( strokeStyle( state() ) );
398 painter->setPen( strokePen );
399 painter->setBrush( Qt::NoBrush );
400 const QRectF rect = itemRect();
401 painter->drawRect( rect );
402 painter->setRenderHint( QPainter::RenderHint::Antialiasing, wasAntiAliased );
403 }
404}
405
406void QgsModelComponentGraphicItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
407{
408 paintBackground( painter, option, widget );
409
410 const QRectF rect = itemRect();
411 QColor foreColor;
412 if ( mComponent->color().isValid() )
413 {
414 QColor color = mComponent->color();
415 switch ( state() )
416 {
417 case Selected:
418 color = color.darker( 110 );
419 break;
420 case Hover:
421 color = color.darker( 105 );
422 break;
423
424 case Normal:
425 break;
426 }
427 foreColor = color.lightness() > 150 ? QColor( 0, 0, 0 ) : QColor( 255, 255, 255 );
428 }
429 else
430 {
431 foreColor = textColor( state() );
432 }
433 painter->setFont( font() );
434 painter->setPen( QPen( foreColor ) );
435
436 QString text;
437
438 const QSizeF componentSize = itemSize();
439
440 const QFontMetricsF fm( font() );
441 double h = fm.ascent();
442 QPointF pt( -componentSize.width() / 2 + 25, componentSize.height() / 2.0 - h + 1 );
443
444 if ( iconPicture().isNull() && iconPixmap().isNull() )
445 {
446 const QRectF labelRect = QRectF( rect.left() + TEXT_MARGIN, rect.top() + TEXT_MARGIN, rect.width() - 2 * TEXT_MARGIN - mButtonSize.width() - BUTTON_MARGIN, rect.height() - 2 * TEXT_MARGIN );
447 text = label();
448 painter->drawText( labelRect, Qt::TextWordWrap | titleAlignment(), text );
449 }
450 else
451 {
452 const QRectF labelRect = QRectF( rect.left() + 21 + TEXT_MARGIN, rect.top() + TEXT_MARGIN, rect.width() - 2 * TEXT_MARGIN - mButtonSize.width() - BUTTON_MARGIN - 21, rect.height() - 2 * TEXT_MARGIN );
453 text = label();
454 painter->drawText( labelRect, Qt::TextWordWrap | Qt::AlignVCenter, text );
455 }
456
457 painter->setPen( QPen( QApplication::palette().color( QPalette::Text ) ) );
458
459 if ( linkPointCount( Qt::TopEdge ) )
460 {
461 h = -( fm.height() * 1.2 );
462 h = h - componentSize.height() / 2.0 + 5;
463 pt = QPointF( -componentSize.width() / 2 + 25, h );
464 painter->drawText( pt, QObject::tr( "In" ) );
465 int i = 1;
466 if ( !mComponent->linksCollapsed( Qt::TopEdge ) )
467 {
468 for ( int idx = 0; idx < linkPointCount( Qt::TopEdge ); ++idx )
469 {
470 text = linkPointText( Qt::TopEdge, idx );
471 h = -( fm.height() * 1.2 ) * ( i + 1 );
472 h = h - componentSize.height() / 2.0 + 5;
473 pt = QPointF( -componentSize.width() / 2 + 33, h );
474 painter->drawText( pt, text );
475 i += 1;
476 }
477 }
478 }
479 if ( linkPointCount( Qt::BottomEdge ) )
480 {
481 h = fm.height() * 1.1;
482 h = h + componentSize.height() / 2.0;
483 pt = QPointF( -componentSize.width() / 2 + 25, h );
484 painter->drawText( pt, QObject::tr( "Out" ) );
485 if ( !mComponent->linksCollapsed( Qt::BottomEdge ) )
486 {
487 for ( int idx = 0; idx < linkPointCount( Qt::BottomEdge ); ++idx )
488 {
489 text = linkPointText( Qt::BottomEdge, idx );
490 h = fm.height() * 1.2 * ( idx + 2 );
491 h = h + componentSize.height() / 2.0;
492 pt = QPointF( -componentSize.width() / 2 + 33, h );
493 painter->drawText( pt, text );
494 }
495 }
496 }
497
498 const QPixmap px = iconPixmap();
499 if ( !px.isNull() )
500 {
501 painter->drawPixmap( QPointF( -( componentSize.width() / 2.0 ) + 3, -8 ), px );
502 }
503 else
504 {
505 const QPicture pic = iconPicture();
506 if ( !pic.isNull() )
507 {
508 painter->drawPicture( QPointF( -( componentSize.width() / 2.0 ) + 3, -8 ), pic );
509 }
510 }
511}
512
513QRectF QgsModelComponentGraphicItem::itemRect( bool storedRect ) const
514{
515 if ( storedRect )
516 {
517 return QRectF( mComponent->position().x() - ( mComponent->size().width() ) / 2.0, mComponent->position().y() - ( mComponent->size().height() ) / 2.0, mComponent->size().width(), mComponent->size().height() );
518 }
519 else
520 return QRectF( -( itemSize().width() ) / 2.0, -( itemSize().height() ) / 2.0, itemSize().width(), itemSize().height() );
521}
522
523QString QgsModelComponentGraphicItem::truncatedTextForItem( const QString &text ) const
524{
525 const QFontMetricsF fm( mFont );
526 double width = fm.boundingRect( text ).width();
527 if ( width < itemSize().width() - 25 - mButtonSize.width() )
528 return text;
529
530 QString t = text;
531 t = t.left( t.length() - 3 ) + QChar( 0x2026 );
532 width = fm.boundingRect( t ).width();
533 while ( width > itemSize().width() - 25 - mButtonSize.width() )
534 {
535 if ( t.length() < 5 )
536 break;
537
538 t = t.left( t.length() - 4 ) + QChar( 0x2026 );
539 width = fm.boundingRect( t ).width();
540 }
541 return t;
542}
543
544Qt::PenStyle QgsModelComponentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
545{
546 return Qt::SolidLine;
547}
548
549Qt::Alignment QgsModelComponentGraphicItem::titleAlignment() const
550{
551 return Qt::AlignLeft;
552}
553
554QPicture QgsModelComponentGraphicItem::iconPicture() const
555{
556 return QPicture();
557}
558
559QPixmap QgsModelComponentGraphicItem::iconPixmap() const
560{
561 return QPixmap();
562}
563
564
565void QgsModelComponentGraphicItem::updateButtonPositions()
566{
567 mEditButton->setPosition( QPointF( itemSize().width() / 2.0 - mButtonSize.width() / 2.0 - BUTTON_MARGIN, itemSize().height() / 2.0 - mButtonSize.height() / 2.0 - BUTTON_MARGIN ) );
568 mDeleteButton->setPosition( QPointF( itemSize().width() / 2.0 - mButtonSize.width() / 2.0 - BUTTON_MARGIN, mButtonSize.height() / 2.0 - itemSize().height() / 2.0 + BUTTON_MARGIN ) );
569
570 if ( mExpandBottomButton )
571 {
572 const QPointF pt = linkPoint( Qt::BottomEdge, -1, false );
573 mExpandBottomButton->setPosition( QPointF( 0, pt.y() ) );
574
575 bool collapsed = mComponent->linksCollapsed( Qt::BottomEdge );
576 for ( QgsModelDesignerSocketGraphicItem *socket : std::as_const( mOutSockets ) )
577 {
578 const QPointF pt = linkPoint( Qt::BottomEdge, socket->index(), false );
579 socket->setPosition( pt );
580 socket->setVisible( !collapsed );
581 }
582 }
583
584
585 if ( mExpandTopButton )
586 {
587 const QPointF pt = linkPoint( Qt::TopEdge, -1, true );
588 mExpandTopButton->setPosition( QPointF( 0, pt.y() ) );
589
590 bool collapsed = mComponent->linksCollapsed( Qt::TopEdge );
591 for ( QgsModelDesignerSocketGraphicItem *socket : std::as_const( mInSockets ) )
592 {
593 const QPointF pt = linkPoint( Qt::TopEdge, socket->index(), true );
594 socket->setPosition( pt );
595 socket->setVisible( !collapsed );
596 }
597 }
598}
599
600
601QSizeF QgsModelComponentGraphicItem::itemSize() const
602{
603 return !mTempSize.isValid() ? mComponent->size() : mTempSize;
604}
605
606void QgsModelComponentGraphicItem::updateToolTip( const QPointF &pos )
607{
608 const bool prevHoverStatus = mIsHovering;
609 if ( itemRect().contains( pos ) )
610 {
611 setToolTip( mLabel );
612 mIsHovering = true;
613 }
614 else
615 {
616 setToolTip( QString() );
617 mIsHovering = false;
618 }
619 if ( mIsHovering != prevHoverStatus )
620 {
621 update();
622 emit repaintArrows();
623 }
624}
625
626void QgsModelComponentGraphicItem::fold( Qt::Edge edge, bool folded )
627{
628 emit aboutToChange( !folded ? tr( "Expand Item" ) : tr( "Collapse Item" ) );
629 mComponent->setLinksCollapsed( edge, folded );
630 // also need to update the model's stored component
631
632 // TODO - this is not so nice, consider moving this to model class
633 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast<QgsProcessingModelChildAlgorithm *>( mComponent.get() ) )
634 {
635 mModel->childAlgorithm( child->childId() ).setLinksCollapsed( edge, folded );
636 }
637 else if ( QgsProcessingModelParameter *param = dynamic_cast<QgsProcessingModelParameter *>( mComponent.get() ) )
638 {
639 mModel->parameterComponent( param->parameterName() ).setLinksCollapsed( edge, folded );
640 }
641 else if ( QgsProcessingModelOutput *output = dynamic_cast<QgsProcessingModelOutput *>( mComponent.get() ) )
642 {
643 mModel->childAlgorithm( output->childId() ).modelOutput( output->name() ).setLinksCollapsed( edge, folded );
644 }
645
646 updateButtonPositions();
647 prepareGeometryChange();
648 emit updateArrowPaths();
649 emit changed();
650 update();
651}
652
653QString QgsModelComponentGraphicItem::label() const
654{
655 return mLabel;
656}
657
658void QgsModelComponentGraphicItem::setLabel( const QString &label )
659{
660 mLabel = label;
661 update();
662}
663
664QgsModelComponentGraphicItem::State QgsModelComponentGraphicItem::state() const
665{
666 if ( isSelected() )
667 return Selected;
668 else if ( mIsHovering )
669 return Hover;
670 else
671 return Normal;
672}
673
674int QgsModelComponentGraphicItem::linkPointCount( Qt::Edge ) const
675{
676 return 0;
677}
678
679QString QgsModelComponentGraphicItem::linkPointText( Qt::Edge, int ) const
680{
681 return QString();
682}
683
684QPointF QgsModelComponentGraphicItem::linkPoint( Qt::Edge edge, int index, bool incoming ) const
685{
686 switch ( edge )
687 {
688 case Qt::BottomEdge:
689 {
690 if ( linkPointCount( Qt::BottomEdge ) )
691 {
692 double offsetX = 25;
693 if ( mComponent->linksCollapsed( Qt::BottomEdge ) )
694 {
695 offsetX = 17;
696 }
697 const int pointIndex = !mComponent->linksCollapsed( Qt::BottomEdge ) ? index : -1;
698 const QString text = truncatedTextForItem( linkPointText( Qt::BottomEdge, index ) );
699 const QFontMetricsF fm( mFont );
700 const double w = fm.boundingRect( text ).width();
701 const double h = fm.height() * 1.2 * ( pointIndex + 1 ) + fm.height() / 2.0;
702 const double y = h + itemSize().height() / 2.0 + 6.4;
703 const double x = !mComponent->linksCollapsed( Qt::BottomEdge ) ? ( -itemSize().width() / 2 + 33 + w + 10 ) : 10.4;
704 return QPointF( incoming ? -itemSize().width() / 2 + offsetX : x, y );
705 }
706 break;
707 }
708
709 case Qt::TopEdge:
710 {
711 if ( linkPointCount( Qt::TopEdge ) )
712 {
713 double offsetX = 25;
714 int paramIndex = index;
715 if ( mComponent->linksCollapsed( Qt::TopEdge ) )
716 {
717 paramIndex = -1;
718 offsetX = 17;
719 }
720 const QFontMetricsF fm( mFont );
721 const QString text = truncatedTextForItem( linkPointText( Qt::TopEdge, index ) );
722 const double w = fm.boundingRect( text ).width();
723 double h = -( fm.height() * 1.2 ) * ( paramIndex + 2 ) - fm.height() / 2.0 + 8;
724 h = h - itemSize().height() / 2.0;
725 return QPointF( incoming ? -itemSize().width() / 2 + offsetX : ( !mComponent->linksCollapsed( Qt::TopEdge ) ? ( -itemSize().width() / 2 + 33 + w + 5 ) : 10 ), h );
726 }
727 break;
728 }
729 case Qt::LeftEdge:
730 case Qt::RightEdge:
731 break;
732 }
733
734 return QPointF();
735}
736
737QPointF QgsModelComponentGraphicItem::calculateAutomaticLinkPoint( QgsModelComponentGraphicItem *other, Qt::Edge &edge ) const
738{
739 // find closest edge to other item
740 const QgsRectangle otherRect( other->itemRect().translated( other->pos() ) );
741
742 const QPointF leftPoint = pos() + QPointF( -itemSize().width() / 2.0, 0 );
743 const double distLeft = otherRect.distance( QgsPointXY( leftPoint ) );
744
745 const QPointF rightPoint = pos() + QPointF( itemSize().width() / 2.0, 0 );
746 const double distRight = otherRect.distance( QgsPointXY( rightPoint ) );
747
748 const QPointF topPoint = pos() + QPointF( 0, -itemSize().height() / 2.0 );
749 const double distTop = otherRect.distance( QgsPointXY( topPoint ) );
750
751 const QPointF bottomPoint = pos() + QPointF( 0, itemSize().height() / 2.0 );
752 const double distBottom = otherRect.distance( QgsPointXY( bottomPoint ) );
753
754 if ( distLeft <= distRight && distLeft <= distTop && distLeft <= distBottom )
755 {
756 edge = Qt::LeftEdge;
757 return leftPoint;
758 }
759 else if ( distRight <= distTop && distRight <= distBottom )
760 {
761 edge = Qt::RightEdge;
762 return rightPoint;
763 }
764 else if ( distBottom <= distTop )
765 {
766 edge = Qt::BottomEdge;
767 return bottomPoint;
768 }
769 else
770 {
771 edge = Qt::TopEdge;
772 return topPoint;
773 }
774}
775
776QPointF QgsModelComponentGraphicItem::calculateAutomaticLinkPoint( const QPointF &point, Qt::Edge &edge ) const
777{
778 // find closest edge to other point
779 const QgsPointXY otherPt( point );
780 const QPointF leftPoint = pos() + QPointF( -itemSize().width() / 2.0, 0 );
781 const double distLeft = otherPt.distance( QgsPointXY( leftPoint ) );
782
783 const QPointF rightPoint = pos() + QPointF( itemSize().width() / 2.0, 0 );
784 const double distRight = otherPt.distance( QgsPointXY( rightPoint ) );
785
786 const QPointF topPoint = pos() + QPointF( 0, -itemSize().height() / 2.0 );
787 const double distTop = otherPt.distance( QgsPointXY( topPoint ) );
788
789 const QPointF bottomPoint = pos() + QPointF( 0, itemSize().height() / 2.0 );
790 const double distBottom = otherPt.distance( QgsPointXY( bottomPoint ) );
791
792 if ( distLeft <= distRight && distLeft <= distTop && distLeft <= distBottom )
793 {
794 edge = Qt::LeftEdge;
795 return leftPoint;
796 }
797 else if ( distRight <= distTop && distRight <= distBottom )
798 {
799 edge = Qt::RightEdge;
800 return rightPoint;
801 }
802 else if ( distBottom <= distTop )
803 {
804 edge = Qt::BottomEdge;
805 return bottomPoint;
806 }
807 else
808 {
809 edge = Qt::TopEdge;
810 return topPoint;
811 }
812}
813
814QgsModelDesignerSocketGraphicItem *QgsModelComponentGraphicItem::outSocketAt( int index ) const
815{
816 if ( index < 0 || index >= mOutSockets.size() )
817 {
818 return nullptr;
819 }
820 return mOutSockets.at( index );
821}
822
823QList<QgsModelArrowItem *> QgsModelComponentGraphicItem::incomingArrows()
824{
825 const QList<QGraphicsItem *> allItems = scene()->items();
826 QList<QgsModelArrowItem *> arrows;
827 for ( QGraphicsItem *item : allItems )
828 {
829 if ( auto arrowItem = dynamic_cast< QgsModelArrowItem * >( item ) )
830 {
831 if ( arrowItem->endItem() == this )
832 {
833 arrows << arrowItem;
834 }
835 }
836 }
837 return arrows;
838}
839
840QList<QgsModelArrowItem *> QgsModelComponentGraphicItem::outgoingArrows()
841{
842 const QList<QGraphicsItem *> allItems = scene()->items();
843 QList<QgsModelArrowItem *> arrows;
844 for ( QGraphicsItem *item : allItems )
845 {
846 if ( auto arrowItem = dynamic_cast< QgsModelArrowItem * >( item ) )
847 {
848 if ( arrowItem->startItem() == this )
849 {
850 arrows << arrowItem;
851 }
852 }
853 }
854 return arrows;
855}
856
857void QgsModelComponentGraphicItem::registerWidgetContextGenerator( QgsProcessingWidgetContextGenerator *generator )
858{
859 mWidgetContextGenerator = generator;
860}
861
862QgsProcessingParameterWidgetContext QgsModelComponentGraphicItem::createWidgetContext()
863{
864 if ( mWidgetContextGenerator )
865 {
866 return mWidgetContextGenerator->createWidgetContext();
867 }
869}
870
871QgsModelParameterGraphicItem::QgsModelParameterGraphicItem( QgsProcessingModelParameter *parameter, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
872 : QgsModelComponentGraphicItem( parameter, model, parent )
873{
874 QSvgRenderer svg( QgsApplication::iconPath( u"mIconModelInput.svg"_s ) );
875 QPainter painter( &mPicture );
876 svg.render( &painter );
877 painter.end();
878
879 if ( const QgsProcessingParameterDefinition *parameterDefinition = model->parameterDefinition( parameter->parameterName() ) )
880 setLabel( parameterDefinition->description() );
881 else
882 setLabel( QObject::tr( "Error (%1)" ).arg( parameter->parameterName() ) );
883}
884
885void QgsModelParameterGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
886{
887 QMenu *popupmenu = new QMenu( event->widget() );
888 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
889 connect( removeAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::deleteComponent );
890 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
891 connect( editAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComponent );
892 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
893 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
894
895 popupmenu->exec( event->screenPos() );
896}
897
898QColor QgsModelParameterGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
899{
900 QColor c( 238, 242, 131 );
901 switch ( state )
902 {
903 case Selected:
904 c = c.darker( 110 );
905 break;
906 case Hover:
907 c = c.darker( 105 );
908 break;
909
910 case Normal:
911 break;
912 }
913 return c;
914}
915
916QColor QgsModelParameterGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
917{
918 switch ( state )
919 {
920 case Selected:
921 return QColor( 116, 113, 68 );
922 case Hover:
923 case Normal:
924 return QColor( 234, 226, 118 );
925 }
926 return QColor();
927}
928
929QColor QgsModelParameterGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
930{
931 return Qt::black;
932}
933
934QPicture QgsModelParameterGraphicItem::iconPicture() const
935{
936 return mPicture;
937}
938
939int QgsModelParameterGraphicItem::linkPointCount( Qt::Edge edge ) const
940{
941 switch ( edge )
942 {
943 case Qt::BottomEdge:
944 return 1;
945 case Qt::TopEdge:
946 case Qt::LeftEdge:
947 case Qt::RightEdge:
948 break;
949 }
950
951 return 0;
952}
953
954QString QgsModelParameterGraphicItem::linkPointText( Qt::Edge, int index ) const
955{
956 if ( index < 0 )
957 {
958 return QString();
959 }
960
961 if ( const QgsProcessingModelParameter *parameter = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
962 {
963 QString text = this->model()->parameterDefinition( parameter->parameterName() )->type();
964
965 // Getting the default value to append to the box name
966 if ( const QgsProcessingParameterDefinition *paramDef = this->model()->parameterDefinition( parameter->parameterName() ) )
967 {
968 const QVariant paramValue = paramDef->defaultValue();
969
970 if ( paramValue.isValid() )
971 {
972 text += ": " + paramDef->userFriendlyString( paramValue );
973 }
974 }
975 return truncatedTextForItem( text );
976 }
977
978 return QString();
979}
980
981QColor QgsModelParameterGraphicItem::linkColor( Qt::Edge /* unused in this implementation because parameters only have a bottom edge */, int index ) const
982{
983 if ( index < 0 )
984 {
985 return FALLBACK_COLOR;
986 }
987
988 if ( const QgsProcessingModelParameter *parameter = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
989 {
990 if ( const QgsProcessingParameterDefinition *parameterDefinition = model()->parameterDefinition( parameter->parameterName() ) )
991 {
992 return parameterDefinition->modelColor();
993 }
994 }
995
996 return FALLBACK_COLOR;
997}
998
999void QgsModelParameterGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1000{
1001 if ( QgsProcessingModelParameter *param = dynamic_cast<QgsProcessingModelParameter *>( component() ) )
1002 {
1003 model()->parameterComponent( param->parameterName() ).setPosition( pos );
1004 model()->parameterComponent( param->parameterName() ).setSize( size );
1005 }
1006}
1007
1008bool QgsModelParameterGraphicItem::canDeleteComponent()
1009{
1010 if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( component() ) )
1011 {
1012 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
1013 {
1014 return false;
1015 }
1016 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
1017 {
1018 return false;
1019 }
1020 else
1021 {
1022 return true;
1023 }
1024 }
1025 return false;
1026}
1027
1028void QgsModelParameterGraphicItem::deleteComponent()
1029{
1030 if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( component() ) )
1031 {
1032 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
1033 {
1034 QMessageBox::warning(
1035 nullptr,
1036 QObject::tr( "Could not remove input" ),
1037 QObject::tr(
1038 "Algorithms depend on the selected input.\n"
1039 "Remove them before trying to remove it."
1040 )
1041 );
1042 }
1043 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
1044 {
1045 QMessageBox::warning(
1046 nullptr,
1047 QObject::tr( "Could not remove input" ),
1048 QObject::tr(
1049 "Other inputs depend on the selected input.\n"
1050 "Remove them before trying to remove it."
1051 )
1052 );
1053 }
1054 else
1055 {
1056 emit aboutToChange( tr( "Delete Input %1" ).arg( param->description() ) );
1057 model()->removeModelParameter( param->parameterName() );
1058 emit changed();
1059 emit requestModelRepaint();
1060 }
1061 }
1062}
1063
1064
1065QgsModelChildAlgorithmGraphicItem::QgsModelChildAlgorithmGraphicItem( QgsProcessingModelChildAlgorithm *child, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1066 : QgsModelComponentGraphicItem( child, model, parent )
1067{
1068 if ( child->algorithm() && !child->algorithm()->svgIconPath().isEmpty() )
1069 {
1070 QSvgRenderer svg( child->algorithm()->svgIconPath() );
1071 const QSizeF size = svg.defaultSize();
1072 QPainter painter( &mPicture );
1073 painter.scale( 16.0 / size.width(), 16.0 / size.width() );
1074 svg.render( &painter );
1075 painter.end();
1076 }
1077 else if ( child->algorithm() )
1078 {
1079 mPixmap = child->algorithm()->icon().pixmap( 15, 15 );
1080 }
1081
1082 setLabel( child->description() );
1083
1084 QStringList issues;
1085 mIsValid = model->validateChildAlgorithm( child->childId(), issues );
1086}
1087
1088void QgsModelChildAlgorithmGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1089{
1090 QMenu *popupmenu = new QMenu( event->widget() );
1091
1092 if ( isSelected() )
1093 {
1094 QAction *runSelectedStepsAction = popupmenu->addAction( QObject::tr( "Run Selected Steps…" ) );
1095 runSelectedStepsAction->setIcon( QgsApplication::getThemeIcon( u"mActionRunSelected.svg"_s ) );
1096 connect( runSelectedStepsAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runSelected );
1097 }
1098
1099 QAction *runFromHereAction = popupmenu->addAction( QObject::tr( "Run from Here…" ) );
1100 runFromHereAction->setIcon( QgsApplication::getThemeIcon( u"mActionStart.svg"_s ) );
1101 connect( runFromHereAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runFromHere );
1102
1103 popupmenu->addSeparator();
1104
1105 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1106 connect( removeAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deleteComponent );
1107 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1108 connect( editAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::editComponent );
1109 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
1110 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
1111 popupmenu->addSeparator();
1112
1113 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1114 {
1115 if ( !child->isActive() )
1116 {
1117 QAction *activateAction = popupmenu->addAction( QObject::tr( "Activate" ) );
1118 connect( activateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::activateAlgorithm );
1119 }
1120 else
1121 {
1122 QAction *deactivateAction = popupmenu->addAction( QObject::tr( "Deactivate" ) );
1123 connect( deactivateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm );
1124 }
1125
1126 // only show the "View Output Layers" action for algorithms which create layers
1127 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1128 {
1129 const QList<const QgsProcessingParameterDefinition *> outputParams = algorithm->destinationParameterDefinitions();
1130 if ( !outputParams.isEmpty() )
1131 {
1132 popupmenu->addSeparator();
1133 QAction *viewOutputLayersAction = popupmenu->addAction( QObject::tr( "View Output Layers" ) );
1134 viewOutputLayersAction->setIcon( QgsApplication::getThemeIcon( u"mActionShowSelectedLayers.svg"_s ) );
1135 connect( viewOutputLayersAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showPreviousResults );
1136 // enable this action only when the child succeeded
1137 switch ( mResults.executionStatus() )
1138 {
1141 viewOutputLayersAction->setEnabled( false );
1142 break;
1143
1145 break;
1146 }
1147 }
1148 }
1149
1150 QAction *viewLogAction = popupmenu->addAction( QObject::tr( "View Log…" ) );
1151 connect( viewLogAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showLog );
1152 // enable this action even when the child failed
1153 switch ( mResults.executionStatus() )
1154 {
1156 viewLogAction->setEnabled( false );
1157 break;
1158
1161 break;
1162 }
1163 }
1164
1165 popupmenu->exec( event->screenPos() );
1166}
1167
1168QColor QgsModelChildAlgorithmGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1169{
1170 QColor c;
1171
1172 if ( mIsValid )
1173 c = QColor( 255, 255, 255 );
1174 else
1175 c = QColor( 208, 0, 0 );
1176
1177 switch ( state )
1178 {
1179 case Selected:
1180 c = c.darker( 110 );
1181 break;
1182 case Hover:
1183 c = c.darker( 105 );
1184 break;
1185
1186 case Normal:
1187 break;
1188 }
1189 return c;
1190}
1191
1192QColor QgsModelChildAlgorithmGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1193{
1194 switch ( state )
1195 {
1196 case Selected:
1197 return mIsValid ? QColor( 50, 50, 50 ) : QColor( 80, 0, 0 );
1198 case Hover:
1199 case Normal:
1200 return mIsValid ? Qt::gray : QColor( 134, 0, 0 );
1201 }
1202 return QColor();
1203}
1204
1205QColor QgsModelChildAlgorithmGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1206{
1207 return mIsValid ? ( qgis::down_cast<const QgsProcessingModelChildAlgorithm *>( component() )->isActive() ? Qt::black : Qt::gray ) : QColor( 255, 255, 255 );
1208}
1209
1210QColor QgsModelChildAlgorithmGraphicItem::outlineColor() const
1211{
1212 if ( mOutdated )
1213 {
1214 return QColor( 150, 150, 0 );
1215 }
1216
1217 switch ( mResults.executionStatus() )
1218 {
1220 if ( mStarted )
1221 {
1222 return QColor( 150, 150, 150 );
1223 }
1224 return QColor();
1226 return QColor( 55, 160, 55 );
1228 return QColor( 208, 0, 0 );
1229 }
1231}
1232
1233QPixmap QgsModelChildAlgorithmGraphicItem::iconPixmap() const
1234{
1235 return mPixmap;
1236}
1237
1238QPicture QgsModelChildAlgorithmGraphicItem::iconPicture() const
1239{
1240 return mPicture;
1241}
1242
1243int QgsModelChildAlgorithmGraphicItem::linkPointCount( Qt::Edge edge ) const
1244{
1245 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1246 {
1247 if ( !child->algorithm() )
1248 return 0;
1249
1250 switch ( edge )
1251 {
1252 case Qt::BottomEdge:
1253 return child->algorithm()->outputDefinitions().size();
1254 case Qt::TopEdge:
1255 {
1256 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1257 params.erase(
1258 std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition *param ) { return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination(); } ),
1259 params.end()
1260 );
1261 return params.size();
1262 }
1263
1264 case Qt::LeftEdge:
1265 case Qt::RightEdge:
1266 break;
1267 }
1268 }
1269 return 0;
1270}
1271
1272QColor QgsModelComponentGraphicItem::linkColor( Qt::Edge edge, int index ) const
1273{
1274 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1275 {
1276 if ( !child->algorithm() )
1277 {
1278 return FALLBACK_COLOR;
1279 }
1280
1281 switch ( edge )
1282 {
1283 case Qt::BottomEdge:
1284 {
1285 if ( index <= child->algorithm()->outputDefinitions().size() - 1 )
1286 {
1287 return child->algorithm()->outputDefinitions().at( index )->modelColor();
1288 }
1289 return FALLBACK_COLOR;
1290 }
1291 case Qt::TopEdge:
1292 {
1293 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1294
1295 if ( index <= params.size() - 1 )
1296 {
1297 return params.at( index )->modelColor();
1298 }
1299
1300 return FALLBACK_COLOR;
1301 }
1302
1303 case Qt::LeftEdge:
1304 case Qt::RightEdge:
1305 break;
1306 }
1307 }
1308
1309 return FALLBACK_COLOR;
1310}
1311
1312QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int index ) const
1313{
1314 if ( index < 0 )
1315 return QString();
1316
1317 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1318 {
1319 if ( !child->algorithm() )
1320 return QString();
1321
1322 switch ( edge )
1323 {
1324 case Qt::BottomEdge:
1325 {
1326 if ( index >= child->algorithm()->outputDefinitions().length() )
1327 {
1328 // something goes wrong and tried to link to an not existing output
1329 QgsMessageLog::logMessage( tr( "Cannot link output for child: %1" ).arg( child->algorithm()->name() ), "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1330 return QString();
1331 }
1332
1333 const QgsProcessingOutputDefinition *output = child->algorithm()->outputDefinitions().at( index );
1334 QString title = output->description();
1335 return truncatedTextForItem( title );
1336 }
1337
1338 case Qt::TopEdge:
1339 {
1340 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1341 params.erase(
1342 std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition *param ) { return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination(); } ),
1343 params.end()
1344 );
1345
1346 if ( index >= params.length() )
1347 {
1348 // something goes wrong and tried to link to an not existing source parameter
1349 QgsMessageLog::logMessage( tr( "Cannot link source for child: %1" ).arg( child->algorithm()->name() ), "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1350 return QString();
1351 }
1352
1353 const QgsProcessingParameterDefinition *param = params.at( index );
1354 QString name = param->name();
1355 QString title = param->description();
1356 QgsProcessingModelChildParameterSources paramSources = child->parameterSources().value( name );
1357 QString parameterValueAsString;
1358
1359 if ( !paramSources.empty() )
1360 {
1361 QgsProcessingModelChildParameterSource firstParameterSource = paramSources[0];
1362
1363 switch ( firstParameterSource.source() )
1364 {
1366 parameterValueAsString = u": %1"_s.arg( firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) ) );
1367 break;
1368
1370 parameterValueAsString = u": %1"_s.arg( firstParameterSource.expression() );
1371 break;
1372
1375 parameterValueAsString = u": %1"_s.arg( firstParameterSource.expressionText() );
1377 break;
1378
1380 parameterValueAsString = u": <%1>"_s.arg( firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) ) );
1381 break;
1382
1384 {
1385 const QString friendlyName = firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) );
1386 parameterValueAsString = friendlyName.isEmpty() ? u":"_s : u": <%1>"_s.arg( friendlyName );
1387 break;
1388 }
1389
1391 const QVariant paramValue = paramSources[0].staticValue();
1392 parameterValueAsString = u": %1"_s.arg( param->userFriendlyString( paramValue ) );
1393 }
1394 title += parameterValueAsString;
1395 }
1396
1397 return truncatedTextForItem( title );
1398 }
1399
1400 case Qt::LeftEdge:
1401 case Qt::RightEdge:
1402 break;
1403 }
1404 }
1405 return QString();
1406}
1407
1408void QgsModelChildAlgorithmGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1409{
1410 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast<QgsProcessingModelChildAlgorithm *>( component() ) )
1411 {
1412 model()->childAlgorithm( child->childId() ).setPosition( pos );
1413 model()->childAlgorithm( child->childId() ).setSize( size );
1414 }
1415}
1416
1417bool QgsModelChildAlgorithmGraphicItem::canDeleteComponent()
1418{
1419 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1420 {
1421 return model()->dependentChildAlgorithms( child->childId() ).empty();
1422 }
1423 return false;
1424}
1425
1426void QgsModelChildAlgorithmGraphicItem::setResults( const QgsProcessingModelChildAlgorithmResult &results )
1427{
1428 if ( mResults == results )
1429 return;
1430
1431 mOutdated = false;
1432 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1434 {
1435 for ( QgsModelArrowItem *arrow : arrows )
1436 {
1437 arrow->setShowBadge( false );
1438 }
1439 }
1440 else
1441 {
1442 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1443 {
1444 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1445 {
1446 const QVariantMap outputs = results.outputs();
1447 for ( auto it = outputs.constBegin(); it != outputs.constEnd(); ++it )
1448 {
1449 // don't show badges for output layers, these will just be the internal layer identifiers and we have logic elsewhere
1450 // to show actually useful information in the badges (feature counts)
1451 if ( const QgsProcessingOutputDefinition *outputDefinition = algorithm->outputDefinition( it.key() ); outputDefinition && outputDefinition->isMapLayer() )
1452 continue;
1453
1454 const int index = indexForOutput( it.key() );
1455 if ( index >= 0 )
1456 {
1457 for ( QgsModelArrowItem *arrow : arrows )
1458 {
1459 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1460 {
1461 arrow->setShowBadge( true );
1462 arrow->badgeItem()->setValue( it.value() );
1463 }
1464 }
1465 }
1466 }
1467 }
1468 }
1469 }
1470
1471 mResults = results;
1472 mStarted = false;
1473 update();
1474 emit updateArrowPaths();
1475}
1476
1477void QgsModelChildAlgorithmGraphicItem::setSourceFeatureCount( const QString &parameterName, long long featureCount )
1478{
1479 const int index = indexForInput( parameterName );
1480 if ( index < 0 )
1481 return;
1482
1483 const QList< QgsModelArrowItem * > arrows = incomingArrows();
1484 for ( QgsModelArrowItem *arrow : arrows )
1485 {
1486 if ( arrow->endIndex() == index && arrow->endEdge() == Qt::TopEdge )
1487 {
1488 arrow->setShowBadge( true );
1489 arrow->badgeItem()->setValue( featureCount );
1490 }
1491 }
1492}
1493
1494void QgsModelChildAlgorithmGraphicItem::setSinkFeatureCount( const QString &outputName, long long featureCount )
1495{
1496 const int index = indexForOutput( outputName );
1497 if ( index < 0 )
1498 return;
1499
1500 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1501 for ( QgsModelArrowItem *arrow : arrows )
1502 {
1503 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1504 {
1505 arrow->setShowBadge( true );
1506 arrow->badgeItem()->setValue( featureCount );
1507 }
1508 }
1509}
1510
1511void QgsModelChildAlgorithmGraphicItem::setProgress( double progress )
1512{
1513 if ( mProgress == progress )
1514 return;
1515
1516 mProgress = progress;
1517 update();
1518}
1519
1520void QgsModelChildAlgorithmGraphicItem::setStarted()
1521{
1522 mStarted = true;
1523 update();
1524}
1525
1526void QgsModelChildAlgorithmGraphicItem::setOutdated()
1527{
1528 mOutdated = true;
1529 update();
1530}
1531
1532int QgsModelChildAlgorithmGraphicItem::indexForInput( const QString &parameterName ) const
1533{
1534 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1535 {
1536 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1537 {
1539 }
1540 }
1541 return -1;
1542}
1543
1544int QgsModelChildAlgorithmGraphicItem::indexForOutput( const QString &output ) const
1545{
1546 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1547 {
1548 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1549 {
1551 }
1552 }
1553 return -1;
1554}
1555
1556void QgsModelChildAlgorithmGraphicItem::paintBackground( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
1557{
1558 if ( mProgress < 0 )
1559 {
1560 QgsModelComponentGraphicItem::paintBackground( painter, option, widget );
1561 return;
1562 }
1563
1564 paintOutline( painter, option, widget );
1565
1566 const QRectF rect = itemRect();
1567 QColor color;
1568 QColor stroke;
1569 if ( component()->color().isValid() )
1570 {
1571 color = component()->color();
1572 switch ( state() )
1573 {
1574 case Selected:
1575 color = color.darker( 110 );
1576 break;
1577 case Hover:
1578 color = color.darker( 105 );
1579 break;
1580
1581 case Normal:
1582 break;
1583 }
1584 stroke = color.darker( 110 );
1585 }
1586 else
1587 {
1588 color = fillColor( state() );
1589 stroke = strokeColor( state() );
1590 }
1591
1592 QPen strokePen = QPen( stroke, 0 );
1593 strokePen.setStyle( strokeStyle( state() ) );
1594 painter->setPen( strokePen );
1595
1596 const QColor colorLeft = color.darker( 120 );
1597 QColor colorRight = color;
1598
1599 constexpr double fadeSize = 5;
1600 const double fadeSizeProportionRect = fadeSize / rect.width();
1601
1602 if ( mProgress < 98 )
1603 {
1604 QLinearGradient gradient( rect.topLeft(), rect.topRight() );
1605 gradient.setColorAt( 0.0, colorLeft );
1606 gradient.setColorAt( std::max( 0.0, mProgress / 100 - fadeSizeProportionRect / 2 ), colorLeft );
1607 gradient.setColorAt( std::min( 1.0, mProgress / 100 + fadeSizeProportionRect / 2 ), colorRight );
1608 gradient.setColorAt( 1.0, colorRight );
1609
1610 painter->setBrush( QBrush( gradient ) );
1611 }
1612 else
1613 {
1614 painter->setBrush( QBrush( colorLeft ) );
1615 }
1616 painter->drawRect( rect );
1617}
1618
1619void QgsModelChildAlgorithmGraphicItem::deleteComponent()
1620{
1621 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1622 {
1623 emit aboutToChange( tr( "Remove %1" ).arg( child->algorithm() ? child->algorithm()->displayName() : tr( "Algorithm" ) ) );
1624 if ( !model()->removeChildAlgorithm( child->childId() ) )
1625 {
1626 QMessageBox::warning(
1627 nullptr,
1628 QObject::tr( "Could not remove algorithm" ),
1629 QObject::tr(
1630 "Other algorithms depend on the selected one.\n"
1631 "Remove them before trying to remove it."
1632 )
1633 );
1634 }
1635 else
1636 {
1637 emit changed();
1638 emit requestModelRepaint();
1639 }
1640 }
1641}
1642
1643void QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm()
1644{
1645 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1646 {
1647 model()->deactivateChildAlgorithm( child->childId() );
1648 emit requestModelRepaint();
1649 }
1650}
1651
1652void QgsModelChildAlgorithmGraphicItem::activateAlgorithm()
1653{
1654 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1655 {
1656 if ( model()->activateChildAlgorithm( child->childId() ) )
1657 {
1658 emit requestModelRepaint();
1659 }
1660 else
1661 {
1662 QMessageBox::warning(
1663 nullptr,
1664 QObject::tr( "Could not activate algorithm" ),
1665 QObject::tr(
1666 "The selected algorithm depends on other currently non-active algorithms.\n"
1667 "Activate them them before trying to activate it.."
1668 )
1669 );
1670 }
1671 }
1672}
1673
1674
1675QgsModelOutputGraphicItem::QgsModelOutputGraphicItem( QgsProcessingModelOutput *output, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1676 : QgsModelComponentGraphicItem( output, model, parent )
1677{
1678 QSvgRenderer svg( QgsApplication::iconPath( u"mIconModelOutput.svg"_s ) );
1679 QPainter painter( &mPicture );
1680 svg.render( &painter );
1681 painter.end();
1682 setLabel( output->description() );
1683}
1684
1685QColor QgsModelOutputGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1686{
1687 QColor c( 172, 196, 114 );
1688 switch ( state )
1689 {
1690 case Selected:
1691 c = c.darker( 110 );
1692 break;
1693 case Hover:
1694 c = c.darker( 105 );
1695 break;
1696
1697 case Normal:
1698 break;
1699 }
1700 return c;
1701}
1702
1703QColor QgsModelOutputGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1704{
1705 switch ( state )
1706 {
1707 case Selected:
1708 return QColor( 42, 65, 42 );
1709 case Hover:
1710 case Normal:
1711 return QColor( 90, 140, 90 );
1712 }
1713 return QColor();
1714}
1715
1716QColor QgsModelOutputGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1717{
1718 return Qt::black;
1719}
1720
1721QPicture QgsModelOutputGraphicItem::iconPicture() const
1722{
1723 return mPicture;
1724}
1725
1726void QgsModelOutputGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1727{
1728 if ( QgsProcessingModelOutput *output = dynamic_cast<QgsProcessingModelOutput *>( component() ) )
1729 {
1730 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setPosition( pos );
1731 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setSize( size );
1732 }
1733}
1734
1735bool QgsModelOutputGraphicItem::canDeleteComponent()
1736{
1737 if ( dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1738 {
1739 return true;
1740 }
1741 return false;
1742}
1743
1744void QgsModelOutputGraphicItem::deleteComponent()
1745{
1746 if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1747 {
1748 emit aboutToChange( tr( "Delete Output %1" ).arg( output->description() ) );
1749 model()->childAlgorithm( output->childId() ).removeModelOutput( output->name() );
1750 model()->updateDestinationParameters();
1751 emit changed();
1752 emit requestModelRepaint();
1753 }
1754}
1755
1756
1757//
1758// QgsModelGroupBoxGraphicItem
1759//
1760
1761QgsModelGroupBoxGraphicItem::QgsModelGroupBoxGraphicItem( QgsProcessingModelGroupBox *box, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1762 : QgsModelComponentGraphicItem( box, model, parent )
1763{
1764 setZValue( QgsModelGraphicsScene::ZValues::GroupBox );
1765 setLabel( box->description() );
1766
1767 QFont f = font();
1768 f.setBold( true );
1769 f.setPixelSize( 14 );
1770 setFont( f );
1771}
1772
1773void QgsModelGroupBoxGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1774{
1775 QMenu *popupmenu = new QMenu( event->widget() );
1776 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1777 connect( removeAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::deleteComponent );
1778 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1779 connect( editAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::editComponent );
1780 popupmenu->exec( event->screenPos() );
1781}
1782
1783QgsModelGroupBoxGraphicItem::~QgsModelGroupBoxGraphicItem() = default;
1784
1785QColor QgsModelGroupBoxGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1786{
1787 QColor c( 230, 230, 230 );
1788 switch ( state )
1789 {
1790 case Selected:
1791 c = c.darker( 110 );
1792 break;
1793 case Hover:
1794 c = c.darker( 105 );
1795 break;
1796
1797 case Normal:
1798 break;
1799 }
1800 return c;
1801}
1802
1803QColor QgsModelGroupBoxGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1804{
1805 switch ( state )
1806 {
1807 case Selected:
1808 return QColor( 50, 50, 50 );
1809 case Hover:
1810 case Normal:
1811 return QColor( 150, 150, 150 );
1812 }
1813 return QColor();
1814}
1815
1816QColor QgsModelGroupBoxGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1817{
1818 return QColor( 100, 100, 100 );
1819}
1820
1821Qt::PenStyle QgsModelGroupBoxGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1822{
1823 return Qt::DotLine;
1824}
1825
1826Qt::Alignment QgsModelGroupBoxGraphicItem::titleAlignment() const
1827{
1828 return Qt::AlignHCenter;
1829}
1830
1831void QgsModelGroupBoxGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1832{
1833 if ( QgsProcessingModelGroupBox *box = dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1834 {
1835 box->setPosition( pos );
1836 box->setSize( size );
1837 model()->addGroupBox( *box );
1838 }
1839}
1840
1841bool QgsModelGroupBoxGraphicItem::canDeleteComponent()
1842{
1843 if ( dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1844 {
1845 return true;
1846 }
1847 return false;
1848}
1849
1850void QgsModelGroupBoxGraphicItem::applyEdit( const QgsProcessingModelGroupBox &groupBox )
1851{
1852 QgsProcessingModelGroupBox newGroupBox = groupBox;
1853 const QList<QgsProcessingModelGroupBox> existingGroupBoxes = model()->groupBoxes();
1854 for ( const QgsProcessingModelGroupBox &existingGroupBox : existingGroupBoxes )
1855 {
1856 if ( existingGroupBox.uuid() == newGroupBox.uuid() )
1857 {
1858 // copy position and size from existing group box
1859 newGroupBox.setPosition( existingGroupBox.position() );
1860 newGroupBox.setSize( existingGroupBox.size() );
1861 }
1862 }
1863
1864 const QString commandId = u"groupbox:%1"_s.arg( newGroupBox.uuid() );
1865 emit aboutToChange( tr( "Edit Group Box" ), commandId );
1866
1867 model()->addGroupBox( newGroupBox );
1868 emit changed();
1869 emit requestModelRepaint();
1870}
1871
1872void QgsModelGroupBoxGraphicItem::deleteComponent()
1873{
1874 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1875 {
1876 emit aboutToChange( tr( "Delete Group Box" ) );
1877 model()->removeGroupBox( box->uuid() );
1878 emit changed();
1879 emit requestModelRepaint();
1880 }
1881}
1882
1883void QgsModelGroupBoxGraphicItem::editComponent()
1884{
1885 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1886 {
1887 QgsModelGroupBoxDefinitionDialog dlg( *box, this->scene()->views().at( 0 ) );
1888
1889 if ( dlg.exec() )
1890 {
1891 applyEdit( dlg.groupBox() );
1892 }
1893 }
1894}
1895
1896//
1897// QgsModelCommentGraphicItem
1898//
1899
1900QgsModelCommentGraphicItem::QgsModelCommentGraphicItem( QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1901 : QgsModelComponentGraphicItem( comment, model, parent )
1902 , mParentComponent( parentItem->component()->clone() )
1903 , mParentItem( parentItem )
1904{
1905 setLabel( comment->description() );
1906
1907 QFont f = font();
1908 f.setPixelSize( 9 );
1909 setFont( f );
1910}
1911
1912void QgsModelCommentGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1913{
1914 QMenu *popupmenu = new QMenu( event->widget() );
1915 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1916 connect( removeAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::deleteComponent );
1917 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1918 connect( editAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::editComponent );
1919 popupmenu->exec( event->screenPos() );
1920}
1921
1922QgsModelCommentGraphicItem::~QgsModelCommentGraphicItem() = default;
1923
1924QColor QgsModelCommentGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1925{
1926 QColor c( 230, 230, 230 );
1927 switch ( state )
1928 {
1929 case Selected:
1930 c = c.darker( 110 );
1931 break;
1932 case Hover:
1933 c = c.darker( 105 );
1934 break;
1935
1936 case Normal:
1937 break;
1938 }
1939 return c;
1940}
1941
1942QColor QgsModelCommentGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1943{
1944 switch ( state )
1945 {
1946 case Selected:
1947 return QColor( 50, 50, 50 );
1948 case Hover:
1949 case Normal:
1950 return QColor( 150, 150, 150 );
1951 }
1952 return QColor();
1953}
1954
1955QColor QgsModelCommentGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1956{
1957 return QColor( 100, 100, 100 );
1958}
1959
1960Qt::PenStyle QgsModelCommentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1961{
1962 return Qt::DotLine;
1963}
1964
1965void QgsModelCommentGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1966{
1967 if ( QgsProcessingModelComment *comment = modelComponent() )
1968 {
1969 comment->setPosition( pos );
1970 comment->setSize( size );
1971 }
1972}
1973
1974bool QgsModelCommentGraphicItem::canDeleteComponent()
1975{
1976 if ( modelComponent() )
1977 {
1978 return true;
1979 }
1980 return false;
1981}
1982
1983void QgsModelCommentGraphicItem::deleteComponent()
1984{
1985 if ( QgsProcessingModelComment *comment = modelComponent() )
1986 {
1987 emit aboutToChange( tr( "Delete Comment" ) );
1988 comment->setDescription( QString() );
1989 emit changed();
1990 emit requestModelRepaint();
1991 }
1992}
1993
1994void QgsModelCommentGraphicItem::editComponent()
1995{
1996 if ( mParentItem )
1997 {
1998 mParentItem->editComment();
1999 }
2000}
2001
2002QgsProcessingModelComment *QgsModelCommentGraphicItem::modelComponent()
2003{
2004 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( mParentComponent.get() ) )
2005 {
2006 return model()->childAlgorithm( child->childId() ).comment();
2007 }
2008 else if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( mParentComponent.get() ) )
2009 {
2010 return model()->parameterComponent( param->parameterName() ).comment();
2011 }
2012 else if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( mParentComponent.get() ) )
2013 {
2014 return model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).comment();
2015 }
2016 return nullptr;
2017}
2018
2019QgsModelComponentGraphicItem *QgsModelCommentGraphicItem::parentComponentItem() const
2020{
2021 return mParentItem;
2022}
2023
2024
@ Success
Child was successfully executed.
Definition qgis.h:4084
@ NotExecuted
Child has not been executed.
Definition qgis.h:4083
@ Failed
Child encountered an error while executing.
Definition qgis.h:4085
@ Warning
Warning message.
Definition qgis.h:162
@ ExpressionText
Parameter value is taken from a text with expressions, evaluated just before the algorithm runs.
Definition qgis.h:4071
@ ModelOutput
Parameter value is linked to an output parameter for the model.
Definition qgis.h:4072
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
Definition qgis.h:4068
@ ModelParameter
Parameter value is taken from a parent model parameter.
Definition qgis.h:4067
@ StaticValue
Parameter value is a static value.
Definition qgis.h:4069
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
Definition qgis.h:4070
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
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 dialog which allows users to specify the properties of a model group box.
A mouse event which is the result of a user interaction with a QgsModelGraphicsView.
QPointF modelPoint() const
Returns the event point location in model coordinates.
Represents a 2D point.
Definition qgspointxy.h:62
Abstract base class for processing algorithms.
Encapsulates the results of running a child algorithm within a model.
QVariantMap outputs() const
Returns the outputs generated by the child algorithm.
Qgis::ProcessingModelChildAlgorithmExecutionStatus executionStatus() const
Returns the status of executing the child algorithm.
Base class for the definition of processing outputs.
QString description() const
Returns the description for the output.
Base class for the definition of processing parameters.
virtual QString userFriendlyString(const QVariant &value) const
Returns a user-friendly string representation of the provided parameter value.
QString description() const
Returns the description for the parameter.
QString name() const
Returns the name of the parameter.
Contains settings which reflect the context in which a Processing parameter widget is shown.
static int parameterDefinitionIndex(const QgsProcessingAlgorithm *algorithm, const QString &name)
Returns the index of the parameter with matching name for a specified algorithm.
static int outputDefinitionIndex(const QgsProcessingAlgorithm *algorithm, const QString &name)
Returns the index of the output matching name for a specified algorithm.
An interface for objects which can create Processing widget contexts.
A rectangle specified with double values.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:8127
#define BUILTIN_UNREACHABLE
Definition qgis.h:8163
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:8126
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.