QGIS API Documentation 4.3.0-Master (026d9cd75d1)
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
1361 parameterValueAsString = u": %1"_s.arg( firstParameterSource.expressionText() );
1363 break;
1364
1366 parameterValueAsString = u": <%1>"_s.arg( firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) ) );
1367 break;
1368
1370 {
1371 const QString friendlyName = firstParameterSource.friendlyIdentifier( const_cast<QgsProcessingModelAlgorithm *>( model() ) );
1372 parameterValueAsString = friendlyName.isEmpty() ? u":"_s : u": <%1>"_s.arg( friendlyName );
1373 break;
1374 }
1375
1377 const QVariant paramValue = paramSources[0].staticValue();
1378 parameterValueAsString = u": %1"_s.arg( param->userFriendlyString( paramValue ) );
1379 }
1380 title += parameterValueAsString;
1381 }
1382
1383 return truncatedTextForItem( title );
1384 }
1385
1386 case Qt::LeftEdge:
1387 case Qt::RightEdge:
1388 break;
1389 }
1390 }
1391 return QString();
1392}
1393
1394void QgsModelChildAlgorithmGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1395{
1396 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast<QgsProcessingModelChildAlgorithm *>( component() ) )
1397 {
1398 model()->childAlgorithm( child->childId() ).setPosition( pos );
1399 model()->childAlgorithm( child->childId() ).setSize( size );
1400 }
1401}
1402
1403bool QgsModelChildAlgorithmGraphicItem::canDeleteComponent()
1404{
1405 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1406 {
1407 return model()->dependentChildAlgorithms( child->childId() ).empty();
1408 }
1409 return false;
1410}
1411
1412void QgsModelChildAlgorithmGraphicItem::setResults( const QgsProcessingModelChildAlgorithmResult &results )
1413{
1414 if ( mResults == results )
1415 return;
1416
1417 mOutdated = false;
1418 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1420 {
1421 for ( QgsModelArrowItem *arrow : arrows )
1422 {
1423 arrow->setShowBadge( false );
1424 }
1425 }
1426 else
1427 {
1428 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1429 {
1430 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1431 {
1432 const QVariantMap outputs = results.outputs();
1433 for ( auto it = outputs.constBegin(); it != outputs.constEnd(); ++it )
1434 {
1435 // don't show badges for output layers, these will just be the internal layer identifiers and we have logic elsewhere
1436 // to show actually useful information in the badges (feature counts)
1437 if ( const QgsProcessingOutputDefinition *outputDefinition = algorithm->outputDefinition( it.key() ); outputDefinition && outputDefinition->isMapLayer() )
1438 continue;
1439
1440 const int index = indexForOutput( it.key() );
1441 if ( index >= 0 )
1442 {
1443 for ( QgsModelArrowItem *arrow : arrows )
1444 {
1445 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1446 {
1447 arrow->setShowBadge( true );
1448 arrow->badgeItem()->setValue( it.value() );
1449 }
1450 }
1451 }
1452 }
1453 }
1454 }
1455 }
1456
1457 mResults = results;
1458 mStarted = false;
1459 update();
1460 emit updateArrowPaths();
1461}
1462
1463void QgsModelChildAlgorithmGraphicItem::setSourceFeatureCount( const QString &parameterName, long long featureCount )
1464{
1465 const int index = indexForInput( parameterName );
1466 if ( index < 0 )
1467 return;
1468
1469 const QList< QgsModelArrowItem * > arrows = incomingArrows();
1470 for ( QgsModelArrowItem *arrow : arrows )
1471 {
1472 if ( arrow->endIndex() == index && arrow->endEdge() == Qt::TopEdge )
1473 {
1474 arrow->setShowBadge( true );
1475 arrow->badgeItem()->setValue( featureCount );
1476 }
1477 }
1478}
1479
1480void QgsModelChildAlgorithmGraphicItem::setSinkFeatureCount( const QString &outputName, long long featureCount )
1481{
1482 const int index = indexForOutput( outputName );
1483 if ( index < 0 )
1484 return;
1485
1486 const QList< QgsModelArrowItem * > arrows = outgoingArrows();
1487 for ( QgsModelArrowItem *arrow : arrows )
1488 {
1489 if ( arrow->startIndex() == index && arrow->startEdge() == Qt::BottomEdge )
1490 {
1491 arrow->setShowBadge( true );
1492 arrow->badgeItem()->setValue( featureCount );
1493 }
1494 }
1495}
1496
1497void QgsModelChildAlgorithmGraphicItem::setProgress( double progress )
1498{
1499 if ( mProgress == progress )
1500 return;
1501
1502 mProgress = progress;
1503 update();
1504}
1505
1506void QgsModelChildAlgorithmGraphicItem::setStarted()
1507{
1508 mStarted = true;
1509 update();
1510}
1511
1512void QgsModelChildAlgorithmGraphicItem::setOutdated()
1513{
1514 mOutdated = true;
1515 update();
1516}
1517
1518int QgsModelChildAlgorithmGraphicItem::indexForInput( const QString &parameterName ) const
1519{
1520 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1521 {
1522 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1523 {
1525 }
1526 }
1527 return -1;
1528}
1529
1530int QgsModelChildAlgorithmGraphicItem::indexForOutput( const QString &output ) const
1531{
1532 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1533 {
1534 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
1535 {
1537 }
1538 }
1539 return -1;
1540}
1541
1542void QgsModelChildAlgorithmGraphicItem::paintBackground( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
1543{
1544 if ( mProgress < 0 )
1545 {
1546 QgsModelComponentGraphicItem::paintBackground( painter, option, widget );
1547 return;
1548 }
1549
1550 paintOutline( painter, option, widget );
1551
1552 const QRectF rect = itemRect();
1553 QColor color;
1554 QColor stroke;
1555 if ( component()->color().isValid() )
1556 {
1557 color = component()->color();
1558 switch ( state() )
1559 {
1560 case Selected:
1561 color = color.darker( 110 );
1562 break;
1563 case Hover:
1564 color = color.darker( 105 );
1565 break;
1566
1567 case Normal:
1568 break;
1569 }
1570 stroke = color.darker( 110 );
1571 }
1572 else
1573 {
1574 color = fillColor( state() );
1575 stroke = strokeColor( state() );
1576 }
1577
1578 QPen strokePen = QPen( stroke, 0 );
1579 strokePen.setStyle( strokeStyle( state() ) );
1580 painter->setPen( strokePen );
1581
1582 const QColor colorLeft = color.darker( 120 );
1583 QColor colorRight = color;
1584
1585 constexpr double fadeSize = 5;
1586 const double fadeSizeProportionRect = fadeSize / rect.width();
1587
1588 if ( mProgress < 98 )
1589 {
1590 QLinearGradient gradient( rect.topLeft(), rect.topRight() );
1591 gradient.setColorAt( 0.0, colorLeft );
1592 gradient.setColorAt( std::max( 0.0, mProgress / 100 - fadeSizeProportionRect / 2 ), colorLeft );
1593 gradient.setColorAt( std::min( 1.0, mProgress / 100 + fadeSizeProportionRect / 2 ), colorRight );
1594 gradient.setColorAt( 1.0, colorRight );
1595
1596 painter->setBrush( QBrush( gradient ) );
1597 }
1598 else
1599 {
1600 painter->setBrush( QBrush( colorLeft ) );
1601 }
1602 painter->drawRect( rect );
1603}
1604
1605void QgsModelChildAlgorithmGraphicItem::deleteComponent()
1606{
1607 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1608 {
1609 emit aboutToChange( tr( "Remove %1" ).arg( child->algorithm() ? child->algorithm()->displayName() : tr( "Algorithm" ) ) );
1610 if ( !model()->removeChildAlgorithm( child->childId() ) )
1611 {
1612 QMessageBox::warning(
1613 nullptr,
1614 QObject::tr( "Could not remove algorithm" ),
1615 QObject::tr(
1616 "Other algorithms depend on the selected one.\n"
1617 "Remove them before trying to remove it."
1618 )
1619 );
1620 }
1621 else
1622 {
1623 emit changed();
1624 emit requestModelRepaint();
1625 }
1626 }
1627}
1628
1629void QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm()
1630{
1631 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1632 {
1633 model()->deactivateChildAlgorithm( child->childId() );
1634 emit requestModelRepaint();
1635 }
1636}
1637
1638void QgsModelChildAlgorithmGraphicItem::activateAlgorithm()
1639{
1640 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( component() ) )
1641 {
1642 if ( model()->activateChildAlgorithm( child->childId() ) )
1643 {
1644 emit requestModelRepaint();
1645 }
1646 else
1647 {
1648 QMessageBox::warning(
1649 nullptr,
1650 QObject::tr( "Could not activate algorithm" ),
1651 QObject::tr(
1652 "The selected algorithm depends on other currently non-active algorithms.\n"
1653 "Activate them them before trying to activate it.."
1654 )
1655 );
1656 }
1657 }
1658}
1659
1660
1661QgsModelOutputGraphicItem::QgsModelOutputGraphicItem( QgsProcessingModelOutput *output, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1662 : QgsModelComponentGraphicItem( output, model, parent )
1663{
1664 QSvgRenderer svg( QgsApplication::iconPath( u"mIconModelOutput.svg"_s ) );
1665 QPainter painter( &mPicture );
1666 svg.render( &painter );
1667 painter.end();
1668 setLabel( output->description() );
1669}
1670
1671QColor QgsModelOutputGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1672{
1673 QColor c( 172, 196, 114 );
1674 switch ( state )
1675 {
1676 case Selected:
1677 c = c.darker( 110 );
1678 break;
1679 case Hover:
1680 c = c.darker( 105 );
1681 break;
1682
1683 case Normal:
1684 break;
1685 }
1686 return c;
1687}
1688
1689QColor QgsModelOutputGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1690{
1691 switch ( state )
1692 {
1693 case Selected:
1694 return QColor( 42, 65, 42 );
1695 case Hover:
1696 case Normal:
1697 return QColor( 90, 140, 90 );
1698 }
1699 return QColor();
1700}
1701
1702QColor QgsModelOutputGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1703{
1704 return Qt::black;
1705}
1706
1707QPicture QgsModelOutputGraphicItem::iconPicture() const
1708{
1709 return mPicture;
1710}
1711
1712void QgsModelOutputGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1713{
1714 if ( QgsProcessingModelOutput *output = dynamic_cast<QgsProcessingModelOutput *>( component() ) )
1715 {
1716 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setPosition( pos );
1717 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setSize( size );
1718 }
1719}
1720
1721bool QgsModelOutputGraphicItem::canDeleteComponent()
1722{
1723 if ( dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1724 {
1725 return true;
1726 }
1727 return false;
1728}
1729
1730void QgsModelOutputGraphicItem::deleteComponent()
1731{
1732 if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( component() ) )
1733 {
1734 emit aboutToChange( tr( "Delete Output %1" ).arg( output->description() ) );
1735 model()->childAlgorithm( output->childId() ).removeModelOutput( output->name() );
1736 model()->updateDestinationParameters();
1737 emit changed();
1738 emit requestModelRepaint();
1739 }
1740}
1741
1742
1743//
1744// QgsModelGroupBoxGraphicItem
1745//
1746
1747QgsModelGroupBoxGraphicItem::QgsModelGroupBoxGraphicItem( QgsProcessingModelGroupBox *box, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1748 : QgsModelComponentGraphicItem( box, model, parent )
1749{
1750 setZValue( QgsModelGraphicsScene::ZValues::GroupBox );
1751 setLabel( box->description() );
1752
1753 QFont f = font();
1754 f.setBold( true );
1755 f.setPixelSize( 14 );
1756 setFont( f );
1757}
1758
1759void QgsModelGroupBoxGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1760{
1761 QMenu *popupmenu = new QMenu( event->widget() );
1762 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1763 connect( removeAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::deleteComponent );
1764 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1765 connect( editAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::editComponent );
1766 popupmenu->exec( event->screenPos() );
1767}
1768
1769QgsModelGroupBoxGraphicItem::~QgsModelGroupBoxGraphicItem() = default;
1770
1771QColor QgsModelGroupBoxGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1772{
1773 QColor c( 230, 230, 230 );
1774 switch ( state )
1775 {
1776 case Selected:
1777 c = c.darker( 110 );
1778 break;
1779 case Hover:
1780 c = c.darker( 105 );
1781 break;
1782
1783 case Normal:
1784 break;
1785 }
1786 return c;
1787}
1788
1789QColor QgsModelGroupBoxGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1790{
1791 switch ( state )
1792 {
1793 case Selected:
1794 return QColor( 50, 50, 50 );
1795 case Hover:
1796 case Normal:
1797 return QColor( 150, 150, 150 );
1798 }
1799 return QColor();
1800}
1801
1802QColor QgsModelGroupBoxGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1803{
1804 return QColor( 100, 100, 100 );
1805}
1806
1807Qt::PenStyle QgsModelGroupBoxGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1808{
1809 return Qt::DotLine;
1810}
1811
1812Qt::Alignment QgsModelGroupBoxGraphicItem::titleAlignment() const
1813{
1814 return Qt::AlignHCenter;
1815}
1816
1817void QgsModelGroupBoxGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1818{
1819 if ( QgsProcessingModelGroupBox *box = dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1820 {
1821 box->setPosition( pos );
1822 box->setSize( size );
1823 model()->addGroupBox( *box );
1824 }
1825}
1826
1827bool QgsModelGroupBoxGraphicItem::canDeleteComponent()
1828{
1829 if ( dynamic_cast<QgsProcessingModelGroupBox *>( component() ) )
1830 {
1831 return true;
1832 }
1833 return false;
1834}
1835
1836void QgsModelGroupBoxGraphicItem::applyEdit( const QgsProcessingModelGroupBox &groupBox )
1837{
1838 const QString commandId = u"groupbox:%1"_s.arg( groupBox.uuid() );
1839 emit aboutToChange( tr( "Edit Group Box" ), commandId );
1840 model()->addGroupBox( groupBox );
1841 emit changed();
1842 emit requestModelRepaint();
1843}
1844
1845void QgsModelGroupBoxGraphicItem::deleteComponent()
1846{
1847 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1848 {
1849 emit aboutToChange( tr( "Delete Group Box" ) );
1850 model()->removeGroupBox( box->uuid() );
1851 emit changed();
1852 emit requestModelRepaint();
1853 }
1854}
1855
1856void QgsModelGroupBoxGraphicItem::editComponent()
1857{
1858 if ( const QgsProcessingModelGroupBox *box = dynamic_cast<const QgsProcessingModelGroupBox *>( component() ) )
1859 {
1860 QgsModelGroupBoxDefinitionDialog dlg( *box, this->scene()->views().at( 0 ) );
1861
1862 if ( dlg.exec() )
1863 {
1864 applyEdit( dlg.groupBox() );
1865 }
1866 }
1867}
1868
1869//
1870// QgsModelCommentGraphicItem
1871//
1872
1873QgsModelCommentGraphicItem::QgsModelCommentGraphicItem( QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1874 : QgsModelComponentGraphicItem( comment, model, parent )
1875 , mParentComponent( parentItem->component()->clone() )
1876 , mParentItem( parentItem )
1877{
1878 setLabel( comment->description() );
1879
1880 QFont f = font();
1881 f.setPixelSize( 9 );
1882 setFont( f );
1883}
1884
1885void QgsModelCommentGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1886{
1887 QMenu *popupmenu = new QMenu( event->widget() );
1888 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1889 connect( removeAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::deleteComponent );
1890 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1891 connect( editAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::editComponent );
1892 popupmenu->exec( event->screenPos() );
1893}
1894
1895QgsModelCommentGraphicItem::~QgsModelCommentGraphicItem() = default;
1896
1897QColor QgsModelCommentGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1898{
1899 QColor c( 230, 230, 230 );
1900 switch ( state )
1901 {
1902 case Selected:
1903 c = c.darker( 110 );
1904 break;
1905 case Hover:
1906 c = c.darker( 105 );
1907 break;
1908
1909 case Normal:
1910 break;
1911 }
1912 return c;
1913}
1914
1915QColor QgsModelCommentGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1916{
1917 switch ( state )
1918 {
1919 case Selected:
1920 return QColor( 50, 50, 50 );
1921 case Hover:
1922 case Normal:
1923 return QColor( 150, 150, 150 );
1924 }
1925 return QColor();
1926}
1927
1928QColor QgsModelCommentGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1929{
1930 return QColor( 100, 100, 100 );
1931}
1932
1933Qt::PenStyle QgsModelCommentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1934{
1935 return Qt::DotLine;
1936}
1937
1938void QgsModelCommentGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1939{
1940 if ( QgsProcessingModelComment *comment = modelComponent() )
1941 {
1942 comment->setPosition( pos );
1943 comment->setSize( size );
1944 }
1945}
1946
1947bool QgsModelCommentGraphicItem::canDeleteComponent()
1948{
1949 if ( modelComponent() )
1950 {
1951 return true;
1952 }
1953 return false;
1954}
1955
1956void QgsModelCommentGraphicItem::deleteComponent()
1957{
1958 if ( QgsProcessingModelComment *comment = modelComponent() )
1959 {
1960 emit aboutToChange( tr( "Delete Comment" ) );
1961 comment->setDescription( QString() );
1962 emit changed();
1963 emit requestModelRepaint();
1964 }
1965}
1966
1967void QgsModelCommentGraphicItem::editComponent()
1968{
1969 if ( mParentItem )
1970 {
1971 mParentItem->editComment();
1972 }
1973}
1974
1975QgsProcessingModelComment *QgsModelCommentGraphicItem::modelComponent()
1976{
1977 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast<const QgsProcessingModelChildAlgorithm *>( mParentComponent.get() ) )
1978 {
1979 return model()->childAlgorithm( child->childId() ).comment();
1980 }
1981 else if ( const QgsProcessingModelParameter *param = dynamic_cast<const QgsProcessingModelParameter *>( mParentComponent.get() ) )
1982 {
1983 return model()->parameterComponent( param->parameterName() ).comment();
1984 }
1985 else if ( const QgsProcessingModelOutput *output = dynamic_cast<const QgsProcessingModelOutput *>( mParentComponent.get() ) )
1986 {
1987 return model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).comment();
1988 }
1989 return nullptr;
1990}
1991
1992QgsModelComponentGraphicItem *QgsModelCommentGraphicItem::parentComponentItem() const
1993{
1994 return mParentItem;
1995}
1996
1997
@ Success
Child was successfully executed.
Definition qgis.h:4079
@ NotExecuted
Child has not been executed.
Definition qgis.h:4078
@ Failed
Child encountered an error while executing.
Definition qgis.h:4080
@ 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:4066
@ ModelOutput
Parameter value is linked to an output parameter for the model.
Definition qgis.h:4067
@ ChildOutput
Parameter value is taken from an output generated by a child algorithm.
Definition qgis.h:4063
@ ModelParameter
Parameter value is taken from a parent model parameter.
Definition qgis.h:4062
@ StaticValue
Parameter value is a static value.
Definition qgis.h:4064
@ Expression
Parameter value is taken from an expression, evaluated just before the algorithm runs.
Definition qgis.h:4065
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 Q_NOWARN_DEPRECATED_POP
Definition qgis.h:8015
#define BUILTIN_UNREACHABLE
Definition qgis.h:8051
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:8014
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.