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