Multi item selection work

This commit is contained in:
Nyall Dawson 2020-03-10 10:44:12 +10:00
parent bb82c12791
commit b22e669bbd
12 changed files with 179 additions and 107 deletions

View File

@ -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<QgsModelComponentGraphicItem *> 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:

View File

@ -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

View File

@ -186,6 +186,63 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
}
}
QList<QgsModelComponentGraphicItem *> QgsModelGraphicsScene::selectedComponentItems()
{
QList<QgsModelComponentGraphicItem *> componentItemList;
const QList<QGraphicsItem *> graphicsItemList = selectedItems();
for ( QGraphicsItem *item : graphicsItemList )
{
if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( 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<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
for ( QGraphicsItem *graphicsItem : itemList )
{
if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( 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<QGraphicsItem *> selectedItemList = selectedItems();
for ( QGraphicsItem *item : selectedItemList )
{
if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( 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::LinkSource> QgsModelGraphicsScene::linkSourcesForParameterValue( QgsProcessingModelAlgorithm *model, const QVariant &value, const QString &childId, QgsProcessingContext &context ) const
{
QList<QgsModelGraphicsScene::LinkSource> res;

View File

@ -93,6 +93,29 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene
*/
void createItems( QgsProcessingModelAlgorithm *model, QgsProcessingContext &context );
/**
* Returns list of selected component items.
*/
QList<QgsModelComponentGraphicItem *> 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:
/**

View File

@ -21,6 +21,7 @@
#include "qgsmodelviewtooltemporarymousepan.h"
#include "qgsmodelviewtooltemporarykeyzoom.h"
#include "qgsmodelcomponentgraphicitem.h"
#include "qgsmodelgraphicsscene.h"
#include <QDragEnterEvent>
#include <QScrollBar>
@ -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<QgsModelViewMouseEvent> 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;

View File

@ -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

View File

@ -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;

View File

@ -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()

View File

@ -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()

View File

@ -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:

View File

@ -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<QgsLayoutItem *> selectedItems = layout()->selectedLayoutItems();
QgsModelComponentGraphicItem *selectedItem = nullptr;
QList<QgsModelComponentGraphicItem *> 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<QgsLayoutItem *> selectedItems = layout()->selectedLayoutItems();
const QList<QgsModelComponentGraphicItem *> 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<QGraphicsItem *> 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<QgsLayoutItem *>( item );
QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( item );
if ( layoutItem && !paperItem )
if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
{
if ( !layoutItem->isLocked() )
if ( subtractingSelection )
{
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( false );
}
else
{
componentItem->setSelected( true );
}
if ( wasClick )
{
// found an item, and only a click - nothing more to do
break;
}
}
}
//update item panel
const QList<QgsLayoutItem *> selectedItemList = layout()->selectedLayoutItems();
const QList<QgsModelComponentGraphicItem *> 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

View File

@ -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: