QGIS API Documentation 3.41.0-Master (3440c17df1d)
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#include "moc_qgsmodelcomponentgraphicitem.cpp"
24#include "qgsapplication.h"
25#include "qgsmodelgraphicitem.h"
28#include "qgsmodelviewtool.h"
31#include "qgsmessagelog.h"
32
33#include <QSvgRenderer>
34#include <QPicture>
35#include <QPainter>
36#include <QGraphicsSceneHoverEvent>
37#include <QApplication>
38#include <QPalette>
39#include <QMessageBox>
40#include <QMenu>
41
43
44QgsModelComponentGraphicItem::QgsModelComponentGraphicItem( QgsProcessingModelComponent *component, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
45 : QGraphicsObject( parent )
46 , mComponent( component )
47 , mModel( model )
48{
49 setAcceptHoverEvents( true );
50 setFlag( QGraphicsItem::ItemIsSelectable, true );
51 setFlag( QGraphicsItem::ItemSendsGeometryChanges, true );
52 setZValue( QgsModelGraphicsScene::ZValues::ModelComponent );
53
54 mFont.setPixelSize( 12 );
55
56 QSvgRenderer svg( QgsApplication::iconPath( QStringLiteral( "mActionEditModelComponent.svg" ) ) );
57 QPicture editPicture;
58 QPainter painter( &editPicture );
59 svg.render( &painter );
60 painter.end();
61 mEditButton = new QgsModelDesignerFlatButtonGraphicItem( this, editPicture, QPointF( 0, 0 ) );
62 connect( mEditButton, &QgsModelDesignerFlatButtonGraphicItem::clicked, this, &QgsModelComponentGraphicItem::editComponent );
63
64 QSvgRenderer svg2( QgsApplication::iconPath( QStringLiteral( "mActionDeleteModelComponent.svg" ) ) );
65 QPicture deletePicture;
66 painter.begin( &deletePicture );
67 svg2.render( &painter );
68 painter.end();
69 mDeleteButton = new QgsModelDesignerFlatButtonGraphicItem( this, deletePicture, QPointF( 0, 0 ) );
70 connect( mDeleteButton, &QgsModelDesignerFlatButtonGraphicItem::clicked, this, &QgsModelComponentGraphicItem::deleteComponent );
71
72 updateButtonPositions();
73}
74
75QgsModelComponentGraphicItem::Flags QgsModelComponentGraphicItem::flags() const
76{
77 return QgsModelComponentGraphicItem::Flags();
78}
79
80QgsModelComponentGraphicItem::~QgsModelComponentGraphicItem() = default;
81
82QgsProcessingModelComponent *QgsModelComponentGraphicItem::component()
83{
84 return mComponent.get();
85}
86
87const QgsProcessingModelComponent *QgsModelComponentGraphicItem::component() const
88{
89 return mComponent.get();
90}
91
92QgsProcessingModelAlgorithm *QgsModelComponentGraphicItem::model()
93{
94 return mModel;
95}
96
97QgsModelGraphicsView *QgsModelComponentGraphicItem::view()
98{
99 if ( scene()->views().isEmpty() )
100 return nullptr;
101
102 return qobject_cast< QgsModelGraphicsView * >( scene()->views().first() );
103}
104
105QFont QgsModelComponentGraphicItem::font() const
106{
107 return mFont;
108}
109
110void QgsModelComponentGraphicItem::setFont( const QFont &font )
111{
112 mFont = font;
113 update();
114}
115
116void QgsModelComponentGraphicItem::moveComponentBy( qreal dx, qreal dy )
117{
118 setPos( mComponent->position().x() + dx, mComponent->position().y() + dy );
119 mComponent->setPosition( pos() );
120
121 emit aboutToChange( tr( "Move %1" ).arg( mComponent->description() ) );
122 updateStoredComponentPosition( pos(), mComponent->size() );
123 emit changed();
124
125 emit sizePositionChanged();
126 emit updateArrowPaths();
127}
128
129void QgsModelComponentGraphicItem::previewItemMove( qreal dx, qreal dy )
130{
131 setPos( mComponent->position().x() + dx, mComponent->position().y() + dy );
132 emit updateArrowPaths();
133}
134
135void QgsModelComponentGraphicItem::setItemRect( QRectF rect )
136{
137 rect = rect.normalized();
138
139 if ( rect.width() < MIN_COMPONENT_WIDTH )
140 rect.setWidth( MIN_COMPONENT_WIDTH );
141 if ( rect.height() < MIN_COMPONENT_HEIGHT )
142 rect.setHeight( MIN_COMPONENT_HEIGHT );
143
144 setPos( rect.center() );
145 prepareGeometryChange();
146
147 emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );
148
149 mComponent->setPosition( pos() );
150 mComponent->setSize( rect.size() );
151 updateStoredComponentPosition( pos(), mComponent->size() );
152
153 updateButtonPositions();
154 emit changed();
155
156 emit updateArrowPaths();
157 emit sizePositionChanged();
158}
159
160QRectF QgsModelComponentGraphicItem::previewItemRectChange( QRectF rect )
161{
162 rect = rect.normalized();
163
164 if ( rect.width() < MIN_COMPONENT_WIDTH )
165 rect.setWidth( MIN_COMPONENT_WIDTH );
166 if ( rect.height() < MIN_COMPONENT_HEIGHT )
167 rect.setHeight( MIN_COMPONENT_HEIGHT );
168
169 setPos( rect.center() );
170 prepareGeometryChange();
171
172 mTempSize = rect.size();
173
174 updateButtonPositions();
175 emit updateArrowPaths();
176
177 return rect;
178}
179
180void QgsModelComponentGraphicItem::finalizePreviewedItemRectChange( QRectF )
181{
182 mComponent->setPosition( pos() );
183 prepareGeometryChange();
184 mComponent->setSize( mTempSize );
185 mTempSize = QSizeF();
186
187 emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );
188 updateStoredComponentPosition( pos(), mComponent->size() );
189
190 updateButtonPositions();
191
192 emit changed();
193
194 emit sizePositionChanged();
195 emit updateArrowPaths();
196}
197
198void QgsModelComponentGraphicItem::modelHoverEnterEvent( QgsModelViewMouseEvent *event )
199{
200 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
201 updateToolTip( mapFromScene( event->modelPoint() ) );
202}
203
204void QgsModelComponentGraphicItem::modelHoverMoveEvent( QgsModelViewMouseEvent *event )
205{
206 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
207 updateToolTip( mapFromScene( event->modelPoint() ) );
208}
209
210void QgsModelComponentGraphicItem::modelHoverLeaveEvent( QgsModelViewMouseEvent * )
211{
212 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
213 {
214 setToolTip( QString() );
215 if ( mIsHovering )
216 {
217 mIsHovering = false;
218 update();
219 emit repaintArrows();
220 }
221 }
222}
223
224void QgsModelComponentGraphicItem::modelDoubleClickEvent( QgsModelViewMouseEvent * )
225{
226 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
227 editComponent();
228}
229
230void QgsModelComponentGraphicItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent * )
231{
232 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
233 editComponent();
234}
235
236void QgsModelComponentGraphicItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
237{
238 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
239 updateToolTip( event->pos() );
240}
241
242void QgsModelComponentGraphicItem::hoverMoveEvent( QGraphicsSceneHoverEvent *event )
243{
244 if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
245 updateToolTip( event->pos() );
246}
247
248void QgsModelComponentGraphicItem::hoverLeaveEvent( QGraphicsSceneHoverEvent * )
249{
250 modelHoverLeaveEvent( nullptr );
251}
252
253QVariant QgsModelComponentGraphicItem::itemChange( QGraphicsItem::GraphicsItemChange change, const QVariant &value )
254{
255 switch ( change )
256 {
257 case QGraphicsItem::ItemSelectedChange:
258 {
259 emit repaintArrows();
260 break;
261 }
262
263 case QGraphicsItem::ItemSceneChange:
264 {
265 if ( !mInitialized )
266 {
267 // ideally would be in constructor, but cannot call virtual methods from that...
268 if ( linkPointCount( Qt::TopEdge ) )
269 {
270 mExpandTopButton = new QgsModelDesignerFoldButtonGraphicItem( this, mComponent->linksCollapsed( Qt::TopEdge ), QPointF( 0, 0 ) );
271 connect( mExpandTopButton, &QgsModelDesignerFoldButtonGraphicItem::folded, this, [ = ]( bool folded ) { fold( Qt::TopEdge, folded ); } );
272 }
273 if ( linkPointCount( Qt::BottomEdge ) )
274 {
275 mExpandBottomButton = new QgsModelDesignerFoldButtonGraphicItem( this, mComponent->linksCollapsed( Qt::BottomEdge ), QPointF( 0, 0 ) );
276 connect( mExpandBottomButton, &QgsModelDesignerFoldButtonGraphicItem::folded, this, [ = ]( bool folded ) { fold( Qt::BottomEdge, folded ); } );
277 }
278 mInitialized = true;
279 updateButtonPositions();
280 }
281 break;
282 }
283
284 default:
285 break;
286 }
287
288 return QGraphicsObject::itemChange( change, value );
289}
290
291QRectF QgsModelComponentGraphicItem::boundingRect() const
292{
293 const QFontMetricsF fm( mFont );
294 const int linksAbove = linkPointCount( Qt::TopEdge );
295 const int linksBelow = linkPointCount( Qt::BottomEdge );
296
297 const double hUp = linksAbove == 0 ? 0 :
298 fm.height() * 1.2 * ( ( mComponent->linksCollapsed( Qt::TopEdge ) ? 0 : linksAbove ) + 2 );
299 const double hDown = linksBelow == 0 ? 0 :
300 fm.height() * 1.2 * ( ( mComponent->linksCollapsed( Qt::BottomEdge ) ? 0 : linksBelow ) + 2 );
301 return QRectF( -( itemSize().width() ) / 2 - RECT_PEN_SIZE,
302 -( itemSize().height() ) / 2 - hUp - RECT_PEN_SIZE,
303 itemSize().width() + 2 * RECT_PEN_SIZE,
304 itemSize().height() + hDown + hUp + 2 * RECT_PEN_SIZE );
305}
306
307bool QgsModelComponentGraphicItem::contains( const QPointF &point ) const
308{
309 const QRectF paintingBounds = boundingRect();
310 if ( point.x() < paintingBounds.left() + RECT_PEN_SIZE )
311 return false;
312 if ( point.x() > paintingBounds.right() - RECT_PEN_SIZE )
313 return false;
314 if ( point.y() < paintingBounds.top() + RECT_PEN_SIZE )
315 return false;
316 if ( point.y() > paintingBounds.bottom() - RECT_PEN_SIZE )
317 return false;
318
319 return true;
320}
321
322void QgsModelComponentGraphicItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * )
323{
324 const QRectF rect = itemRect();
325 QColor color;
326 QColor stroke;
327 QColor foreColor;
328 if ( mComponent->color().isValid() )
329 {
330 color = mComponent->color();
331 switch ( state() )
332 {
333 case Selected:
334 color = color.darker( 110 );
335 break;
336 case Hover:
337 color = color.darker( 105 );
338 break;
339
340 case Normal:
341 break;
342 }
343 stroke = color.darker( 110 );
344 foreColor = color.lightness() > 150 ? QColor( 0, 0, 0 ) : QColor( 255, 255, 255 );
345 }
346 else
347 {
348 color = fillColor( state() );
349 stroke = strokeColor( state() );
350 foreColor = textColor( state() );
351 }
352
353 QPen strokePen = QPen( stroke, 0 ) ; // 0 width "cosmetic" pen
354 strokePen.setStyle( strokeStyle( state() ) );
355 painter->setPen( strokePen );
356 painter->setBrush( QBrush( color, Qt::SolidPattern ) );
357 painter->drawRect( rect );
358 painter->setFont( font() );
359 painter->setPen( QPen( foreColor ) );
360
361 QString text;
362
363 const QSizeF componentSize = itemSize();
364
365 const QFontMetricsF fm( font() );
366 double h = fm.ascent();
367 QPointF pt( -componentSize.width() / 2 + 25, componentSize.height() / 2.0 - h + 1 );
368
369 if ( iconPicture().isNull() && iconPixmap().isNull() )
370 {
371 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 );
372 text = label();
373 painter->drawText( labelRect, Qt::TextWordWrap | titleAlignment(), text );
374 }
375 else
376 {
377 const QRectF labelRect = QRectF( rect.left() + 21 + TEXT_MARGIN, rect.top() + TEXT_MARGIN,
378 rect.width() - 2 * TEXT_MARGIN - mButtonSize.width() - BUTTON_MARGIN - 21, rect.height() - 2 * TEXT_MARGIN );
379 text = label();
380 painter->drawText( labelRect, Qt::TextWordWrap | Qt::AlignVCenter, text );
381 }
382
383 painter->setPen( QPen( QApplication::palette().color( QPalette::Text ) ) );
384
385 if ( linkPointCount( Qt::TopEdge ) || linkPointCount( Qt::BottomEdge ) )
386 {
387 h = -( fm.height() * 1.2 );
388 h = h - componentSize.height() / 2.0 + 5;
389 pt = QPointF( -componentSize.width() / 2 + 25, h );
390 painter->drawText( pt, QObject::tr( "In" ) );
391 int i = 1;
392 if ( !mComponent->linksCollapsed( Qt::TopEdge ) )
393 {
394 for ( int idx = 0; idx < linkPointCount( Qt::TopEdge ); ++idx )
395 {
396 text = linkPointText( Qt::TopEdge, idx );
397 h = -( fm.height() * 1.2 ) * ( i + 1 );
398 h = h - componentSize.height() / 2.0 + 5;
399 pt = QPointF( -componentSize.width() / 2 + 33, h );
400 painter->drawText( pt, text );
401 i += 1;
402 }
403 }
404
405 h = fm.height() * 1.1;
406 h = h + componentSize.height() / 2.0;
407 pt = QPointF( -componentSize.width() / 2 + 25, h );
408 painter->drawText( pt, QObject::tr( "Out" ) );
409 if ( !mComponent->linksCollapsed( Qt::BottomEdge ) )
410 {
411 for ( int idx = 0; idx < linkPointCount( Qt::BottomEdge ); ++idx )
412 {
413 text = linkPointText( Qt::BottomEdge, idx );
414 h = fm.height() * 1.2 * ( idx + 2 );
415 h = h + componentSize.height() / 2.0;
416 pt = QPointF( -componentSize.width() / 2 + 33, h );
417 painter->drawText( pt, text );
418 }
419 }
420 }
421
422 const QPixmap px = iconPixmap();
423 if ( !px.isNull() )
424 {
425 painter->drawPixmap( QPointF( -( componentSize.width() / 2.0 ) + 3, -8 ), px );
426 }
427 else
428 {
429 const QPicture pic = iconPicture();
430 if ( !pic.isNull() )
431 {
432 painter->drawPicture( QPointF( -( componentSize.width() / 2.0 ) + 3, -8 ), pic );
433 }
434 }
435}
436
437QRectF QgsModelComponentGraphicItem::itemRect( bool storedRect ) const
438{
439 if ( storedRect )
440 {
441 return QRectF( mComponent->position().x() - ( mComponent->size().width() ) / 2.0,
442 mComponent->position().y() - ( mComponent->size().height() ) / 2.0,
443 mComponent->size().width(),
444 mComponent->size().height() );
445 }
446 else
447 return QRectF( -( itemSize().width() ) / 2.0,
448 -( itemSize().height() ) / 2.0,
449 itemSize().width(),
450 itemSize().height() );
451}
452
453QString QgsModelComponentGraphicItem::truncatedTextForItem( const QString &text ) const
454{
455 const QFontMetricsF fm( mFont );
456 double width = fm.boundingRect( text ).width();
457 if ( width < itemSize().width() - 25 - mButtonSize.width() )
458 return text;
459
460 QString t = text;
461 t = t.left( t.length() - 3 ) + QChar( 0x2026 );
462 width = fm.boundingRect( t ).width();
463 while ( width > itemSize().width() - 25 - mButtonSize.width() )
464 {
465 if ( t.length() < 5 )
466 break;
467
468 t = t.left( t.length() - 4 ) + QChar( 0x2026 );
469 width = fm.boundingRect( t ).width();
470 }
471 return t;
472}
473
474Qt::PenStyle QgsModelComponentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
475{
476 return Qt::SolidLine;
477}
478
479Qt::Alignment QgsModelComponentGraphicItem::titleAlignment() const
480{
481 return Qt::AlignLeft;
482}
483
484QPicture QgsModelComponentGraphicItem::iconPicture() const
485{
486 return QPicture();
487}
488
489QPixmap QgsModelComponentGraphicItem::iconPixmap() const
490{
491 return QPixmap();
492}
493
494void QgsModelComponentGraphicItem::updateButtonPositions()
495{
496 mEditButton->setPosition( QPointF( itemSize().width() / 2.0 - mButtonSize.width() / 2.0 - BUTTON_MARGIN,
497 itemSize().height() / 2.0 - mButtonSize.height() / 2.0 - BUTTON_MARGIN ) );
498 mDeleteButton->setPosition( QPointF( itemSize().width() / 2.0 - mButtonSize.width() / 2.0 - BUTTON_MARGIN,
499 mButtonSize.height() / 2.0 - itemSize().height() / 2.0 + BUTTON_MARGIN ) );
500
501 if ( mExpandTopButton )
502 {
503 const QPointF pt = linkPoint( Qt::TopEdge, -1, true );
504 mExpandTopButton->setPosition( QPointF( 0, pt.y() ) );
505 }
506 if ( mExpandBottomButton )
507 {
508 const QPointF pt = linkPoint( Qt::BottomEdge, -1, false );
509 mExpandBottomButton->setPosition( QPointF( 0, pt.y() ) );
510 }
511}
512
513QSizeF QgsModelComponentGraphicItem::itemSize() const
514{
515 return !mTempSize.isValid() ? mComponent->size() : mTempSize;
516}
517
518void QgsModelComponentGraphicItem::updateToolTip( const QPointF &pos )
519{
520 const bool prevHoverStatus = mIsHovering;
521 if ( itemRect().contains( pos ) )
522 {
523 setToolTip( mLabel );
524 mIsHovering = true;
525 }
526 else
527 {
528 setToolTip( QString() );
529 mIsHovering = false;
530 }
531 if ( mIsHovering != prevHoverStatus )
532 {
533 update();
534 emit repaintArrows();
535 }
536}
537
538void QgsModelComponentGraphicItem::fold( Qt::Edge edge, bool folded )
539{
540 emit aboutToChange( !folded ? tr( "Expand Item" ) : tr( "Collapse Item" ) );
541 mComponent->setLinksCollapsed( edge, folded );
542 // also need to update the model's stored component
543
544 // TODO - this is not so nice, consider moving this to model class
545 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast< QgsProcessingModelChildAlgorithm * >( mComponent.get() ) )
546 mModel->childAlgorithm( child->childId() ).setLinksCollapsed( edge, folded );
547 else if ( QgsProcessingModelParameter *param = dynamic_cast< QgsProcessingModelParameter * >( mComponent.get() ) )
548 mModel->parameterComponent( param->parameterName() ).setLinksCollapsed( edge, folded );
549 else if ( QgsProcessingModelOutput *output = dynamic_cast< QgsProcessingModelOutput * >( mComponent.get() ) )
550 mModel->childAlgorithm( output->childId() ).modelOutput( output->name() ).setLinksCollapsed( edge, folded );
551
552 prepareGeometryChange();
553 emit updateArrowPaths();
554 emit changed();
555 update();
556}
557
558QString QgsModelComponentGraphicItem::label() const
559{
560 return mLabel;
561}
562
563void QgsModelComponentGraphicItem::setLabel( const QString &label )
564{
565 mLabel = label;
566 update();
567}
568
569QgsModelComponentGraphicItem::State QgsModelComponentGraphicItem::state() const
570{
571 if ( isSelected() )
572 return Selected;
573 else if ( mIsHovering )
574 return Hover;
575 else
576 return Normal;
577}
578
579int QgsModelComponentGraphicItem::linkPointCount( Qt::Edge ) const
580{
581 return 0;
582}
583
584QString QgsModelComponentGraphicItem::linkPointText( Qt::Edge, int ) const
585{
586 return QString();
587}
588
589QPointF QgsModelComponentGraphicItem::linkPoint( Qt::Edge edge, int index, bool incoming ) const
590{
591 switch ( edge )
592 {
593 case Qt::BottomEdge:
594 {
595 if ( linkPointCount( Qt::BottomEdge ) )
596 {
597 double offsetX = 25;
598 if ( mComponent->linksCollapsed( Qt::BottomEdge ) )
599 {
600 offsetX = 17;
601 }
602 const int pointIndex = !mComponent->linksCollapsed( Qt::BottomEdge ) ? index : -1;
603 const QString text = truncatedTextForItem( linkPointText( Qt::BottomEdge, index ) );
604 const QFontMetricsF fm( mFont );
605 const double w = fm.boundingRect( text ).width();
606 const double h = fm.height() * 1.2 * ( pointIndex + 1 ) + fm.height() / 2.0;
607 const double y = h + itemSize().height() / 2.0 + 5;
608 const double x = !mComponent->linksCollapsed( Qt::BottomEdge ) ? ( -itemSize().width() / 2 + 33 + w + 5 ) : 10;
609 return QPointF( incoming ? -itemSize().width() / 2 + offsetX
610 : x,
611 y );
612 }
613 break;
614 }
615
616 case Qt::TopEdge:
617 {
618 if ( linkPointCount( Qt::TopEdge ) )
619 {
620 double offsetX = 25;
621 int paramIndex = index;
622 if ( mComponent->linksCollapsed( Qt::TopEdge ) )
623 {
624 paramIndex = -1;
625 offsetX = 17;
626 }
627 const QFontMetricsF fm( mFont );
628 const QString text = truncatedTextForItem( linkPointText( Qt::TopEdge, index ) );
629 const double w = fm.boundingRect( text ).width();
630 double h = -( fm.height() * 1.2 ) * ( paramIndex + 2 ) - fm.height() / 2.0 + 8;
631 h = h - itemSize().height() / 2.0;
632 return QPointF( incoming ? -itemSize().width() / 2 + offsetX
633 : ( !mComponent->linksCollapsed( Qt::TopEdge ) ? ( -itemSize().width() / 2 + 33 + w + 5 ) : 10 ),
634 h );
635 }
636 break;
637 }
638 case Qt::LeftEdge:
639 case Qt::RightEdge:
640 break;
641 }
642
643 return QPointF();
644}
645
646QPointF QgsModelComponentGraphicItem::calculateAutomaticLinkPoint( QgsModelComponentGraphicItem *other, Qt::Edge &edge ) const
647{
648 // find closest edge to other item
649 const QgsRectangle otherRect( other->itemRect().translated( other->pos() ) );
650
651 const QPointF leftPoint = pos() + QPointF( -itemSize().width() / 2.0, 0 );
652 const double distLeft = otherRect.distance( QgsPointXY( leftPoint ) );
653
654 const QPointF rightPoint = pos() + QPointF( itemSize().width() / 2.0, 0 );
655 const double distRight = otherRect.distance( QgsPointXY( rightPoint ) );
656
657 const QPointF topPoint = pos() + QPointF( 0, -itemSize().height() / 2.0 );
658 const double distTop = otherRect.distance( QgsPointXY( topPoint ) );
659
660 const QPointF bottomPoint = pos() + QPointF( 0, itemSize().height() / 2.0 );
661 const double distBottom = otherRect.distance( QgsPointXY( bottomPoint ) );
662
663 if ( distLeft <= distRight && distLeft <= distTop && distLeft <= distBottom )
664 {
665 edge = Qt::LeftEdge;
666 return leftPoint;
667 }
668 else if ( distRight <= distTop && distRight <= distBottom )
669 {
670 edge = Qt::RightEdge;
671 return rightPoint;
672 }
673 else if ( distBottom <= distTop )
674 {
675 edge = Qt::BottomEdge;
676 return bottomPoint;
677 }
678 else
679 {
680 edge = Qt::TopEdge;
681 return topPoint;
682 }
683}
684
685QPointF QgsModelComponentGraphicItem::calculateAutomaticLinkPoint( const QPointF &point, Qt::Edge &edge ) const
686{
687 // find closest edge to other point
688 const QgsPointXY otherPt( point );
689 const QPointF leftPoint = pos() + QPointF( -itemSize().width() / 2.0, 0 );
690 const double distLeft = otherPt.distance( QgsPointXY( leftPoint ) );
691
692 const QPointF rightPoint = pos() + QPointF( itemSize().width() / 2.0, 0 );
693 const double distRight = otherPt.distance( QgsPointXY( rightPoint ) );
694
695 const QPointF topPoint = pos() + QPointF( 0, -itemSize().height() / 2.0 );
696 const double distTop = otherPt.distance( QgsPointXY( topPoint ) );
697
698 const QPointF bottomPoint = pos() + QPointF( 0, itemSize().height() / 2.0 );
699 const double distBottom = otherPt.distance( QgsPointXY( bottomPoint ) );
700
701 if ( distLeft <= distRight && distLeft <= distTop && distLeft <= distBottom )
702 {
703 edge = Qt::LeftEdge;
704 return leftPoint;
705 }
706 else if ( distRight <= distTop && distRight <= distBottom )
707 {
708 edge = Qt::RightEdge;
709 return rightPoint;
710 }
711 else if ( distBottom <= distTop )
712 {
713 edge = Qt::BottomEdge;
714 return bottomPoint;
715 }
716 else
717 {
718 edge = Qt::TopEdge;
719 return topPoint;
720 }
721}
722
723QgsModelParameterGraphicItem::QgsModelParameterGraphicItem( QgsProcessingModelParameter *parameter, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
724 : QgsModelComponentGraphicItem( parameter, model, parent )
725{
726 QSvgRenderer svg( QgsApplication::iconPath( QStringLiteral( "mIconModelInput.svg" ) ) );
727 QPainter painter( &mPicture );
728 svg.render( &painter );
729 painter.end();
730
731 if ( const QgsProcessingParameterDefinition *paramDef = model->parameterDefinition( parameter->parameterName() ) )
732 setLabel( paramDef->description() );
733 else
734 setLabel( QObject::tr( "Error (%1)" ).arg( parameter->parameterName() ) );
735}
736
737void QgsModelParameterGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
738{
739 QMenu *popupmenu = new QMenu( event->widget() );
740 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
741 connect( removeAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::deleteComponent );
742 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
743 connect( editAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComponent );
744 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
745 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
746
747 popupmenu->exec( event->screenPos() );
748}
749
750QColor QgsModelParameterGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
751{
752 QColor c( 238, 242, 131 );
753 switch ( state )
754 {
755 case Selected:
756 c = c.darker( 110 );
757 break;
758 case Hover:
759 c = c.darker( 105 );
760 break;
761
762 case Normal:
763 break;
764 }
765 return c;
766}
767
768QColor QgsModelParameterGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
769{
770 switch ( state )
771 {
772 case Selected:
773 return QColor( 116, 113, 68 );
774 case Hover:
775 case Normal:
776 return QColor( 234, 226, 118 );
777 }
778 return QColor();
779}
780
781QColor QgsModelParameterGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
782{
783 return Qt::black;
784}
785
786QPicture QgsModelParameterGraphicItem::iconPicture() const
787{
788 return mPicture;
789}
790
791void QgsModelParameterGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
792{
793 if ( QgsProcessingModelParameter *param = dynamic_cast< QgsProcessingModelParameter * >( component() ) )
794 {
795 model()->parameterComponent( param->parameterName() ).setPosition( pos );
796 model()->parameterComponent( param->parameterName() ).setSize( size );
797 }
798}
799
800bool QgsModelParameterGraphicItem::canDeleteComponent()
801{
802 if ( const QgsProcessingModelParameter *param = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
803 {
804 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
805 {
806 return false;
807 }
808 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
809 {
810 return false;
811 }
812 else
813 {
814 return true;
815 }
816 }
817 return false;
818}
819
820void QgsModelParameterGraphicItem::deleteComponent()
821{
822 if ( const QgsProcessingModelParameter *param = dynamic_cast< const QgsProcessingModelParameter * >( component() ) )
823 {
824 if ( model()->childAlgorithmsDependOnParameter( param->parameterName() ) )
825 {
826 QMessageBox::warning( nullptr, QObject::tr( "Could not remove input" ),
827 QObject::tr( "Algorithms depend on the selected input.\n"
828 "Remove them before trying to remove it." ) );
829 }
830 else if ( model()->otherParametersDependOnParameter( param->parameterName() ) )
831 {
832 QMessageBox::warning( nullptr, QObject::tr( "Could not remove input" ),
833 QObject::tr( "Other inputs depend on the selected input.\n"
834 "Remove them before trying to remove it." ) );
835 }
836 else
837 {
838 emit aboutToChange( tr( "Delete Input %1" ).arg( param->description() ) );
839 model()->removeModelParameter( param->parameterName() );
840 emit changed();
841 emit requestModelRepaint();
842 }
843 }
844}
845
846
847
848QgsModelChildAlgorithmGraphicItem::QgsModelChildAlgorithmGraphicItem( QgsProcessingModelChildAlgorithm *child, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
849 : QgsModelComponentGraphicItem( child, model, parent )
850{
851 if ( child->algorithm() && !child->algorithm()->svgIconPath().isEmpty() )
852 {
853 QSvgRenderer svg( child->algorithm()->svgIconPath() );
854 const QSizeF size = svg.defaultSize();
855 QPainter painter( &mPicture );
856 painter.scale( 16.0 / size.width(), 16.0 / size.width() );
857 svg.render( &painter );
858 painter.end();
859 }
860 else if ( child->algorithm() )
861 {
862 mPixmap = child->algorithm()->icon().pixmap( 15, 15 );
863 }
864
865 setLabel( child->description() );
866
867 QStringList issues;
868 mIsValid = model->validateChildAlgorithm( child->childId(), issues );
869}
870
871void QgsModelChildAlgorithmGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
872{
873 QMenu *popupmenu = new QMenu( event->widget() );
874
875 if ( isSelected() )
876 {
877 QAction *runSelectedStepsAction = popupmenu->addAction( QObject::tr( "Run Selected Steps…" ) );
878 runSelectedStepsAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionRunSelected.svg" ) ) );
879 connect( runSelectedStepsAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runSelected );
880 }
881
882 QAction *runFromHereAction = popupmenu->addAction( QObject::tr( "Run from Here…" ) );
883 runFromHereAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionStart.svg" ) ) );
884 connect( runFromHereAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::runFromHere );
885
886 popupmenu->addSeparator();
887
888 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
889 connect( removeAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deleteComponent );
890 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
891 connect( editAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::editComponent );
892 QAction *editCommentAction = popupmenu->addAction( component()->comment()->description().isEmpty() ? QObject::tr( "Add Comment…" ) : QObject::tr( "Edit Comment…" ) );
893 connect( editCommentAction, &QAction::triggered, this, &QgsModelParameterGraphicItem::editComment );
894 popupmenu->addSeparator();
895
896 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
897 {
898 if ( !child->isActive() )
899 {
900 QAction *activateAction = popupmenu->addAction( QObject::tr( "Activate" ) );
901 connect( activateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::activateAlgorithm );
902 }
903 else
904 {
905 QAction *deactivateAction = popupmenu->addAction( QObject::tr( "Deactivate" ) );
906 connect( deactivateAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm );
907 }
908
909 // only show the "View Output Layers" action for algorithms which create layers
910 if ( const QgsProcessingAlgorithm *algorithm = child->algorithm() )
911 {
912 const QList< const QgsProcessingParameterDefinition * > outputParams = algorithm->destinationParameterDefinitions();
913 if ( !outputParams.isEmpty() )
914 {
915 popupmenu->addSeparator();
916 QAction *viewOutputLayersAction = popupmenu->addAction( QObject::tr( "View Output Layers" ) );
917 viewOutputLayersAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionShowSelectedLayers.svg" ) ) );
918 connect( viewOutputLayersAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showPreviousResults );
919 // enable this action only when the child succeeded
920 switch ( mResults.executionStatus() )
921 {
924 viewOutputLayersAction->setEnabled( false );
925 break;
926
928 break;
929 }
930 }
931 }
932
933 QAction *viewLogAction = popupmenu->addAction( QObject::tr( "View Log…" ) );
934 connect( viewLogAction, &QAction::triggered, this, &QgsModelChildAlgorithmGraphicItem::showLog );
935 // enable this action even when the child failed
936 switch ( mResults.executionStatus() )
937 {
939 viewLogAction->setEnabled( false );
940 break;
941
944 break;
945 }
946 }
947
948 popupmenu->exec( event->screenPos() );
949}
950
951QColor QgsModelChildAlgorithmGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
952{
953 QColor c;
954
955 if ( mIsValid )
956 c = QColor( 255, 255, 255 );
957 else
958 c = QColor( 208, 0, 0 );
959
960 switch ( state )
961 {
962 case Selected:
963 c = c.darker( 110 );
964 break;
965 case Hover:
966 c = c.darker( 105 );
967 break;
968
969 case Normal:
970 break;
971 }
972 return c;
973}
974
975QColor QgsModelChildAlgorithmGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
976{
977 switch ( state )
978 {
979 case Selected:
980 return mIsValid ? QColor( 50, 50, 50 ) : QColor( 80, 0, 0 );
981 case Hover:
982 case Normal:
983 return mIsValid ? Qt::gray : QColor( 134, 0, 0 );
984 }
985 return QColor();
986}
987
988QColor QgsModelChildAlgorithmGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
989{
990 return mIsValid ? ( qgis::down_cast< const QgsProcessingModelChildAlgorithm * >( component() )->isActive() ? Qt::black : Qt::gray ) : QColor( 255, 255, 255 );
991}
992
993QPixmap QgsModelChildAlgorithmGraphicItem::iconPixmap() const
994{
995 return mPixmap;
996}
997
998QPicture QgsModelChildAlgorithmGraphicItem::iconPicture() const
999{
1000 return mPicture;
1001}
1002
1003int QgsModelChildAlgorithmGraphicItem::linkPointCount( Qt::Edge edge ) const
1004{
1005 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1006 {
1007 if ( !child->algorithm() )
1008 return 0;
1009
1010 switch ( edge )
1011 {
1012 case Qt::BottomEdge:
1013 return child->algorithm()->outputDefinitions().size();
1014 case Qt::TopEdge:
1015 {
1016 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1017 params.erase( std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition * param )
1018 {
1019 return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination();
1020 } ), params.end() );
1021 return params.size();
1022 }
1023
1024 case Qt::LeftEdge:
1025 case Qt::RightEdge:
1026 break;
1027 }
1028 }
1029 return 0;
1030}
1031
1032QString QgsModelChildAlgorithmGraphicItem::linkPointText( Qt::Edge edge, int index ) const
1033{
1034 if ( index < 0 )
1035 return QString();
1036
1037 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1038 {
1039 if ( !child->algorithm() )
1040 return QString();
1041
1042 const QVariantMap inputs = mResults.inputs();
1043 const QVariantMap outputs = mResults.outputs();
1044 switch ( edge )
1045 {
1046 case Qt::BottomEdge:
1047 {
1048 if ( index >= child->algorithm()->outputDefinitions().length() )
1049 {
1050 // something goes wrong and tried to link to an not existing output
1052 tr( "Cannot link output for child: %1" ).arg( child->algorithm()->name() ),
1053 "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1054 return QString();
1055 }
1056
1057 const QgsProcessingOutputDefinition *output = child->algorithm()->outputDefinitions().at( index );
1058 QString title = output->description();
1059 if ( outputs.contains( output->name() ) )
1060 {
1061 title += QStringLiteral( ": %1" ).arg( outputs.value( output->name() ).toString() );
1062 }
1063 return truncatedTextForItem( title );
1064 }
1065
1066 case Qt::TopEdge:
1067 {
1068 QgsProcessingParameterDefinitions params = child->algorithm()->parameterDefinitions();
1069 params.erase( std::remove_if( params.begin(), params.end(), []( const QgsProcessingParameterDefinition * param )
1070 {
1071 return param->flags() & Qgis::ProcessingParameterFlag::Hidden || param->isDestination();
1072 } ), params.end() );
1073
1074 if ( index >= params.length() )
1075 {
1076 // something goes wrong and tried to link to an not existing source parameter
1078 tr( "Cannot link source for child: %1" ).arg( child->algorithm()->name() ),
1079 "QgsModelChildAlgorithmGraphicItem", Qgis::MessageLevel::Warning, true );
1080 return QString();
1081 }
1082
1083 QString title = params.at( index )->description();
1084 if ( !inputs.value( params.at( index )->name() ).toString().isEmpty() )
1085 title += QStringLiteral( ": %1" ).arg( inputs.value( params.at( index )->name() ).toString() );
1086 return truncatedTextForItem( title );
1087 }
1088
1089 case Qt::LeftEdge:
1090 case Qt::RightEdge:
1091 break;
1092 }
1093 }
1094 return QString();
1095}
1096
1097void QgsModelChildAlgorithmGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1098{
1099 if ( QgsProcessingModelChildAlgorithm *child = dynamic_cast< QgsProcessingModelChildAlgorithm * >( component() ) )
1100 {
1101 model()->childAlgorithm( child->childId() ).setPosition( pos );
1102 model()->childAlgorithm( child->childId() ).setSize( size );
1103 }
1104}
1105
1106bool QgsModelChildAlgorithmGraphicItem::canDeleteComponent()
1107{
1108 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1109 {
1110 return model()->dependentChildAlgorithms( child->childId() ).empty();
1111 }
1112 return false;
1113}
1114
1115void QgsModelChildAlgorithmGraphicItem::setResults( const QgsProcessingModelChildAlgorithmResult &results )
1116{
1117 if ( mResults == results )
1118 return;
1119
1120 mResults = results;
1121 update();
1122 emit updateArrowPaths();
1123}
1124
1125void QgsModelChildAlgorithmGraphicItem::deleteComponent()
1126{
1127 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1128 {
1129 emit aboutToChange( tr( "Remove %1" ).arg( child->algorithm() ? child->algorithm()->displayName() : tr( "Algorithm" ) ) );
1130 if ( !model()->removeChildAlgorithm( child->childId() ) )
1131 {
1132 QMessageBox::warning( nullptr, QObject::tr( "Could not remove algorithm" ),
1133 QObject::tr( "Other algorithms depend on the selected one.\n"
1134 "Remove them before trying to remove it." ) );
1135 }
1136 else
1137 {
1138 emit changed();
1139 emit requestModelRepaint();
1140 }
1141 }
1142}
1143
1144void QgsModelChildAlgorithmGraphicItem::deactivateAlgorithm()
1145{
1146 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1147 {
1148 model()->deactivateChildAlgorithm( child->childId() );
1149 emit requestModelRepaint();
1150 }
1151}
1152
1153void QgsModelChildAlgorithmGraphicItem::activateAlgorithm()
1154{
1155 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( component() ) )
1156 {
1157 if ( model()->activateChildAlgorithm( child->childId() ) )
1158 {
1159 emit requestModelRepaint();
1160 }
1161 else
1162 {
1163 QMessageBox::warning( nullptr, QObject::tr( "Could not activate algorithm" ),
1164 QObject::tr( "The selected algorithm depends on other currently non-active algorithms.\n"
1165 "Activate them them before trying to activate it.." ) );
1166 }
1167 }
1168}
1169
1170
1171QgsModelOutputGraphicItem::QgsModelOutputGraphicItem( QgsProcessingModelOutput *output, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1172 : QgsModelComponentGraphicItem( output, model, parent )
1173{
1174 QSvgRenderer svg( QgsApplication::iconPath( QStringLiteral( "mIconModelOutput.svg" ) ) );
1175 QPainter painter( &mPicture );
1176 svg.render( &painter );
1177 painter.end();
1178 setLabel( output->description() );
1179}
1180
1181QColor QgsModelOutputGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1182{
1183 QColor c( 172, 196, 114 );
1184 switch ( state )
1185 {
1186 case Selected:
1187 c = c.darker( 110 );
1188 break;
1189 case Hover:
1190 c = c.darker( 105 );
1191 break;
1192
1193 case Normal:
1194 break;
1195 }
1196 return c;
1197}
1198
1199QColor QgsModelOutputGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1200{
1201 switch ( state )
1202 {
1203 case Selected:
1204 return QColor( 42, 65, 42 );
1205 case Hover:
1206 case Normal:
1207 return QColor( 90, 140, 90 );
1208 }
1209 return QColor();
1210}
1211
1212QColor QgsModelOutputGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1213{
1214 return Qt::black;
1215}
1216
1217QPicture QgsModelOutputGraphicItem::iconPicture() const
1218{
1219 return mPicture;
1220}
1221
1222void QgsModelOutputGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1223{
1224 if ( QgsProcessingModelOutput *output = dynamic_cast< QgsProcessingModelOutput * >( component() ) )
1225 {
1226 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setPosition( pos );
1227 model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).setSize( size );
1228 }
1229}
1230
1231bool QgsModelOutputGraphicItem::canDeleteComponent()
1232{
1233 if ( dynamic_cast< const QgsProcessingModelOutput * >( component() ) )
1234 {
1235 return true;
1236 }
1237 return false;
1238}
1239
1240void QgsModelOutputGraphicItem::deleteComponent()
1241{
1242 if ( const QgsProcessingModelOutput *output = dynamic_cast< const QgsProcessingModelOutput * >( component() ) )
1243 {
1244 emit aboutToChange( tr( "Delete Output %1" ).arg( output->description() ) );
1245 model()->childAlgorithm( output->childId() ).removeModelOutput( output->name() );
1246 model()->updateDestinationParameters();
1247 emit changed();
1248 emit requestModelRepaint();
1249 }
1250}
1251
1252
1253//
1254// QgsModelGroupBoxGraphicItem
1255//
1256
1257QgsModelGroupBoxGraphicItem::QgsModelGroupBoxGraphicItem( QgsProcessingModelGroupBox *box, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1258 : QgsModelComponentGraphicItem( box, model, parent )
1259{
1260 setZValue( QgsModelGraphicsScene::ZValues::GroupBox );
1261 setLabel( box->description() );
1262
1263 QFont f = font();
1264 f.setBold( true );
1265 f.setPixelSize( 14 );
1266 setFont( f );
1267}
1268
1269void QgsModelGroupBoxGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1270{
1271 QMenu *popupmenu = new QMenu( event->widget() );
1272 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1273 connect( removeAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::deleteComponent );
1274 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1275 connect( editAction, &QAction::triggered, this, &QgsModelGroupBoxGraphicItem::editComponent );
1276 popupmenu->exec( event->screenPos() );
1277}
1278
1279QgsModelGroupBoxGraphicItem::~QgsModelGroupBoxGraphicItem() = default;
1280
1281QColor QgsModelGroupBoxGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1282{
1283 QColor c( 230, 230, 230 );
1284 switch ( state )
1285 {
1286 case Selected:
1287 c = c.darker( 110 );
1288 break;
1289 case Hover:
1290 c = c.darker( 105 );
1291 break;
1292
1293 case Normal:
1294 break;
1295 }
1296 return c;
1297}
1298
1299QColor QgsModelGroupBoxGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1300{
1301 switch ( state )
1302 {
1303 case Selected:
1304 return QColor( 50, 50, 50 );
1305 case Hover:
1306 case Normal:
1307 return QColor( 150, 150, 150 );
1308 }
1309 return QColor();
1310}
1311
1312QColor QgsModelGroupBoxGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1313{
1314 return QColor( 100, 100, 100 );
1315}
1316
1317Qt::PenStyle QgsModelGroupBoxGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1318{
1319 return Qt::DotLine;
1320}
1321
1322Qt::Alignment QgsModelGroupBoxGraphicItem::titleAlignment() const
1323{
1324 return Qt::AlignHCenter;
1325}
1326
1327void QgsModelGroupBoxGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1328{
1329 if ( QgsProcessingModelGroupBox *box = dynamic_cast< QgsProcessingModelGroupBox * >( component() ) )
1330 {
1331 box->setPosition( pos );
1332 box->setSize( size );
1333 model()->addGroupBox( *box );
1334 }
1335}
1336
1337bool QgsModelGroupBoxGraphicItem::canDeleteComponent()
1338{
1339 if ( dynamic_cast< QgsProcessingModelGroupBox * >( component() ) )
1340 {
1341 return true;
1342 }
1343 return false;
1344}
1345
1346void QgsModelGroupBoxGraphicItem::deleteComponent()
1347{
1348 if ( const QgsProcessingModelGroupBox *box = dynamic_cast< const QgsProcessingModelGroupBox * >( component() ) )
1349 {
1350 emit aboutToChange( tr( "Delete Group Box" ) );
1351 model()->removeGroupBox( box->uuid() );
1352 emit changed();
1353 emit requestModelRepaint();
1354 }
1355}
1356
1357void QgsModelGroupBoxGraphicItem::editComponent()
1358{
1359 if ( const QgsProcessingModelGroupBox *box = dynamic_cast< const QgsProcessingModelGroupBox * >( component() ) )
1360 {
1361 QgsModelGroupBoxDefinitionDialog dlg( *box, this->scene()->views().at( 0 ) );
1362
1363 if ( dlg.exec() )
1364 {
1365 emit aboutToChange( tr( "Edit Group Box" ) );
1366 model()->addGroupBox( dlg.groupBox() );
1367 emit changed();
1368 emit requestModelRepaint();
1369 }
1370 }
1371}
1372
1373//
1374// QgsModelCommentGraphicItem
1375//
1376
1377QgsModelCommentGraphicItem::QgsModelCommentGraphicItem( QgsProcessingModelComment *comment, QgsModelComponentGraphicItem *parentItem, QgsProcessingModelAlgorithm *model, QGraphicsItem *parent )
1378 : QgsModelComponentGraphicItem( comment, model, parent )
1379 , mParentComponent( parentItem->component()->clone() )
1380 , mParentItem( parentItem )
1381{
1382 setLabel( comment->description() );
1383
1384 QFont f = font();
1385 f.setPixelSize( 9 );
1386 setFont( f );
1387}
1388
1389void QgsModelCommentGraphicItem::contextMenuEvent( QGraphicsSceneContextMenuEvent *event )
1390{
1391 QMenu *popupmenu = new QMenu( event->widget() );
1392 QAction *removeAction = popupmenu->addAction( QObject::tr( "Remove" ) );
1393 connect( removeAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::deleteComponent );
1394 QAction *editAction = popupmenu->addAction( QObject::tr( "Edit…" ) );
1395 connect( editAction, &QAction::triggered, this, &QgsModelCommentGraphicItem::editComponent );
1396 popupmenu->exec( event->screenPos() );
1397}
1398
1399QgsModelCommentGraphicItem::~QgsModelCommentGraphicItem() = default;
1400
1401QColor QgsModelCommentGraphicItem::fillColor( QgsModelComponentGraphicItem::State state ) const
1402{
1403 QColor c( 230, 230, 230 );
1404 switch ( state )
1405 {
1406 case Selected:
1407 c = c.darker( 110 );
1408 break;
1409 case Hover:
1410 c = c.darker( 105 );
1411 break;
1412
1413 case Normal:
1414 break;
1415 }
1416 return c;
1417}
1418
1419QColor QgsModelCommentGraphicItem::strokeColor( QgsModelComponentGraphicItem::State state ) const
1420{
1421 switch ( state )
1422 {
1423 case Selected:
1424 return QColor( 50, 50, 50 );
1425 case Hover:
1426 case Normal:
1427 return QColor( 150, 150, 150 );
1428 }
1429 return QColor();
1430}
1431
1432QColor QgsModelCommentGraphicItem::textColor( QgsModelComponentGraphicItem::State ) const
1433{
1434 return QColor( 100, 100, 100 );
1435}
1436
1437Qt::PenStyle QgsModelCommentGraphicItem::strokeStyle( QgsModelComponentGraphicItem::State ) const
1438{
1439 return Qt::DotLine;
1440}
1441
1442void QgsModelCommentGraphicItem::updateStoredComponentPosition( const QPointF &pos, const QSizeF &size )
1443{
1444 if ( QgsProcessingModelComment *comment = modelComponent() )
1445 {
1446 comment->setPosition( pos );
1447 comment->setSize( size );
1448 }
1449}
1450
1451bool QgsModelCommentGraphicItem::canDeleteComponent()
1452{
1453 if ( modelComponent() )
1454 {
1455 return true;
1456 }
1457 return false;
1458}
1459
1460void QgsModelCommentGraphicItem::deleteComponent()
1461{
1462 if ( QgsProcessingModelComment *comment = modelComponent() )
1463 {
1464 emit aboutToChange( tr( "Delete Comment" ) );
1465 comment->setDescription( QString() );
1466 emit changed();
1467 emit requestModelRepaint();
1468 }
1469}
1470
1471void QgsModelCommentGraphicItem::editComponent()
1472{
1473 if ( mParentItem )
1474 {
1475 mParentItem->editComment();
1476 }
1477}
1478
1479QgsProcessingModelComment *QgsModelCommentGraphicItem::modelComponent()
1480{
1481 if ( const QgsProcessingModelChildAlgorithm *child = dynamic_cast< const QgsProcessingModelChildAlgorithm * >( mParentComponent.get() ) )
1482 {
1483 return model()->childAlgorithm( child->childId() ).comment();
1484 }
1485 else if ( const QgsProcessingModelParameter *param = dynamic_cast< const QgsProcessingModelParameter * >( mParentComponent.get() ) )
1486 {
1487 return model()->parameterComponent( param->parameterName() ).comment();
1488 }
1489 else if ( const QgsProcessingModelOutput *output = dynamic_cast< const QgsProcessingModelOutput * >( mParentComponent.get() ) )
1490 {
1491 return model()->childAlgorithm( output->childId() ).modelOutput( output->name() ).comment();
1492 }
1493 return nullptr;
1494}
1495
1496QgsModelComponentGraphicItem *QgsModelCommentGraphicItem::parentComponentItem() const
1497{
1498 return mParentItem;
1499}
1500
1501
@ Success
Child was successfully executed.
@ Failed
Child encountered an error while executing.
@ Warning
Warning message.
Definition qgis.h:156
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)
Adds a message to the log instance (and creates it if necessary).
A widget which allow users to specify the properties of a model group box.
A QgsModelViewMouseEvent is the result of a user interaction with the mouse on a QgsModelGraphicsView...
QPointF modelPoint() const
Returns the event point location in model coordinates.
A class to represent a 2D point.
Definition qgspointxy.h:60
Abstract base class for processing algorithms.
QgsProcessingParameterDefinitions destinationParameterDefinitions() const
Returns a list of destination parameters definitions utilized by the algorithm.
Encapsulates the results of running a child algorithm within a model.
Base class for the definition of processing outputs.
QString name() const
Returns the name of the output.
QString description() const
Returns the description for the output.
Base class for the definition of processing parameters.
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
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.