QGIS API Documentation 4.1.0-Master (31622b25bb0)
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
857QgsModelParameterGraphicItem::QgsModelParameterGraphicItem( QgsProcessingModelParameter *parameter, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
858 : QgsModelComponentGraphicItem( parameter, model, parent )
859{
860 QSvgRenderer svg( QgsApplication::iconPath( u"mIconModelInput.svg"_s ) );
861 QPainter painter( &mPicture );
862 svg.render( &painter );
863 painter.end();
864
865 if ( const QgsProcessingParameterDefinition *parameterDefinition = model->parameterDefinition( parameter->parameterName() ) )
866 setLabel( parameterDefinition->description() );
867 else
868 setLabel( QObject::tr( "Error (%1)" ).arg( parameter->parameterName() ) );
869}
870
871void QgsModelParameterGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
872{
873 QMenu *popupmenu = new QMenu( event->widget() );
874 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
875 connect( removeAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::deleteComponent );
876 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
877 connect( editAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComponent );
878 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
879 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
880
881 popupmenu->exec( event->screenPos() );
882}
883
884QColor QgsModelParameterGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
885{
886 QColor c( 238, 242, 131 );
887 switch ( state )
888 {
889 case Selected:
890 c = c.darker( 110 );
891 break;
892 case Hover:
893 c = c.darker( 105 );
894 break;
895
896 case Normal:
897 break;
898 }
899 return c;
900}
901
902QColor QgsModelParameterGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
903{
904 switch ( state )
905 {
906 case Selected:
907 return QColor( 116, 113, 68 );
908 case Hover:
909 case Normal:
910 return QColor( 234, 226, 118 );
911 }
912 return QColor();
913}
914
915QColor QgsModelParameterGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
916{
917 return Qt::black;
918}
919
920QPicture QgsModelParameterGraphicItem::iconPicture() const
921{
922 return mPicture;
923}
924
925int QgsModelParameterGraphicItem::linkPointCount( Qt::Edge edge ) const
926{
927 switch ( edge )
928 {
929 case Qt::BottomEdge:
930 return 1;
931 case Qt::TopEdge:
932 case Qt::LeftEdge:
933 case Qt::RightEdge:
934 break;
935 }
936
937 return 0;
938}
939
940QString QgsModelParameterGraphicItem::linkPointText( Qt::Edge, int index ) const
941{
942 if ( index < 0 )
943 {
944 return QString();
945 }
946
947 if ( const QgsProcessingModelParameter *parameter = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
948 {
949 QString text = this->model()->parameterDefinition( parameter->parameterName() )->type();
950
951 // Getting the default value to append to the box name
952 if ( const QgsProcessingParameterDefinition *paramDef = this->model()->parameterDefinition( parameter->parameterName() ) )
953 {
954 const QVariant paramValue = paramDef->defaultValue();
955
956 if ( paramValue.isValid() )
957 {
958 text += ": " + paramDef->userFriendlyString( paramValue );
959 }
960 }
961 return truncatedTextForItem( text );
962 }
963
964 return QString();
965}
966
967QColor QgsModelParameterGraphicItem::linkColor( Qt::Edge /* unused in this implementation because parameters only have a bottom edge */, int index ) const
968{
969 if ( index < 0 )
970 {
971 return FALLBACK_COLOR;
972 }
973
974 if ( const QgsProcessingModelParameter *parameter = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
975 {
976 if ( const QgsProcessingParameterDefinition *parameterDefinition = model()->parameterDefinition( parameter->parameterName() ) )
977 {
978 return parameterDefinition->modelColor();
979 }
980 }
981
982 return FALLBACK_COLOR;
983}
984
985void QgsModelParameterGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
986{
987 if ( QgsProcessingModelParameter *param = dynamic_cast<QgsProcessingModelParameter *>( component() ) )
988 {
989 model()->parameterComponent( param->parameterName() ).setPosition( pos );
990 model()->parameterComponent( param->parameterName() ).setSize( size );
991 }
992}
993
994bool QgsModelParameterGraphicItem::canDeleteComponent()
995{
996 if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( component() ) )
997 {
998 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
999 {
1000 return false;
1001 }
1002 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
1003 {
1004 return false;
1005 }
1006 else
1007 {
1008 return true;
1009 }
1010 }
1011 return false;
1012}
1013
1014void QgsModelParameterGraphicItem::deleteComponent()
1015{
1016 if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( component() ) )
1017 {
1018 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
1019 {
1020 QMessageBox::warning(
1021 nullptr,
1022 QObject::tr( "Could not remove input" ),
1023 QObject::tr(
1024 "Algorithms depend on the selected input.\n"
1025 "Remove them before trying to remove it."
1026 )
1027 );
1028 }
1029 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
1030 {
1031 QMessageBox::warning(
1032 nullptr,
1033 QObject::tr( "Could not remove input" ),
1034 QObject::tr(
1035 "Other inputs depend on the selected input.\n"
1036 "Remove them before trying to remove it."
1037 )
1038 );
1039 }
1040 else
1041 {
1042 emit aboutToChange( tr( "Delete Input %1" ).arg( param->description() ) );
1043 model()->removeModelParameter( param->parameterName() );
1044 emit changed();
1045 emit requestModelRepaint();
1046 }
1047 }
1048}
1049
1050
1051QgsModelChildAlgorithmGraphicItem::QgsModelChildAlgorithmGraphicItem( QgsProcessingModelChildAlgorithm *child, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1052 : QgsModelComponentGraphicItem( child, model, parent )
1053{
1054 if ( child->algorithm() && !child->algorithm()->svgIconPath().isEmpty() )
1055 {
1056 QSvgRenderer svg( child->algorithm()->svgIconPath() );
1057 const QSizeF size = svg.defaultSize();
1058 QPainter painter( &mPicture );
1059 painter.scale( 16.0 / size.width(), 16.0 / size.width() );
1060 svg.render( &painter );
1061 painter.end();
1062 }
1063 else if ( child->algorithm() )
1064 {
1065 mPixmap = child->algorithm()->icon().pixmap( 15, 15 );
1066 }
1067
1068 setLabel( child->description() );
1069
1070 QStringList issues;
1071 mIsValid = model->validateChildAlgorithm( child->childId(), issues );
1072}
1073
1074void QgsModelChildAlgorithmGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1075{
1076 QMenu *popupmenu = new QMenu( event->widget() );
1077
1078 if ( isSelected() )
1079 {
1080 QAction *runSelectedStepsAction = popupmenu->addAction( QObject::tr( "Run Selected Steps…" ) );
1081 runSelectedStepsAction->setIcon( QgsApplication::getThemeIcon( u"mActionRunSelected.svg"_s ) );
1082 connect( runSelectedStepsAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runSelected );
1083 }
1084
1085 QAction *runFromHereAction = popupmenu->addAction( QObject::tr( "Run from Here…" ) );
1086 runFromHereAction->setIcon( QgsApplication::getThemeIcon( u"mActionStart.svg"_s ) );
1087 connect( runFromHereAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runFromHere );
1088
1089 popupmenu->addSeparator();
1090
1091 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1092 connect( removeAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deleteComponent );
1093 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1094 connect( editAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::editComponent );
1095 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
1096 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
1097 popupmenu->addSeparator();
1098
1099 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1100 {
1101 if ( !child->isActive() )
1102 {
1103 QAction *activateAction = popupmenu->addAction( QObject::tr( "Activate" ) );
1104 connect( activateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::activateAlgorithm );
1105 }
1106 else
1107 {
1108 QAction *deactivateAction = popupmenu->addAction( QObject::tr( "Deactivate" ) );
1109 connect( deactivateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm );
1110 }
1111
1112 // only show the "View Output Layers" action for algorithms which create layers
1113 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1114 {
1115 const QList<const QgsProcessingParameterDefinition *> outputParams = algorithm->destinationParameterDefinitions();
1116 if ( !outputParams.isEmpty() )
1117 {
1118 popupmenu->addSeparator();
1119 QAction *viewOutputLayersAction = popupmenu->addAction( QObject::tr( "View Output Layers" ) );
1120 viewOutputLayersAction->setIcon( QgsApplication::getThemeIcon( u"mActionShowSelectedLayers.svg"_s ) );
1121 connect( viewOutputLayersAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showPreviousResults );
1122 // enable this action only when the child succeeded
1123 switch ( mResults.executionStatus() )
1124 {
1127 viewOutputLayersAction->setEnabled( false );
1128 break;
1129
1131 break;
1132 }
1133 }
1134 }
1135
1136 QAction *viewLogAction = popupmenu->addAction( QObject::tr( "View Log…" ) );
1137 connect( viewLogAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showLog );
1138 // enable this action even when the child failed
1139 switch ( mResults.executionStatus() )
1140 {
1142 viewLogAction->setEnabled( false );
1143 break;
1144
1147 break;
1148 }
1149 }
1150
1151 popupmenu->exec( event->screenPos() );
1152}
1153
1154QColor QgsModelChildAlgorithmGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1155{
1156 QColor c;
1157
1158 if ( mIsValid )
1159 c = QColor( 255, 255, 255 );
1160 else
1161 c = QColor( 208, 0, 0 );
1162
1163 switch ( state )
1164 {
1165 case Selected:
1166 c = c.darker( 110 );
1167 break;
1168 case Hover:
1169 c = c.darker( 105 );
1170 break;
1171
1172 case Normal:
1173 break;
1174 }
1175 return c;
1176}
1177
1178QColor QgsModelChildAlgorithmGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1179{
1180 switch ( state )
1181 {
1182 case Selected:
1183 return mIsValid ? QColor( 50, 50, 50 ) : QColor( 80, 0, 0 );
1184 case Hover:
1185 case Normal:
1186 return mIsValid ? Qt::gray : QColor( 134, 0, 0 );
1187 }
1188 return QColor();
1189}
1190
1191QColor QgsModelChildAlgorithmGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1192{
1193 return mIsValid ? ( qgis::down_cast<const QgsProcessingModelChildAlgorithm *>( component() )->isActive() ? Qt::black : Qt::gray ) : QColor( 255, 255, 255 );
1194}
1195
1196QColor QgsModelChildAlgorithmGraphicItem::outlineColor() const
1197{
1198 if ( mOutdated )
1199 {
1200 return QColor( 150, 150, 0 );
1201 }
1202
1203 switch ( mResults.executionStatus() )
1204 {
1206 if ( mStarted )
1207 {
1208 return QColor( 150, 150, 150 );
1209 }
1210 return QColor();
1212 return QColor( 55, 160, 55 );
1214 return QColor( 208, 0, 0 );
1215 }
1217}
1218
1219QPixmap QgsModelChildAlgorithmGraphicItem::iconPixmap() const
1220{
1221 return mPixmap;
1222}
1223
1224QPicture QgsModelChildAlgorithmGraphicItem::iconPicture() const
1225{
1226 return mPicture;
1227}
1228
1229int QgsModelChildAlgorithmGraphicItem::linkPointCount( Qt::Edge edge ) const
1230{
1231 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1232 {
1233 if ( !child->algorithm() )
1234 return 0;
1235
1236 switch ( edge )
1237 {
1238 case Qt::BottomEdge:
1239 return child->algorithm()->outputDefinitions().size();
1240 case Qt::TopEdge:
1241 {
1242 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1243 params.erase(
1244 std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition *param ) { return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination(); } ),
1245 params.end()
1246 );
1247 return params.size();
1248 }
1249
1250 case Qt::LeftEdge:
1251 case Qt::RightEdge:
1252 break;
1253 }
1254 }
1255 return 0;
1256}
1257
1258QColor QgsModelComponentGraphicItem::linkColor( Qt::Edge edge, int index ) const
1259{
1260 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1261 {
1262 if ( !child->algorithm() )
1263 {
1264 return FALLBACK_COLOR;
1265 }
1266
1267 switch ( edge )
1268 {
1269 case Qt::BottomEdge:
1270 {
1271 if ( index <= child->algorithm()->outputDefinitions().size() - 1 )
1272 {
1273 return child->algorithm()->outputDefinitions().at( index )->modelColor();
1274 }
1275 return FALLBACK_COLOR;
1276 }
1277 case Qt::TopEdge:
1278 {
1279 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1280
1281 if ( index <= params.size() - 1 )
1282 {
1283 return params.at( index )->modelColor();
1284 }
1285
1286 return FALLBACK_COLOR;
1287 }
1288
1289 case Qt::LeftEdge:
1290 case Qt::RightEdge:
1291 break;
1292 }
1293 }
1294
1295 return FALLBACK_COLOR;
1296}
1297
1298QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int index ) const
1299{
1300 if ( index < 0 )
1301 return QString();
1302
1303 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1304 {
1305 if ( !child->algorithm() )
1306 return QString();
1307
1308 switch ( edge )
1309 {
1310 case Qt::BottomEdge:
1311 {
1312 if ( index >= child->algorithm()->outputDefinitions().length() )
1313 {
1314 // something goes wrong and tried to link to an not existing output
1315 QgsMessageLog::logMessage( tr( "Cannot link output for child: %1" ).arg( child->algorithm()->name() ), "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1316 return QString();
1317 }
1318
1319 const QgsProcessingOutputDefinition *output = child->algorithm()->outputDefinitions().at( index );
1320 QString title = output->description();
1321 return truncatedTextForItem( title );
1322 }
1323
1324 case Qt::TopEdge:
1325 {
1326 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1327 params.erase(
1328 std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition *param ) { return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination(); } ),
1329 params.end()
1330 );
1331
1332 if ( index >= params.length() )
1333 {
1334 // something goes wrong and tried to link to an not existing source parameter
1335 QgsMessageLog::logMessage( tr( "Cannot link source for child: %1" ).arg( child->algorithm()->name() ), "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1336 return QString();
1337 }
1338
1339 const QgsProcessingParameterDefinition *param = params.at( index );
1340 QString name = param->name();
1341 QString title = param->description();
1342 QgsProcessingModelChildParameterSources paramSources = child->parameterSources().value( name );
1343 QString parameterValueAsString;
1344
1345 if ( !paramSources.empty() )
1346 {
1347 QgsProcessingModelChildParameterSource firstParameterSource = paramSources[0];
1348
1349 switch ( firstParameterSource.source() )
1350 {
1352 parameterValueAsString = u": %1"_s.arg( firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) ) );
1353 break;
1354
1356 parameterValueAsString = u": %1"_s.arg( firstParameterSource.expression() );
1357 break;
1358
1360 parameterValueAsString = u": %1"_s.arg( firstParameterSource.expressionText() );
1361 break;
1362
1364 parameterValueAsString = u": <%1>"_s.arg( firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) ) );
1365 break;
1366
1368 {
1369 const QString friendlyName = firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) );
1370 parameterValueAsString = friendlyName.isEmpty() ? u":"_s : u": <%1>"_s.arg( friendlyName );
1371 break;
1372 }
1373
1375 const QVariant paramValue = paramSources[0].staticValue();
1376 parameterValueAsString = u": %1"_s.arg( param->userFriendlyString( paramValue ) );
1377 }
1378 title += parameterValueAsString;
1379 }
1380
1381 return truncatedTextForItem( title );
1382 }
1383
1384 case Qt::LeftEdge:
1385 case Qt::RightEdge:
1386 break;
1387 }
1388 }
1389 return QString();
1390}
1391
1392void QgsModelChildAlgorithmGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1393{
1394 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast<QgsProcessingModelChildAlgorithm *>( component() ) )
1395 {
1396 model()->childAlgorithm( child->childId() ).setPosition( pos );
1397 model()->childAlgorithm( child->childId() ).setSize( size );
1398 }
1399}
1400
1401bool QgsModelChildAlgorithmGraphicItem::canDeleteComponent()
1402{
1403 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1404 {
1405 return model()->dependentChildAlgorithms( child->childId() ).empty();
1406 }
1407 return false;
1408}
1409
1410void QgsModelChildAlgorithmGraphicItem::setResults( const QgsProcessingModelChildAlgorithmResult &results )
1411{
1412 if ( mResults == results )
1413 return;
1414
1415 mOutdated = false;
1416 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1418 {
1419 for ( QgsModelArrowItem *arrow : arrows )
1420 {
1421 arrow->setShowBadge( false );
1422 }
1423 }
1424 else
1425 {
1426 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1427 {
1428 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1429 {
1430 const QVariantMap outputs = results.outputs();
1431 for ( auto it = outputs.constBegin(); it != outputs.constEnd(); ++it )
1432 {
1433 // don't show badges for output layers, these will just be the internal layer identifiers and we have logic elsewhere
1434 // to show actually useful information in the badges (feature counts)
1435 if ( const QgsProcessingOutputDefinition *outputDefinition = algorithm->outputDefinition( it.key() ); outputDefinition && outputDefinition->isMapLayer() )
1436 continue;
1437
1438 const int index = indexForOutput( it.key() );
1439 if ( index >= 0 )
1440 {
1441 for ( QgsModelArrowItem *arrow : arrows )
1442 {
1443 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1444 {
1445 arrow->setShowBadge( true );
1446 arrow->badgeItem()->setValue( it.value() );
1447 }
1448 }
1449 }
1450 }
1451 }
1452 }
1453 }
1454
1455 mResults = results;
1456 mStarted = false;
1457 update();
1458 emit updateArrowPaths();
1459}
1460
1461void QgsModelChildAlgorithmGraphicItem::setSourceFeatureCount( const QString &parameterName, long long featureCount )
1462{
1463 const int index = indexForInput( parameterName );
1464 if ( index < 0 )
1465 return;
1466
1467 const QList< QgsModelArrowItem * > arrows = incomingArrows();
1468 for ( QgsModelArrowItem *arrow : arrows )
1469 {
1470 if ( arrow->endIndex() == index && arrow->endEdge() == Qt::TopEdge )
1471 {
1472 arrow->setShowBadge( true );
1473 arrow->badgeItem()->setValue( featureCount );
1474 }
1475 }
1476}
1477
1478void QgsModelChildAlgorithmGraphicItem::setSinkFeatureCount( const QString &outputName, long long featureCount )
1479{
1480 const int index = indexForOutput( outputName );
1481 if ( index < 0 )
1482 return;
1483
1484 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1485 for ( QgsModelArrowItem *arrow : arrows )
1486 {
1487 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1488 {
1489 arrow->setShowBadge( true );
1490 arrow->badgeItem()->setValue( featureCount );
1491 }
1492 }
1493}
1494
1495void QgsModelChildAlgorithmGraphicItem::setProgress( double progress )
1496{
1497 if ( mProgress == progress )
1498 return;
1499
1500 mProgress = progress;
1501 update();
1502}
1503
1504void QgsModelChildAlgorithmGraphicItem::setStarted()
1505{
1506 mStarted = true;
1507 update();
1508}
1509
1510void QgsModelChildAlgorithmGraphicItem::setOutdated()
1511{
1512 mOutdated = true;
1513 update();
1514}
1515
1516int QgsModelChildAlgorithmGraphicItem::indexForInput( const QString &parameterName ) const
1517{
1518 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1519 {
1520 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1521 {
1523 }
1524 }
1525 return -1;
1526}
1527
1528int QgsModelChildAlgorithmGraphicItem::indexForOutput( const QString &output ) const
1529{
1530 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1531 {
1532 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1533 {
1535 }
1536 }
1537 return -1;
1538}
1539
1540void QgsModelChildAlgorithmGraphicItem::paintBackground( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
1541{
1542 if ( mProgress < 0 )
1543 {
1544 QgsModelComponentGraphicItem::paintBackground( painter, option, widget );
1545 return;
1546 }
1547
1548 paintOutline( painter, option, widget );
1549
1550 const QRectF rect = itemRect();
1551 QColor color;
1552 QColor stroke;
1553 if ( component()->color().isValid() )
1554 {
1555 color = component()->color();
1556 switch ( state() )
1557 {
1558 case Selected:
1559 color = color.darker( 110 );
1560 break;
1561 case Hover:
1562 color = color.darker( 105 );
1563 break;
1564
1565 case Normal:
1566 break;
1567 }
1568 stroke = color.darker( 110 );
1569 }
1570 else
1571 {
1572 color = fillColor( state() );
1573 stroke = strokeColor( state() );
1574 }
1575
1576 QPen strokePen = QPen( stroke, 0 );
1577 strokePen.setStyle( strokeStyle( state() ) );
1578 painter->setPen( strokePen );
1579
1580 const QColor colorLeft = color.darker( 120 );
1581 QColor colorRight = color;
1582
1583 constexpr double fadeSize = 5;
1584 const double fadeSizeProportionRect = fadeSize / rect.width();
1585
1586 if ( mProgress < 98 )
1587 {
1588 QLinearGradient gradient( rect.topLeft(), rect.topRight() );
1589 gradient.setColorAt( 0.0, colorLeft );
1590 gradient.setColorAt( std::max( 0.0, mProgress / 100 - fadeSizeProportionRect / 2 ), colorLeft );
1591 gradient.setColorAt( std::min( 1.0, mProgress / 100 + fadeSizeProportionRect / 2 ), colorRight );
1592 gradient.setColorAt( 1.0, colorRight );
1593
1594 painter->setBrush( QBrush( gradient ) );
1595 }
1596 else
1597 {
1598 painter->setBrush( QBrush( colorLeft ) );
1599 }
1600 painter->drawRect( rect );
1601}
1602
1603void QgsModelChildAlgorithmGraphicItem::deleteComponent()
1604{
1605 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1606 {
1607 emit aboutToChange( tr( "Remove %1" ).arg( child->algorithm() ? child->algorithm()->displayName() : tr( "Algorithm" ) ) );
1608 if ( !model()->removeChildAlgorithm( child->childId() ) )
1609 {
1610 QMessageBox::warning(
1611 nullptr,
1612 QObject::tr( "Could not remove algorithm" ),
1613 QObject::tr(
1614 "Other algorithms depend on the selected one.\n"
1615 "Remove them before trying to remove it."
1616 )
1617 );
1618 }
1619 else
1620 {
1621 emit changed();
1622 emit requestModelRepaint();
1623 }
1624 }
1625}
1626
1627void QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm()
1628{
1629 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1630 {
1631 model()->deactivateChildAlgorithm( child->childId() );
1632 emit requestModelRepaint();
1633 }
1634}
1635
1636void QgsModelChildAlgorithmGraphicItem::activateAlgorithm()
1637{
1638 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1639 {
1640 if ( model()->activateChildAlgorithm( child->childId() ) )
1641 {
1642 emit requestModelRepaint();
1643 }
1644 else
1645 {
1646 QMessageBox::warning(
1647 nullptr,
1648 QObject::tr( "Could not activate algorithm" ),
1649 QObject::tr(
1650 "The selected algorithm depends on other currently non-active algorithms.\n"
1651 "Activate them them before trying to activate it.."
1652 )
1653 );
1654 }
1655 }
1656}
1657
1658
1659QgsModelOutputGraphicItem::QgsModelOutputGraphicItem( QgsProcessingModelOutput *output, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1660 : QgsModelComponentGraphicItem( output, model, parent )
1661{
1662 QSvgRenderer svg( QgsApplication::iconPath( u"mIconModelOutput.svg"_s ) );
1663 QPainter painter( &mPicture );
1664 svg.render( &painter );
1665 painter.end();
1666 setLabel( output->description() );
1667}
1668
1669QColor QgsModelOutputGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1670{
1671 QColor c( 172, 196, 114 );
1672 switch ( state )
1673 {
1674 case Selected:
1675 c = c.darker( 110 );
1676 break;
1677 case Hover:
1678 c = c.darker( 105 );
1679 break;
1680
1681 case Normal:
1682 break;
1683 }
1684 return c;
1685}
1686
1687QColor QgsModelOutputGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1688{
1689 switch ( state )
1690 {
1691 case Selected:
1692 return QColor( 42, 65, 42 );
1693 case Hover:
1694 case Normal:
1695 return QColor( 90, 140, 90 );
1696 }
1697 return QColor();
1698}
1699
1700QColor QgsModelOutputGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1701{
1702 return Qt::black;
1703}
1704
1705QPicture QgsModelOutputGraphicItem::iconPicture() const
1706{
1707 return mPicture;
1708}
1709
1710void QgsModelOutputGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1711{
1712 if ( QgsProcessingModelOutput *output = dynamic_cast<QgsProcessingModelOutput *>( component() ) )
1713 {
1714 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setPosition( pos );
1715 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setSize( size );
1716 }
1717}
1718
1719bool QgsModelOutputGraphicItem::canDeleteComponent()
1720{
1721 if ( dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1722 {
1723 return true;
1724 }
1725 return false;
1726}
1727
1728void QgsModelOutputGraphicItem::deleteComponent()
1729{
1730 if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1731 {
1732 emit aboutToChange( tr( "Delete Output %1" ).arg( output->description() ) );
1733 model()->childAlgorithm( output->childId() ).removeModelOutput( output->name() );
1734 model()->updateDestinationParameters();
1735 emit changed();
1736 emit requestModelRepaint();
1737 }
1738}
1739
1740
1741//
1742// QgsModelGroupBoxGraphicItem
1743//
1744
1745QgsModelGroupBoxGraphicItem::QgsModelGroupBoxGraphicItem( QgsProcessingModelGroupBox *box, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1746 : QgsModelComponentGraphicItem( box, model, parent )
1747{
1748 setZValue( QgsModelGraphicsScene::ZValues::GroupBox );
1749 setLabel( box->description() );
1750
1751 QFont f = font();
1752 f.setBold( true );
1753 f.setPixelSize( 14 );
1754 setFont( f );
1755}
1756
1757void QgsModelGroupBoxGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1758{
1759 QMenu *popupmenu = new QMenu( event->widget() );
1760 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1761 connect( removeAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::deleteComponent );
1762 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1763 connect( editAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::editComponent );
1764 popupmenu->exec( event->screenPos() );
1765}
1766
1767QgsModelGroupBoxGraphicItem::~QgsModelGroupBoxGraphicItem() = default;
1768
1769QColor QgsModelGroupBoxGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1770{
1771 QColor c( 230, 230, 230 );
1772 switch ( state )
1773 {
1774 case Selected:
1775 c = c.darker( 110 );
1776 break;
1777 case Hover:
1778 c = c.darker( 105 );
1779 break;
1780
1781 case Normal:
1782 break;
1783 }
1784 return c;
1785}
1786
1787QColor QgsModelGroupBoxGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1788{
1789 switch ( state )
1790 {
1791 case Selected:
1792 return QColor( 50, 50, 50 );
1793 case Hover:
1794 case Normal:
1795 return QColor( 150, 150, 150 );
1796 }
1797 return QColor();
1798}
1799
1800QColor QgsModelGroupBoxGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1801{
1802 return QColor( 100, 100, 100 );
1803}
1804
1805Qt::PenStyle QgsModelGroupBoxGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1806{
1807 return Qt::DotLine;
1808}
1809
1810Qt::Alignment QgsModelGroupBoxGraphicItem::titleAlignment() const
1811{
1812 return Qt::AlignHCenter;
1813}
1814
1815void QgsModelGroupBoxGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1816{
1817 if ( QgsProcessingModelGroupBox *box = dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1818 {
1819 box->setPosition( pos );
1820 box->setSize( size );
1821 model()->addGroupBox( *box );
1822 }
1823}
1824
1825bool QgsModelGroupBoxGraphicItem::canDeleteComponent()
1826{
1827 if ( dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1828 {
1829 return true;
1830 }
1831 return false;
1832}
1833
1834void QgsModelGroupBoxGraphicItem::applyEdit( const QgsProcessingModelGroupBox &groupBox )
1835{
1836 const QString commandId = u"groupbox:%1"_s.arg( groupBox.uuid() );
1837 emit aboutToChange( tr( "Edit Group Box" ), commandId );
1838 model()->addGroupBox( groupBox );
1839 emit changed();
1840 emit requestModelRepaint();
1841}
1842
1843void QgsModelGroupBoxGraphicItem::deleteComponent()
1844{
1845 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1846 {
1847 emit aboutToChange( tr( "Delete Group Box" ) );
1848 model()->removeGroupBox( box->uuid() );
1849 emit changed();
1850 emit requestModelRepaint();
1851 }
1852}
1853
1854void QgsModelGroupBoxGraphicItem::editComponent()
1855{
1856 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1857 {
1858 QgsModelGroupBoxDefinitionDialog dlg( *box, this->scene()->views().at( 0 ) );
1859
1860 if ( dlg.exec() )
1861 {
1862 applyEdit( dlg.groupBox() );
1863 }
1864 }
1865}
1866
1867//
1868// QgsModelCommentGraphicItem
1869//
1870
1871QgsModelCommentGraphicItem::QgsModelCommentGraphicItem( QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1872 : QgsModelComponentGraphicItem( comment, model, parent )
1873 , mParentComponent( parentItem->component()->clone() )
1874 , mParentItem( parentItem )
1875{
1876 setLabel( comment->description() );
1877
1878 QFont f = font();
1879 f.setPixelSize( 9 );
1880 setFont( f );
1881}
1882
1883void QgsModelCommentGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1884{
1885 QMenu *popupmenu = new QMenu( event->widget() );
1886 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1887 connect( removeAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::deleteComponent );
1888 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1889 connect( editAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::editComponent );
1890 popupmenu->exec( event->screenPos() );
1891}
1892
1893QgsModelCommentGraphicItem::~QgsModelCommentGraphicItem() = default;
1894
1895QColor QgsModelCommentGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1896{
1897 QColor c( 230, 230, 230 );
1898 switch ( state )
1899 {
1900 case Selected:
1901 c = c.darker( 110 );
1902 break;
1903 case Hover:
1904 c = c.darker( 105 );
1905 break;
1906
1907 case Normal:
1908 break;
1909 }
1910 return c;
1911}
1912
1913QColor QgsModelCommentGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1914{
1915 switch ( state )
1916 {
1917 case Selected:
1918 return QColor( 50, 50, 50 );
1919 case Hover:
1920 case Normal:
1921 return QColor( 150, 150, 150 );
1922 }
1923 return QColor();
1924}
1925
1926QColor QgsModelCommentGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1927{
1928 return QColor( 100, 100, 100 );
1929}
1930
1931Qt::PenStyle QgsModelCommentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1932{
1933 return Qt::DotLine;
1934}
1935
1936void QgsModelCommentGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1937{
1938 if ( QgsProcessingModelComment *comment = modelComponent() )
1939 {
1940 comment->setPosition( pos );
1941 comment->setSize( size );
1942 }
1943}
1944
1945bool QgsModelCommentGraphicItem::canDeleteComponent()
1946{
1947 if ( modelComponent() )
1948 {
1949 return true;
1950 }
1951 return false;
1952}
1953
1954void QgsModelCommentGraphicItem::deleteComponent()
1955{
1956 if ( QgsProcessingModelComment *comment = modelComponent() )
1957 {
1958 emit aboutToChange( tr( "Delete Comment" ) );
1959 comment->setDescription( QString() );
1960 emit changed();
1961 emit requestModelRepaint();
1962 }
1963}
1964
1965void QgsModelCommentGraphicItem::editComponent()
1966{
1967 if ( mParentItem )
1968 {
1969 mParentItem->editComment();
1970 }
1971}
1972
1973QgsProcessingModelComment *QgsModelCommentGraphicItem::modelComponent()
1974{
1975 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( mParentComponent.get() ) )
1976 {
1977 return model()->childAlgorithm( child->childId() ).comment();
1978 }
1979 else if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( mParentComponent.get() ) )
1980 {
1981 return model()->parameterComponent( param->parameterName() ).comment();
1982 }
1983 else if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( mParentComponent.get() ) )
1984 {
1985 return model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).comment();
1986 }
1987 return nullptr;
1988}
1989
1990QgsModelComponentGraphicItem *QgsModelCommentGraphicItem::parentComponentItem() const
1991{
1992 return mParentItem;
1993}
1994
1995
@ Success
Child was successfully executed.
Definition qgis.h:4049
@ NotExecuted
Child has not been executed.
Definition qgis.h:4048
@ Failed
Child encountered an error while executing.
Definition qgis.h:4050
@ 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:4036
@ ModelOutput
Parameter value is linked to an output parameter for the model.
Definition qgis.h:4037
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
Definition qgis.h:4033
@ ModelParameter
Parameter value is taken from a parent model parameter.
Definition qgis.h:4032
@ StaticValue
Parameter value is a static value.
Definition qgis.h:4034
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
Definition qgis.h:4035
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.
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.
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 BUILTIN_UNREACHABLE
Definition qgis.h:7802
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.