QGIS API Documentation  3.0.2-Girona (307d082)
qgsextentgroupbox.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsextentgroupbox.cpp
3  ---------------------
4  begin : March 2014
5  copyright : (C) 2014 by Martin Dobias
6  email : wonder dot 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 #include "qgsextentgroupbox.h"
17 
18 #include "qgslogger.h"
19 #include "qgscoordinatetransform.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsmaplayermodel.h"
22 #include "qgsexception.h"
23 #include "qgsproject.h"
24 
25 #include <QMenu>
26 #include <QAction>
27 #include <QDoubleValidator>
28 
30  : QgsCollapsibleGroupBox( parent )
31  , mTitleBase( tr( "Extent" ) )
32 {
33  setupUi( this );
34  connect( mXMinLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
35  connect( mXMaxLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
36  connect( mYMinLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
37  connect( mYMaxLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
38 
39  mLayerMenu = new QMenu( this );
40  mButtonCalcFromLayer->setMenu( mLayerMenu );
41  connect( mLayerMenu, &QMenu::aboutToShow, this, &QgsExtentGroupBox::layerMenuAboutToShow );
42  mMapLayerModel = new QgsMapLayerModel( this );
43 
44  mXMinLineEdit->setValidator( new QDoubleValidator( this ) );
45  mXMaxLineEdit->setValidator( new QDoubleValidator( this ) );
46  mYMinLineEdit->setValidator( new QDoubleValidator( this ) );
47  mYMaxLineEdit->setValidator( new QDoubleValidator( this ) );
48 
49  mOriginalExtentButton->setVisible( false );
50  mButtonDrawOnCanvas->setVisible( false );
51  mCurrentExtentButton->setVisible( false );
52 
53  connect( mCurrentExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromCurrent );
54  connect( mOriginalExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromOriginal );
55  connect( mButtonDrawOnCanvas, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromDrawOnCanvas );
56 
57  connect( this, &QGroupBox::clicked, this, &QgsExtentGroupBox::groupBoxClicked );
58 }
59 
61 {
62  mOriginalExtent = originalExtent;
63  mOriginalCrs = originalCrs;
64 
65  mOriginalExtentButton->setVisible( true );
66 }
67 
68 
70 {
71  mCurrentExtent = currentExtent;
72  mCurrentCrs = currentCrs;
73 
74  mCurrentExtentButton->setVisible( true );
75 }
76 
78 {
79  if ( mOutputCrs != outputCrs )
80  {
81  switch ( mExtentState )
82  {
83  case CurrentExtent:
84  mOutputCrs = outputCrs;
86  break;
87 
88  case OriginalExtent:
89  mOutputCrs = outputCrs;
91  break;
92 
93  case ProjectLayerExtent:
94  mOutputCrs = outputCrs;
95  setOutputExtentFromLayer( mExtentLayer.data() );
96  break;
97 
98  case DrawOnCanvas:
99  mOutputCrs = outputCrs;
100  extentDrawn( outputExtent() );
101  break;
102 
103  case UserExtent:
104  try
105  {
106  QgsCoordinateTransform ct( mOutputCrs, outputCrs, QgsProject::instance() );
108  mOutputCrs = outputCrs;
109  setOutputExtentFromUser( extent, outputCrs );
110  }
111  catch ( QgsCsException & )
112  {
113  // can't reproject
114  mOutputCrs = outputCrs;
115  }
116  break;
117  }
118 
119  }
120 
121 }
122 
123 void QgsExtentGroupBox::setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, ExtentState state )
124 {
125  QgsRectangle extent;
126  if ( mOutputCrs == srcCrs )
127  {
128  extent = r;
129  }
130  else
131  {
132  try
133  {
134  QgsCoordinateTransform ct( srcCrs, mOutputCrs, QgsProject::instance() );
135  extent = ct.transformBoundingBox( r );
136  }
137  catch ( QgsCsException & )
138  {
139  // can't reproject
140  extent = r;
141  }
142  }
143 
144  int decimals = 4;
145  switch ( mOutputCrs.mapUnits() )
146  {
149  decimals = 9;
150  break;
159  decimals = 4;
160  break;
161  }
162  mXMinLineEdit->setText( QString::number( extent.xMinimum(), 'f', decimals ) );
163  mXMaxLineEdit->setText( QString::number( extent.xMaximum(), 'f', decimals ) );
164  mYMinLineEdit->setText( QString::number( extent.yMinimum(), 'f', decimals ) );
165  mYMaxLineEdit->setText( QString::number( extent.yMaximum(), 'f', decimals ) );
166 
167  mExtentState = state;
168 
169  if ( isCheckable() && !isChecked() )
170  setChecked( true );
171 
172  updateTitle();
173 
174  emit extentChanged( extent );
175 }
176 
177 
178 void QgsExtentGroupBox::setOutputExtentFromLineEdit()
179 {
180  mExtentState = UserExtent;
181 
182  updateTitle();
183 
184  emit extentChanged( outputExtent() );
185 }
186 
187 
188 void QgsExtentGroupBox::updateTitle()
189 {
190  QString msg;
191  switch ( mExtentState )
192  {
193  case OriginalExtent:
194  msg = tr( "layer" );
195  break;
196  case CurrentExtent:
197  msg = tr( "map view" );
198  break;
199  case UserExtent:
200  msg = tr( "user defined" );
201  break;
202  case ProjectLayerExtent:
203  msg = mExtentLayerName;
204  break;
205  case DrawOnCanvas:
206  msg = tr( "drawn on canvas" );
207  break;
208  }
209  if ( isCheckable() && !isChecked() )
210  msg = tr( "none" );
211  msg = tr( "%1 (current: %2)" ).arg( mTitleBase, msg );
212 
213  setTitle( msg );
214 }
215 
216 void QgsExtentGroupBox::layerMenuAboutToShow()
217 {
218  qDeleteAll( mMenuActions );
219  mMenuActions.clear();
220  mLayerMenu->clear();
221  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
222  {
223  QModelIndex index = mMapLayerModel->index( i, 0 );
224  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
225  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
226  QAction *act = new QAction( icon, text, mLayerMenu );
227  act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
228  QString layerId = mMapLayerModel->data( index, QgsMapLayerModel::LayerIdRole ).toString();
229  if ( mExtentState == ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
230  {
231  act->setCheckable( true );
232  act->setChecked( true );
233  }
234  connect( act, &QAction::triggered, this, [this, layerId]
235  {
236  setExtentToLayerExtent( layerId );
237  } );
238  mLayerMenu->addAction( act );
239  mMenuActions << act;
240  }
241 }
242 
243 void QgsExtentGroupBox::setExtentToLayerExtent( const QString &layerId )
244 {
245  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
246  if ( !layer )
247  return;
248 
249  setOutputExtentFromLayer( layer );
250 }
251 
253 {
254  if ( mCanvas )
255  {
256  // Use unrotated visible extent to insure output size and scale matches canvas
257  QgsMapSettings ms = mCanvas->mapSettings();
258  ms.setRotation( 0 );
259  setOutputExtent( ms.visibleExtent(), ms.destinationCrs(), CurrentExtent );
260  }
261  else
262  {
263  setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
264  }
265 }
266 
267 
269 {
270  setOutputExtent( mOriginalExtent, mOriginalCrs, OriginalExtent );
271 }
272 
274 {
275  setOutputExtent( extent, crs, UserExtent );
276 }
277 
279 {
280  if ( !layer )
281  return;
282 
283  mExtentLayer = layer;
284  mExtentLayerName = layer->name();
285 
286  setOutputExtent( layer->extent(), layer->crs(), ProjectLayerExtent );
287 }
288 
290 {
291  if ( mCanvas )
292  {
293  mMapToolPrevious = mCanvas->mapTool();
294  if ( !mMapToolExtent )
295  {
296  mMapToolExtent.reset( new QgsMapToolExtent( mCanvas ) );
297  connect( mMapToolExtent.get(), &QgsMapToolExtent::extentChanged, this, &QgsExtentGroupBox::extentDrawn );
298  connect( mMapToolExtent.get(), &QgsMapTool::deactivated, this, [ = ]
299  {
300  window()->setVisible( true );
301  mMapToolPrevious = nullptr;
302  } );
303  }
304  mMapToolExtent->setRatio( mRatio );
305  mCanvas->setMapTool( mMapToolExtent.get() );
306  window()->setVisible( false );
307  }
308 }
309 
310 void QgsExtentGroupBox::extentDrawn( const QgsRectangle &extent )
311 {
312  setOutputExtent( extent, mCanvas->mapSettings().destinationCrs(), DrawOnCanvas );
313  mCanvas->setMapTool( mMapToolPrevious );
314  window()->setVisible( true );
315  mMapToolPrevious = nullptr;
316 }
317 
318 void QgsExtentGroupBox::groupBoxClicked()
319 {
320  if ( !isCheckable() )
321  return;
322 
323  updateTitle();
324 
325  // output extent just went from null to something (or vice versa)
326  emit extentChanged( outputExtent() );
327 }
328 
329 
331 {
332  if ( isCheckable() && !isChecked() )
333  return QgsRectangle();
334 
335  return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(),
336  mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
337 }
338 
339 void QgsExtentGroupBox::setTitleBase( const QString &title )
340 {
341  mTitleBase = title;
342  updateTitle();
343 }
344 
345 QString QgsExtentGroupBox::titleBase() const
346 {
347  return mTitleBase;
348 }
349 
351 {
352  if ( canvas )
353  {
354  mCanvas = canvas;
355  mButtonDrawOnCanvas->setVisible( true );
356  mCurrentExtentButton->setVisible( true );
357  }
358  else
359  {
360  mButtonDrawOnCanvas->setVisible( false );
361  mCurrentExtentButton->setVisible( false );
362  }
363 }
Extent manually entered/modified by the user.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
QgsRectangle originalExtent() const
Returns the original extent set for the widget.
void setOutputExtentFromCurrent()
Sets the output extent to be the same as current extent (may be transformed to output CRS)...
void extentChanged(const QgsRectangle &r)
Emitted when the widget&#39;s extent is changed.
QString titleBase() const
Returns the base part of title of the group box (will be appended with extent state).
A groupbox that collapses/expands when toggled and can save its collapsed and checked states...
void setOutputExtentFromUser(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &crs)
Sets the output extent to a custom extent (may be transformed to output CRS).
Stores the map layer ID.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas to enable dragging of extent on a canvas.
void setOutputExtentFromDrawOnCanvas()
Sets the output extent by dragging on the canvas.
QgsMapTool * mapTool()
Returns the currently active tool.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
virtual QgsRectangle extent() const
Returns the extent of the layer.
ExtentState
Available states for the current extent selection in the widget.
The QgsMapSettings class contains configuration for rendering of the map.
Extent taken from a rectangled drawn onto the map canvas.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
Extent taken from a layer within the project.
void extentChanged(const QgsRectangle &extent)
signal emitted on extent change
The QgsMapLayerModel class is a model to display layers in widgets.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:51
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
void setOutputCrs(const QgsCoordinateReferenceSystem &outputCrs)
Sets the output CRS - may need to be used for transformation from original/current extent...
void setCurrentExtent(const QgsRectangle &currentExtent, const QgsCoordinateReferenceSystem &currentCrs)
Sets the current extent to show in the widget - should be called as part of initialization (or whenev...
QgsRectangle currentExtent() const
Returns the current extent set for the widget.
void setOutputExtentFromLayer(const QgsMapLayer *layer)
Sets the output extent to match a layer&#39;s extent (may be transformed to output CRS).
QgsRectangle outputExtent() const
Returns the extent shown in the widget - in output CRS coordinates.
A map tool that emits an extent from a rectangle drawn onto the map canvas.
QgsExtentGroupBox(QWidget *parent=nullptr)
Constructor for QgsExtentGroupBox.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:130
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:115
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
Unknown distance unit.
Definition: qgsunittypes.h:54
void setTitleBase(const QString &title)
Sets the base part of title of the group box (will be appended with extent state) ...
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void deactivated()
signal emitted once the map tool is deactivated
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
This class represents a coordinate reference system (CRS).
QgsCoordinateReferenceSystem originalCrs() const
Returns the original coordinate reference system set for the widget.
Class for doing transforms between two map coordinate systems.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:120
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:125
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QString name
Definition: qgsmaplayer.h:60
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
void setOutputExtentFromOriginal()
Sets the output extent to be the same as original extent (may be transformed to output CRS)...
Terrestrial miles.
Definition: qgsunittypes.h:50
void setOriginalExtent(const QgsRectangle &originalExtent, const QgsCoordinateReferenceSystem &originalCrs)
Sets the original extent and coordinate reference system for the widget.
QgsCoordinateReferenceSystem currentCrs() const
Returns the coordinate reference system for the current extent set for the widget.
QgsCoordinateReferenceSystem outputCrs() const
Returns the current output CRS, used in the display.