1 /***************************************************************************
2 qgsmaptoolselect.cpp - map tool for selecting features
3 ----------------------
4 begin : January 2006
5 copyright : (C) 2006 by Martin Dobias
6 email : wonder.sk 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
16
17 #include "qgsmaptoolselect.h"
18 #include "qgsmaptoolselectutils.h"
19 #include "qgsrubberband.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsmapmouseevent.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsgeometry.h"
24 #include "qgspointxy.h"
25 #include "qgis.h"
26 #include "qgsapplication.h"
27 #include "qgslogger.h"
28 #include "qgshighlight.h"
29
30 #include <QMouseEvent>
31 #include <QMenu>
32 #include <QRect>
33 #include <QColor>
34
35
QgsMapToolSelect(QgsMapCanvas * canvas)36 QgsMapToolSelect::QgsMapToolSelect( QgsMapCanvas *canvas )
37 : QgsMapTool( canvas )
38 {
39 mToolName = tr( "Select features" );
40
41 mSelectionHandler = std::make_unique<QgsMapToolSelectionHandler>( canvas );
42 connect( mSelectionHandler.get(), &QgsMapToolSelectionHandler::geometryChanged, this, &QgsMapToolSelect::selectFeatures );
43 setSelectionMode( QgsMapToolSelectionHandler::SelectSimple );
44 }
45
setSelectionMode(QgsMapToolSelectionHandler::SelectionMode selectionMode)46 void QgsMapToolSelect::setSelectionMode( QgsMapToolSelectionHandler::SelectionMode selectionMode )
47 {
48 mSelectionHandler->setSelectionMode( selectionMode );
49 if ( selectionMode == QgsMapToolSelectionHandler::SelectSimple )
50 mCursor = QgsApplication::getThemeCursor( QgsApplication::Cursor::Select );
51 else
52 mCursor = Qt::ArrowCursor;
53 }
54
canvasPressEvent(QgsMapMouseEvent * e)55 void QgsMapToolSelect::canvasPressEvent( QgsMapMouseEvent *e )
56 {
57 mSelectionHandler->canvasPressEvent( e );
58 }
59
canvasMoveEvent(QgsMapMouseEvent * e)60 void QgsMapToolSelect::canvasMoveEvent( QgsMapMouseEvent *e )
61 {
62 mSelectionHandler->canvasMoveEvent( e );
63 }
64
canvasReleaseEvent(QgsMapMouseEvent * e)65 void QgsMapToolSelect::canvasReleaseEvent( QgsMapMouseEvent *e )
66 {
67 mSelectionHandler->canvasReleaseEvent( e );
68 }
69
keyPressEvent(QKeyEvent * e)70 void QgsMapToolSelect::keyPressEvent( QKeyEvent *e )
71 {
72 if ( !e->isAutoRepeat() )
73 {
74 switch ( e->key() )
75 {
76 case Qt::Key_Shift:
77 case Qt::Key_Control:
78 case Qt::Key_Alt:
79 case Qt::Key_Meta:
80 //note -- if ctrl and shift are already depressed, pressing alt reports the "meta" key eventZ
81 modifiersChanged( e->modifiers() & Qt::ControlModifier || e->key() == Qt::Key_Control,
82 e->modifiers() & Qt::ShiftModifier || e->key() == Qt::Key_Shift,
83 e->modifiers() & Qt::AltModifier || e->key() == Qt::Key_Alt ||
84 ( e->modifiers() & Qt::ControlModifier && e->modifiers() & Qt::ShiftModifier && e->key() == Qt::Key_Meta ) );
85 break;
86
87 default:
88 break;
89 }
90 }
91
92 QgsMapTool::keyPressEvent( e );
93 }
94
keyReleaseEvent(QKeyEvent * e)95 void QgsMapToolSelect::keyReleaseEvent( QKeyEvent *e )
96 {
97 if ( mSelectionHandler->keyReleaseEvent( e ) )
98 return;
99
100 if ( !e->isAutoRepeat() )
101 {
102 switch ( e->key() )
103 {
104 case Qt::Key_Shift:
105 case Qt::Key_Control:
106 case Qt::Key_Alt:
107 case Qt::Key_Meta:
108 modifiersChanged( e->modifiers() & Qt::ControlModifier && e->key() != Qt::Key_Control,
109 e->modifiers() & Qt::ShiftModifier && e->key() != Qt::Key_Shift,
110 e->modifiers() & Qt::AltModifier && e->key() != Qt::Key_Alt &&
111 !( e->modifiers() & Qt::ControlModifier && e->modifiers() & Qt::ShiftModifier && e->key() == Qt::Key_Meta ) );
112 break;
113
114 default:
115 break;
116 }
117 }
118
119 QgsMapTool::keyReleaseEvent( e );
120 }
121
deactivate()122 void QgsMapToolSelect::deactivate()
123 {
124 mSelectionHandler->deactivate();
125 QgsMapTool::deactivate();
126 }
127
flags() const128 QgsMapTool::Flags QgsMapToolSelect::flags() const
129 {
130 switch ( mSelectionHandler->selectionMode() )
131 {
132 case QgsMapToolSelectionHandler::SelectPolygon:
133 break;
134
135 case QgsMapToolSelectionHandler::SelectSimple:
136 case QgsMapToolSelectionHandler::SelectFreehand:
137 case QgsMapToolSelectionHandler::SelectRadius:
138 return QgsMapTool::flags() | QgsMapTool::ShowContextMenu;
139 }
140
141 return QgsMapTool::flags();
142 }
143
populateContextMenuWithEvent(QMenu * menu,QgsMapMouseEvent * event)144 bool QgsMapToolSelect::populateContextMenuWithEvent( QMenu *menu, QgsMapMouseEvent *event )
145 {
146 Q_ASSERT( menu );
147 QgsVectorLayer *vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( mCanvas );
148
149 if ( !vlayer )
150 return false;
151
152 menu->addSeparator();
153
154 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
155 QgsPointXY mapPoint;
156 if ( event )
157 {
158 modifiers = event->modifiers();
159 mapPoint = event->mapPoint();
160 }
161 Qgis::SelectBehavior behavior = Qgis::SelectBehavior::SetSelection;
162 if ( modifiers & Qt::ShiftModifier && modifiers & Qt::ControlModifier )
163 behavior = Qgis::SelectBehavior::IntersectSelection;
164 else if ( modifiers & Qt::ShiftModifier )
165 behavior = Qgis::SelectBehavior::AddToSelection;
166 else if ( modifiers & Qt::ControlModifier )
167 behavior = Qgis::SelectBehavior::RemoveFromSelection;
168
169 const QgsRectangle r = QgsMapToolSelectUtils::expandSelectRectangle( mapPoint, mCanvas, vlayer );
170
171 QgsMapToolSelectUtils::QgsMapToolSelectMenuActions *menuActions
172 = new QgsMapToolSelectUtils::QgsMapToolSelectMenuActions( mCanvas, vlayer, behavior, QgsGeometry::fromRect( r ), menu );
173
174 menuActions->populateMenu( menu );
175
176 // cppcheck wrongly believes menuActions will leak
177 // cppcheck-suppress memleak
178 return true;
179 }
180
selectFeatures(Qt::KeyboardModifiers modifiers)181 void QgsMapToolSelect::selectFeatures( Qt::KeyboardModifiers modifiers )
182 {
183 if ( mSelectionHandler->selectionMode() == QgsMapToolSelectionHandler::SelectSimple &&
184 mSelectionHandler->selectedGeometry().type() == QgsWkbTypes::PointGeometry )
185 {
186 QgsVectorLayer *vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( mCanvas );
187 const QgsRectangle r = QgsMapToolSelectUtils::expandSelectRectangle( mSelectionHandler->selectedGeometry().asPoint(), mCanvas, vlayer );
188 QgsMapToolSelectUtils::selectSingleFeature( mCanvas, QgsGeometry::fromRect( r ), modifiers );
189 }
190 else
191 QgsMapToolSelectUtils::selectMultipleFeatures( mCanvas, mSelectionHandler->selectedGeometry(), modifiers );
192 }
193
modifiersChanged(bool ctrlModifier,bool shiftModifier,bool altModifier)194 void QgsMapToolSelect::modifiersChanged( bool ctrlModifier, bool shiftModifier, bool altModifier )
195 {
196 if ( !ctrlModifier && !shiftModifier && !altModifier )
197 emit modeChanged( GeometryIntersectsSetSelection );
198 else if ( !ctrlModifier && !shiftModifier && altModifier )
199 emit modeChanged( GeometryWithinSetSelection );
200 else if ( !ctrlModifier && shiftModifier && !altModifier )
201 emit modeChanged( GeometryIntersectsAddToSelection );
202 else if ( !ctrlModifier && shiftModifier && altModifier )
203 emit modeChanged( GeometryWithinAddToSelection );
204 else if ( ctrlModifier && !shiftModifier && !altModifier )
205 emit modeChanged( GeometryIntersectsSubtractFromSelection );
206 else if ( ctrlModifier && !shiftModifier && altModifier )
207 emit modeChanged( GeometryWithinSubtractFromSelection );
208 else if ( ctrlModifier && shiftModifier && !altModifier )
209 emit modeChanged( GeometryIntersectsIntersectWithSelection );
210 else if ( ctrlModifier && shiftModifier && altModifier )
211 emit modeChanged( GeometryWithinIntersectWithSelection );
212 }
213