QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
qgsmodelviewtoolselect.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmodelviewtoolselect.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_qgsmodelviewtoolselect.cpp"
24#include "qgsmodelgraphicitem.h"
25
27 : QgsModelViewTool( view, tr( "Select" ) )
28{
29 setCursor( Qt::ArrowCursor );
30
31 mRubberBand.reset( new QgsModelViewRectangularRubberBand( view ) );
32 mRubberBand->setBrush( QBrush( QColor( 224, 178, 76, 63 ) ) );
33 mRubberBand->setPen( QPen( QBrush( QColor( 254, 58, 29, 100 ) ), 0, Qt::DotLine ) );
34}
35
37{
38 if ( mMouseHandles )
39 {
40 // want to force them to be removed from the scene
41 if ( mMouseHandles->scene() )
42 mMouseHandles->scene()->removeItem( mMouseHandles );
43 delete mMouseHandles;
44 }
45}
46
48{
49 if ( mMouseHandles->shouldBlockEvent( event ) )
50 {
51 //swallow clicks while dragging/resizing items
52 return;
53 }
54
55 if ( mMouseHandles->isVisible() )
56 {
57 //selection handles are being shown, get mouse action for current cursor position
58 QgsGraphicsViewMouseHandles::MouseAction mouseAction = mMouseHandles->mouseActionForScenePos( event->modelPoint() );
59
60 if ( mouseAction != QgsGraphicsViewMouseHandles::MoveItem
61 && mouseAction != QgsGraphicsViewMouseHandles::NoAction
62 && mouseAction != QgsGraphicsViewMouseHandles::SelectItem )
63 {
64 //mouse is over a resize handle, so propagate event onward
65 event->ignore();
66 return;
67 }
68 }
69
70 if ( event->button() != Qt::LeftButton )
71 {
72 event->ignore();
73 return;
74 }
75
76
77 QgsModelComponentGraphicItem *selectedItem = nullptr;
78
79 //select topmost item at position of event
80 selectedItem = scene()->componentItemAt( event->modelPoint() );
81
82 if ( !selectedItem )
83 {
84 //not clicking over an item, so start marquee selection
85 mIsSelecting = true;
86 mMousePressStartPos = event->pos();
87 mRubberBand->start( event->modelPoint(), Qt::KeyboardModifiers() );
88 return;
89 }
90
91 if ( ( event->modifiers() & Qt::ShiftModifier ) && ( selectedItem->isSelected() ) )
92 {
93 //SHIFT-clicking a selected item deselects it
94 selectedItem->setSelected( false );
95
96 //Check if we have any remaining selected items, and if so, update the item panel
97 const QList<QgsModelComponentGraphicItem *> selectedItems = scene()->selectedComponentItems();
98 if ( !selectedItems.isEmpty() )
99 {
100 emit itemFocused( selectedItems.at( 0 ) );
101 }
102 else
103 {
104 emit itemFocused( nullptr );
105 }
106 }
107 else
108 {
109 if ( ( !selectedItem->isSelected() ) && //keep selection if an already selected item pressed
110 !( event->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
111 {
112 scene()->setSelectedItem( selectedItem ); // clears existing selection
113 }
114 else
115 {
116 selectedItem->setSelected( true );
117 }
118 event->ignore();
119 emit itemFocused( selectedItem );
120
121 if ( !( event->modifiers() & Qt::ShiftModifier ) )
122 {
123 // we need to manually pass this event down to items we want it to go to -- QGraphicsScene doesn't propagate events
124 // to multiple items
125 QList< QGraphicsItem * > items = scene()->items( event->modelPoint() );
126 for ( QGraphicsItem *item : items )
127 {
128 if ( QgsModelDesignerFlatButtonGraphicItem *button = dynamic_cast< QgsModelDesignerFlatButtonGraphicItem * >( item ) )
129 {
130 // arghhh - if the event happens outside the mouse handles bounding rect, then it's ALREADY passed on!
131 if ( mMouseHandles->sceneBoundingRect().contains( event->modelPoint() ) )
132 {
133 button->modelPressEvent( event );
134 event->accept();
135 return;
136 }
137 }
138 }
139 }
140 }
141
142 event->ignore();
143}
144
146{
147 if ( mIsSelecting )
148 {
149 mRubberBand->update( event->modelPoint(), Qt::KeyboardModifiers() );
150 }
151 else
152 {
153 // we need to manually pass this event down to items we want it to go to -- QGraphicsScene doesn't propagate events
154 // to multiple items
155 QList< QGraphicsItem * > items = scene()->items( event->modelPoint() );
156 for ( QGraphicsItem *item : items )
157 {
158 if ( mHoverEnteredItems.contains( item ) )
159 {
160 if ( QgsModelComponentGraphicItem *component = dynamic_cast< QgsModelComponentGraphicItem * >( item ) )
161 {
162 component->modelHoverMoveEvent( event );
163 }
164 }
165 else
166 {
167 mHoverEnteredItems.append( item );
168 if ( QgsModelComponentGraphicItem *component = dynamic_cast< QgsModelComponentGraphicItem * >( item ) )
169 {
170 component->modelHoverEnterEvent( event );
171 }
172 else if ( QgsModelDesignerFlatButtonGraphicItem *button = dynamic_cast<QgsModelDesignerFlatButtonGraphicItem *>( item ) )
173 {
174 // arghhh - if the event happens outside the mouse handles bounding rect, then it's ALREADY passed on!
175 if ( mMouseHandles->sceneBoundingRect().contains( event->modelPoint() ) )
176 button->modelHoverEnterEvent( event );
177 }
178 }
179 }
180 const QList< QGraphicsItem * > prevHovered = mHoverEnteredItems;
181 for ( QGraphicsItem *item : prevHovered )
182 {
183 if ( ! items.contains( item ) )
184 {
185 mHoverEnteredItems.removeAll( item );
186 if ( QgsModelComponentGraphicItem *component = dynamic_cast< QgsModelComponentGraphicItem * >( item ) )
187 {
188 component->modelHoverLeaveEvent( event );
189 }
190 else if ( QgsModelDesignerFlatButtonGraphicItem *button = dynamic_cast<QgsModelDesignerFlatButtonGraphicItem *>( item ) )
191 {
192 // arghhh - if the event happens outside the mouse handles bounding rect, then it's ALREADY passed on!
193 if ( mMouseHandles->sceneBoundingRect().contains( event->modelPoint() ) )
194 button->modelHoverLeaveEvent( event );
195 }
196 }
197 }
198
199 event->ignore();
200 }
201}
202
204{
205 if ( !mIsSelecting )
206 {
207 // we need to manually pass this event down to items we want it to go to -- QGraphicsScene doesn't propagate events
208 // to multiple items
209 QList< QGraphicsItem * > items = scene()->items( event->modelPoint() );
210 for ( QGraphicsItem *item : items )
211 {
212 if ( QgsModelComponentGraphicItem *component = dynamic_cast< QgsModelComponentGraphicItem * >( item ) )
213 {
214 scene()->setSelectedItem( component ); // clears existing selection
215 component->modelDoubleClickEvent( event );
216 break;
217 }
218 }
219 }
220}
221
223{
224 if ( event->button() != Qt::LeftButton && mMouseHandles->shouldBlockEvent( event ) )
225 {
226 //swallow clicks while dragging/resizing items
227 return;
228 }
229
230 if ( !mIsSelecting || event->button() != Qt::LeftButton )
231 {
232 event->ignore();
233 return;
234 }
235
236 mIsSelecting = false;
237 bool wasClick = !isClickAndDrag( mMousePressStartPos, event->pos() );
238
239 // important -- we don't pass the event modifiers here, because we use them for a different meaning!
240 // (modifying how the selection interacts with the items, rather than modifying the selection shape)
241 QRectF rect = mRubberBand->finish( event->modelPoint() );
242
243 bool subtractingSelection = false;
244 if ( event->modifiers() & Qt::ShiftModifier )
245 {
246 //shift modifier means adding to selection, nothing required here
247 }
248 else if ( event->modifiers() & Qt::ControlModifier )
249 {
250 //control modifier means subtract from current selection
251 subtractingSelection = true;
252 }
253 else
254 {
255 //not adding to or removing from selection, so clear current selection
256 whileBlocking( scene() )->deselectAll();
257 }
258
259 //determine item selection mode, default to intersection
260 Qt::ItemSelectionMode selectionMode = Qt::IntersectsItemShape;
261 if ( event->modifiers() & Qt::AltModifier )
262 {
263 //alt modifier switches to contains selection mode
264 selectionMode = Qt::ContainsItemShape;
265 }
266
267 //find all items in rect
268 QList<QGraphicsItem *> itemList;
269 if ( wasClick )
270 itemList = scene()->items( rect.center(), selectionMode );
271 else
272 itemList = scene()->items( rect, selectionMode );
273 for ( QGraphicsItem *item : std::as_const( itemList ) )
274 {
275 if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
276 {
277 if ( subtractingSelection )
278 {
279 componentItem->setSelected( false );
280 }
281 else
282 {
283 componentItem->setSelected( true );
284 }
285 if ( wasClick )
286 {
287 // found an item, and only a click - nothing more to do
288 break;
289 }
290 }
291 }
292
293 //update item panel
294 const QList<QgsModelComponentGraphicItem *> selectedItemList = scene()->selectedComponentItems();
295 if ( !selectedItemList.isEmpty() )
296 {
297 emit itemFocused( selectedItemList.at( 0 ) );
298 }
299 else
300 {
301 emit itemFocused( nullptr );
302 }
303 mMouseHandles->selectionChanged();
304}
305
306void QgsModelViewToolSelect::wheelEvent( QWheelEvent *event )
307{
308 if ( mMouseHandles->shouldBlockEvent( event ) )
309 {
310 //ignore wheel events while dragging/resizing items
311 return;
312 }
313 else
314 {
315 event->ignore();
316 }
317}
318
320{
321 if ( mMouseHandles->isDragging() || mMouseHandles->isResizing() )
322 {
323 return;
324 }
325 else
326 {
327 event->ignore();
328 }
329}
330
332{
333 if ( mIsSelecting )
334 {
335 mRubberBand->finish();
336 mIsSelecting = false;
337 }
339}
340
342{
343 return !mIsSelecting;
344}
345
346QgsModelViewMouseHandles *QgsModelViewToolSelect::mouseHandles()
347{
348 return mMouseHandles;
349}
350
351void QgsModelViewToolSelect::setScene( QgsModelGraphicsScene *scene )
352{
353 // existing handles are owned by previous layout
354 if ( mMouseHandles )
355 mMouseHandles->deleteLater();
356
357 //add mouse selection handles to scene, and initially hide
358 mMouseHandles = new QgsModelViewMouseHandles( view() );
359 mMouseHandles->hide();
360 mMouseHandles->setZValue( QgsModelGraphicsScene::MouseHandles );
361 scene->addItem( mMouseHandles );
362}
363
365{
366 mHoverEnteredItems.clear();
367}
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.
QgsModelViewRectangularRubberBand is rectangular rubber band for use within QgsModelGraphicsView widg...
void modelReleaseEvent(QgsModelViewMouseEvent *event) override
Mouse release event for overriding.
void setScene(QgsModelGraphicsScene *scene)
Sets the a scene.
void modelPressEvent(QgsModelViewMouseEvent *event) override
Mouse press event for overriding.
void wheelEvent(QWheelEvent *event) override
Mouse wheel event for overriding.
void deactivate() override
Called when tool is deactivated.
void modelDoubleClickEvent(QgsModelViewMouseEvent *event) override
Mouse double-click event for overriding.
void modelMoveEvent(QgsModelViewMouseEvent *event) override
Mouse move event for overriding.
void resetCache()
Resets the internal cache following a scene change.
QgsModelViewMouseHandles * mouseHandles()
Returns the view's mouse handles.
void keyPressEvent(QKeyEvent *event) override
Key press event for overriding.
bool allowItemInteraction() override
Returns true if the tool allows interaction with component graphic items.
QgsModelViewToolSelect(QgsModelGraphicsView *view)
Constructor for QgsModelViewToolSelect.
Abstract base class for all model designer view tools.
QgsModelGraphicsView * view() const
Returns the view associated with the tool.
void itemFocused(QgsModelComponentGraphicItem *item)
Emitted when an item is "focused" by the tool, i.e.
bool isClickAndDrag(QPoint startViewPoint, QPoint endViewPoint) const
Returns true if a mouse press/release operation which started at startViewPoint and ended at endViewP...
void setCursor(const QCursor &cursor)
Sets a user defined cursor for use when the tool is active.
virtual void deactivate()
Called when tool is deactivated.
QgsModelGraphicsScene * scene() const
Returns the scene associated with the tool.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5821