diff --git a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in index 14f0cfd10b49..d884cd458f40 100644 --- a/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodelgraphicsscene.sip.in @@ -81,6 +81,29 @@ Returns the current combination of flags set for the scene. void createItems( QgsProcessingModelAlgorithm *model, QgsProcessingContext &context ); %Docstring Populates the scene by creating items representing the specified ``model``. +%End + + QList selectedComponentItems(); +%Docstring +Returns list of selected component items. +%End + + QgsModelComponentGraphicItem *componentItemAt( QPointF position ) const; +%Docstring +Returns the topmost component item at a specified ``position``. +%End + + void deselectAll(); +%Docstring +Clears any selected items in the scene. + +Call this method rather than QGraphicsScene.clearSelection, as the latter does +not correctly emit signals to allow the scene's model to update. +%End + + void setSelectedItem( QgsModelComponentGraphicItem *item ); +%Docstring +Clears any selected items and sets ``item`` as the current selection. %End signals: @@ -101,6 +124,12 @@ optional ``id`` can be used to group the associated undo commands. void componentChanged(); %Docstring Emitted whenever a component of the model is changed. +%End + + void selectedItemChanged( QgsModelComponentGraphicItem *selected ); +%Docstring +Emitted whenever the selected item changes. +If ``None``, no item is selected. %End protected: diff --git a/python/gui/auto_generated/processing/models/qgsmodelgraphicsview.sip.in b/python/gui/auto_generated/processing/models/qgsmodelgraphicsview.sip.in index 28eef7b40fa2..09ffad257829 100644 --- a/python/gui/auto_generated/processing/models/qgsmodelgraphicsview.sip.in +++ b/python/gui/auto_generated/processing/models/qgsmodelgraphicsview.sip.in @@ -54,30 +54,15 @@ Constructor for QgsModelGraphicsView, with the specified ``parent`` widget. virtual void keyReleaseEvent( QKeyEvent *event ); - QgsModelViewTool *tool(); + QgsModelGraphicsScene *modelScene() const; %Docstring -Returns the currently active tool for the view. +Returns the scene associated with the tool. -.. seealso:: :py:func:`setTool` +.. seealso:: :py:func:`view` %End - void setTool( QgsModelViewTool *tool ); -%Docstring -Sets the ``tool`` currently being used in the view. -.. seealso:: :py:func:`unsetTool` -.. seealso:: :py:func:`tool` -%End - - void unsetTool( QgsModelViewTool *tool ); -%Docstring -Unsets the current view tool, if it matches the specified ``tool``. - -This is called from destructor of view tools to make sure -that the tool won't be used any more. -You don't have to call it manually, QgsModelViewTool takes care of it. -%End signals: @@ -91,12 +76,6 @@ Emitted when an algorithm is dropped onto the view. Emitted when an input parameter is dropped onto the view. %End - void toolSet( QgsModelViewTool *tool ); -%Docstring -Emitted when the current ``tool`` is changed. - -.. seealso:: :py:func:`setTool` -%End void itemFocused( QgsModelComponentGraphicItem *item ); %Docstring diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.cpp b/src/gui/processing/models/qgsmodelgraphicsscene.cpp index c078c019b798..c09723611f38 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.cpp +++ b/src/gui/processing/models/qgsmodelgraphicsscene.cpp @@ -186,6 +186,63 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs } } +QList QgsModelGraphicsScene::selectedComponentItems() +{ + QList componentItemList; + + const QList graphicsItemList = selectedItems(); + for ( QGraphicsItem *item : graphicsItemList ) + { + if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast( item ) ) + { + componentItemList.push_back( componentItem ); + } + } + + return componentItemList; +} + +QgsModelComponentGraphicItem *QgsModelGraphicsScene::componentItemAt( QPointF position ) const +{ + //get a list of items which intersect the specified position, in descending z order + const QList itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder ); + + for ( QGraphicsItem *graphicsItem : itemList ) + { + if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast( graphicsItem ) ) + { + return componentItem; + } + } + return nullptr; +} + +void QgsModelGraphicsScene::deselectAll() +{ + //we can't use QGraphicsScene::clearSelection, as that emits no signals + //and we don't know which items are being deselected + //instead, do the clear selection manually... + const QList selectedItemList = selectedItems(); + for ( QGraphicsItem *item : selectedItemList ) + { + if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast( item ) ) + { + componentItem->setSelected( false ); + } + } + emit selectedItemChanged( nullptr ); +} + +void QgsModelGraphicsScene::setSelectedItem( QgsModelComponentGraphicItem *item ) +{ + whileBlocking( this )->deselectAll(); + if ( item ) + { + item->setSelected( true ); + } + emit selectedItemChanged( item ); +} + QList QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model, const QVariant &value, const QString &childId, QgsProcessingContext &context ) const { QList res; diff --git a/src/gui/processing/models/qgsmodelgraphicsscene.h b/src/gui/processing/models/qgsmodelgraphicsscene.h index b33735c82fbb..8db645682a95 100644 --- a/src/gui/processing/models/qgsmodelgraphicsscene.h +++ b/src/gui/processing/models/qgsmodelgraphicsscene.h @@ -93,6 +93,29 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene */ void createItems( QgsProcessingModelAlgorithm *model, QgsProcessingContext &context ); + /** + * Returns list of selected component items. + */ + QList selectedComponentItems(); + + /** + * Returns the topmost component item at a specified \a position. + */ + QgsModelComponentGraphicItem *componentItemAt( QPointF position ) const; + + /** + * Clears any selected items in the scene. + * + * Call this method rather than QGraphicsScene::clearSelection, as the latter does + * not correctly emit signals to allow the scene's model to update. + */ + void deselectAll(); + + /** + * Clears any selected items and sets \a item as the current selection. + */ + void setSelectedItem( QgsModelComponentGraphicItem *item ); + signals: /** @@ -113,6 +136,12 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene */ void componentChanged(); + /** + * Emitted whenever the selected item changes. + * If NULLPTR, no item is selected. + */ + void selectedItemChanged( QgsModelComponentGraphicItem *selected ); + protected: /** diff --git a/src/gui/processing/models/qgsmodelgraphicsview.cpp b/src/gui/processing/models/qgsmodelgraphicsview.cpp index a60014692294..33561c1990db 100644 --- a/src/gui/processing/models/qgsmodelgraphicsview.cpp +++ b/src/gui/processing/models/qgsmodelgraphicsview.cpp @@ -21,6 +21,7 @@ #include "qgsmodelviewtooltemporarymousepan.h" #include "qgsmodelviewtooltemporarykeyzoom.h" #include "qgsmodelcomponentgraphicitem.h" +#include "qgsmodelgraphicsscene.h" #include #include @@ -98,10 +99,8 @@ void QgsModelGraphicsView::dragMoveEvent( QDragMoveEvent *event ) void QgsModelGraphicsView::wheelEvent( QWheelEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !scene() ) return; -#endif if ( mTool ) { @@ -168,10 +167,8 @@ void QgsModelGraphicsView::scaleSafe( double scale ) void QgsModelGraphicsView::mousePressEvent( QMouseEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif if ( mTool ) { @@ -197,10 +194,8 @@ void QgsModelGraphicsView::mousePressEvent( QMouseEvent *event ) void QgsModelGraphicsView::mouseReleaseEvent( QMouseEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif if ( mTool ) { @@ -215,10 +210,8 @@ void QgsModelGraphicsView::mouseReleaseEvent( QMouseEvent *event ) void QgsModelGraphicsView::mouseMoveEvent( QMouseEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif mMouseCurrentXY = event->pos(); @@ -260,10 +253,9 @@ void QgsModelGraphicsView::mouseMoveEvent( QMouseEvent *event ) void QgsModelGraphicsView::mouseDoubleClickEvent( QMouseEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif + if ( mTool ) { std::unique_ptr me( new QgsModelViewMouseEvent( this, event, mTool->flags() & QgsModelViewTool::FlagSnaps ) ); @@ -277,10 +269,8 @@ void QgsModelGraphicsView::mouseDoubleClickEvent( QMouseEvent *event ) void QgsModelGraphicsView::keyPressEvent( QKeyEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif if ( mTool ) { @@ -330,10 +320,8 @@ void QgsModelGraphicsView::keyPressEvent( QKeyEvent *event ) void QgsModelGraphicsView::keyReleaseEvent( QKeyEvent *event ) { -#if 0 - if ( !currentLayout() ) + if ( !modelScene() ) return; -#endif if ( mTool ) { @@ -344,6 +332,11 @@ void QgsModelGraphicsView::keyReleaseEvent( QKeyEvent *event ) QGraphicsView::keyReleaseEvent( event ); } +QgsModelGraphicsScene *QgsModelGraphicsView::modelScene() const +{ + return qobject_cast< QgsModelGraphicsScene * >( QgsModelGraphicsView::scene() ); +} + QgsModelViewTool *QgsModelGraphicsView::tool() { return mTool; diff --git a/src/gui/processing/models/qgsmodelgraphicsview.h b/src/gui/processing/models/qgsmodelgraphicsview.h index 69309810fb92..4caaf3eb320e 100644 --- a/src/gui/processing/models/qgsmodelgraphicsview.h +++ b/src/gui/processing/models/qgsmodelgraphicsview.h @@ -26,6 +26,7 @@ class QgsModelViewToolTemporaryKeyPan; class QgsModelViewToolTemporaryKeyZoom; class QgsModelViewToolTemporaryMousePan; class QgsModelComponentGraphicItem; +class QgsModelGraphicsScene; ///@cond NOT_STABLE @@ -58,18 +59,24 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView void keyPressEvent( QKeyEvent *event ) override; void keyReleaseEvent( QKeyEvent *event ) override; + /** + * Returns the scene associated with the tool. + * \see view() + */ + QgsModelGraphicsScene *modelScene() const; + /** * Returns the currently active tool for the view. * \see setTool() */ - QgsModelViewTool *tool(); + QgsModelViewTool *tool() SIP_SKIP; /** * Sets the \a tool currently being used in the view. * \see unsetTool() * \see tool() */ - void setTool( QgsModelViewTool *tool ); + void setTool( QgsModelViewTool *tool ) SIP_SKIP; /** * Unsets the current view tool, if it matches the specified \a tool. @@ -78,7 +85,7 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView * that the tool won't be used any more. * You don't have to call it manually, QgsModelViewTool takes care of it. */ - void unsetTool( QgsModelViewTool *tool ); + void unsetTool( QgsModelViewTool *tool ) SIP_SKIP; signals: @@ -96,7 +103,7 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView * Emitted when the current \a tool is changed. * \see setTool() */ - void toolSet( QgsModelViewTool *tool ); + void toolSet( QgsModelViewTool *tool ) SIP_SKIP; /** * Emitted when an \a item is "focused" in the view, i.e. it becomes the active diff --git a/src/gui/processing/models/qgsmodelviewrubberband.cpp b/src/gui/processing/models/qgsmodelviewrubberband.cpp index dae99229b8dc..d565a0e8a117 100644 --- a/src/gui/processing/models/qgsmodelviewrubberband.cpp +++ b/src/gui/processing/models/qgsmodelviewrubberband.cpp @@ -30,15 +30,6 @@ QgsModelGraphicsView *QgsModelViewRubberBand::view() const return mView; } -QgsProcessingAlgorithmModel *QgsModelViewRubberBand::model() const -{ -#if 0 - return mView->currentLayout(); -#endif - - return nullptr; -} - QRectF QgsModelViewRubberBand::updateRect( QPointF start, QPointF position, bool constrainSquare, bool fromCenter ) { double x = 0; diff --git a/src/gui/processing/models/qgsmodelviewrubberband.h b/src/gui/processing/models/qgsmodelviewrubberband.h index c78387e4bbd5..03465d852efd 100644 --- a/src/gui/processing/models/qgsmodelviewrubberband.h +++ b/src/gui/processing/models/qgsmodelviewrubberband.h @@ -28,7 +28,6 @@ class QgsModelGraphicsView; class QGraphicsRectItem; class QGraphicsEllipseItem; class QGraphicsPolygonItem; -class QgsProcessingAlgorithmModel; /** * \ingroup gui @@ -76,16 +75,9 @@ class GUI_EXPORT QgsModelViewRubberBand : public QObject /** * Returns the view associated with the rubber band. - * \see model() */ QgsModelGraphicsView *view() const; - /** - * Returns the model associated with the rubber band. - * \see view() - */ - QgsProcessingAlgorithmModel *model() const; - /** * Returns the brush used for drawing the rubber band. * \see setBrush() diff --git a/src/gui/processing/models/qgsmodelviewtool.cpp b/src/gui/processing/models/qgsmodelviewtool.cpp index 4e73fe115d9c..01879f365418 100644 --- a/src/gui/processing/models/qgsmodelviewtool.cpp +++ b/src/gui/processing/models/qgsmodelviewtool.cpp @@ -15,6 +15,7 @@ #include "qgsmodelviewtool.h" #include "qgsmodelgraphicsview.h" +#include "qgsmodelgraphicsscene.h" #include "qgsmodelviewmouseevent.h" QgsModelViewTool::QgsModelViewTool( QgsModelGraphicsView *view, const QString &name ) @@ -40,9 +41,9 @@ QgsModelGraphicsView *QgsModelViewTool::view() const return mView; } -QgsProcessingAlgorithmModel *QgsModelViewTool::model() const +QgsModelGraphicsScene *QgsModelViewTool::scene() const { - return nullptr;// mView->currentLayout(); + return qobject_cast< QgsModelGraphicsScene * >( mView->scene() ); } QgsModelViewTool::~QgsModelViewTool() diff --git a/src/gui/processing/models/qgsmodelviewtool.h b/src/gui/processing/models/qgsmodelviewtool.h index 0351996a73b5..da5620313834 100644 --- a/src/gui/processing/models/qgsmodelviewtool.h +++ b/src/gui/processing/models/qgsmodelviewtool.h @@ -27,8 +27,8 @@ class QWheelEvent; class QKeyEvent; class QgsModelGraphicsView; class QgsModelViewMouseEvent; -class QgsProcessingAlgorithmModel; class QgsModelComponentGraphicItem; +class QgsModelGraphicsScene; #define SIP_NO_FILE @@ -149,15 +149,15 @@ class GUI_EXPORT QgsModelViewTool : public QObject /** * Returns the view associated with the tool. - * \see model() + * \see scene() */ QgsModelGraphicsView *view() const; /** - * Returns the model associated with the tool. + * Returns the scene associated with the tool. * \see view() */ - QgsProcessingAlgorithmModel *model() const; + QgsModelGraphicsScene *scene() const; signals: diff --git a/src/gui/processing/models/qgsmodelviewtoolselect.cpp b/src/gui/processing/models/qgsmodelviewtoolselect.cpp index 3407bff5039e..7272c8c081eb 100644 --- a/src/gui/processing/models/qgsmodelviewtoolselect.cpp +++ b/src/gui/processing/models/qgsmodelviewtoolselect.cpp @@ -17,7 +17,8 @@ #include "qgsmodelviewmouseevent.h" #include "qgsmodelgraphicsview.h" #include "qgsprocessingmodelalgorithm.h" - +#include "qgsmodelgraphicsscene.h" +#include "qgsmodelcomponentgraphicitem.h" QgsModelViewToolSelect::QgsModelViewToolSelect( QgsModelGraphicsView *view ) : QgsModelViewTool( view, tr( "Select" ) ) @@ -73,14 +74,13 @@ void QgsModelViewToolSelect::modelPressEvent( QgsModelViewMouseEvent *event ) return; } -#if 0 - QgsLayoutItem *selectedItem = nullptr; - QgsLayoutItem *previousSelectedItem = nullptr; - QList selectedItems = layout()->selectedLayoutItems(); + QgsModelComponentGraphicItem *selectedItem = nullptr; + + QList selectedItems = scene()->selectedComponentItems(); //select topmost item at position of event - selectedItem = layout()->layoutItemAt( event->layoutPoint(), true ); + selectedItem = scene()->componentItemAt( event->modelPoint() ); if ( !selectedItem ) { @@ -97,7 +97,7 @@ void QgsModelViewToolSelect::modelPressEvent( QgsModelViewMouseEvent *event ) selectedItem->setSelected( false ); //Check if we have any remaining selected items, and if so, update the item panel - const QList selectedItems = layout()->selectedLayoutItems(); + const QList selectedItems = scene()->selectedComponentItems(); if ( !selectedItems.isEmpty() ) { emit itemFocused( selectedItems.at( 0 ) ); @@ -112,7 +112,7 @@ void QgsModelViewToolSelect::modelPressEvent( QgsModelViewMouseEvent *event ) if ( ( !selectedItem->isSelected() ) && //keep selection if an already selected item pressed !( event->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed { - layout()->setSelectedItem( selectedItem ); // clears existing selection + scene()->setSelectedItem( selectedItem ); // clears existing selection } else { @@ -121,7 +121,7 @@ void QgsModelViewToolSelect::modelPressEvent( QgsModelViewMouseEvent *event ) event->ignore(); emit itemFocused( selectedItem ); } -#endif + event->ignore(); } @@ -153,8 +153,6 @@ void QgsModelViewToolSelect::modelReleaseEvent( QgsModelViewMouseEvent *event ) return; } -#if 0 - mIsSelecting = false; bool wasClick = !isClickAndDrag( mMousePressStartPos, event->pos() ); @@ -175,7 +173,7 @@ void QgsModelViewToolSelect::modelReleaseEvent( QgsModelViewMouseEvent *event ) else { //not adding to or removing from selection, so clear current selection - whileBlocking( layout() )->deselectAll(); + whileBlocking( scene() )->deselectAll(); } //determine item selection mode, default to intersection @@ -189,36 +187,31 @@ void QgsModelViewToolSelect::modelReleaseEvent( QgsModelViewMouseEvent *event ) //find all items in rect QList itemList; if ( wasClick ) - itemList = layout()->items( rect.center(), selectionMode ); + itemList = scene()->items( rect.center(), selectionMode ); else - itemList = layout()->items( rect, selectionMode ); + itemList = scene()->items( rect, selectionMode ); for ( QGraphicsItem *item : qgis::as_const( itemList ) ) { - QgsLayoutItem *layoutItem = dynamic_cast( item ); - QgsLayoutItemPage *paperItem = dynamic_cast( item ); - if ( layoutItem && !paperItem ) + if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast( item ) ) { - if ( !layoutItem->isLocked() ) + if ( subtractingSelection ) + { + componentItem->setSelected( false ); + } + else { - if ( subtractingSelection ) - { - layoutItem->setSelected( false ); - } - else - { - layoutItem->setSelected( true ); - } - if ( wasClick ) - { - // found an item, and only a click - nothing more to do - break; - } + componentItem->setSelected( true ); + } + if ( wasClick ) + { + // found an item, and only a click - nothing more to do + break; } } } //update item panel - const QList selectedItemList = layout()->selectedLayoutItems(); + const QList selectedItemList = scene()->selectedComponentItems(); if ( !selectedItemList.isEmpty() ) { emit itemFocused( selectedItemList.at( 0 ) ); @@ -227,6 +220,7 @@ void QgsModelViewToolSelect::modelReleaseEvent( QgsModelViewMouseEvent *event ) { emit itemFocused( nullptr ); } +#if 0 mMouseHandles->selectionChanged(); #endif } @@ -281,7 +275,7 @@ QgsModelViewMouseHandles *QgsModelViewToolSelect::mouseHandles() return nullptr; //mMouseHandles; } -void QgsModelViewToolSelect::setModel( QgsProcessingAlgorithmModel *model ) +void QgsModelViewToolSelect::setScene( QgsModelGraphicsScene *model ) { #if 0 // existing handles are owned by previous layout diff --git a/src/gui/processing/models/qgsmodelviewtoolselect.h b/src/gui/processing/models/qgsmodelviewtoolselect.h index 1e04ab0330f8..f6fee6c1b7e5 100644 --- a/src/gui/processing/models/qgsmodelviewtoolselect.h +++ b/src/gui/processing/models/qgsmodelviewtoolselect.h @@ -58,8 +58,8 @@ class GUI_EXPORT QgsModelViewToolSelect : public QgsModelViewTool */ QgsModelViewMouseHandles *mouseHandles(); - //! Sets the a \a model. - void setModel( QgsProcessingAlgorithmModel *model ); + //! Sets the a \a scene. + void setScene( QgsModelGraphicsScene *scene ); private: