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