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