QGIS API Documentation  2.99.0-Master (585a4d3)
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 
29  : QgsCollapsibleGroupBox( parent )
30  , mTitleBase( tr( "Extent" ) )
31 {
32  setupUi( this );
33  connect( mXMinLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
34  connect( mXMaxLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
35  connect( mYMinLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
36  connect( mYMaxLineEdit, &QLineEdit::textEdited, this, &QgsExtentGroupBox::setOutputExtentFromLineEdit );
37 
38  mLayerMenu = new QMenu( this );
39  mButtonCalcFromLayer->setMenu( mLayerMenu );
40  connect( mLayerMenu, &QMenu::aboutToShow, this, &QgsExtentGroupBox::layerMenuAboutToShow );
41  mMapLayerModel = new QgsMapLayerModel( this );
42 
43  mXMinLineEdit->setValidator( new QDoubleValidator( this ) );
44  mXMaxLineEdit->setValidator( new QDoubleValidator( this ) );
45  mYMinLineEdit->setValidator( new QDoubleValidator( this ) );
46  mYMaxLineEdit->setValidator( new QDoubleValidator( this ) );
47 
48  mOriginalExtentButton->setVisible( false );
49  mButtonDrawOnCanvas->setVisible( false );
50  mCurrentExtentButton->setVisible( false );
51 
52  connect( mCurrentExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromCurrent );
53  connect( mOriginalExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromOriginal );
54  connect( mButtonDrawOnCanvas, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromDrawOnCanvas );
55 
56  connect( this, &QGroupBox::clicked, this, &QgsExtentGroupBox::groupBoxClicked );
57 }
58 
60 {
61  mOriginalExtent = originalExtent;
62  mOriginalCrs = originalCrs;
63 
64  mOriginalExtentButton->setVisible( true );
65 }
66 
67 
69 {
70  mCurrentExtent = currentExtent;
71  mCurrentCrs = currentCrs;
72 
73  mCurrentExtentButton->setVisible( true );
74 }
75 
77 {
78  if ( mOutputCrs != outputCrs )
79  {
80  switch ( mExtentState )
81  {
82  case CurrentExtent:
83  mOutputCrs = outputCrs;
85  break;
86 
87  case OriginalExtent:
88  mOutputCrs = outputCrs;
90  break;
91 
92  case ProjectLayerExtent:
93  mOutputCrs = outputCrs;
94  setOutputExtentFromLayer( mExtentLayer.data() );
95  break;
96 
97  case DrawOnCanvas:
98  mOutputCrs = outputCrs;
99  extentDrawn( outputExtent() );
100  break;
101 
102  case UserExtent:
103  try
104  {
105  QgsCoordinateTransform ct( mOutputCrs, outputCrs, QgsProject::instance() );
107  mOutputCrs = outputCrs;
108  setOutputExtentFromUser( extent, outputCrs );
109  }
110  catch ( QgsCsException & )
111  {
112  // can't reproject
113  mOutputCrs = outputCrs;
114  }
115  break;
116  }
117 
118  }
119 
120 }
121 
122 void QgsExtentGroupBox::setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, ExtentState state )
123 {
124  QgsRectangle extent;
125  if ( mOutputCrs == srcCrs )
126  {
127  extent = r;
128  }
129  else
130  {
131  try
132  {
133  QgsCoordinateTransform ct( srcCrs, mOutputCrs, QgsProject::instance() );
134  extent = ct.transformBoundingBox( r );
135  }
136  catch ( QgsCsException & )
137  {
138  // can't reproject
139  extent = r;
140  }
141  }
142 
143  int decimals = 4;
144  switch ( mOutputCrs.mapUnits() )
145  {
148  decimals = 9;
149  break;
158  decimals = 4;
159  break;
160  }
161  mXMinLineEdit->setText( QString::number( extent.xMinimum(), 'f', decimals ) );
162  mXMaxLineEdit->setText( QString::number( extent.xMaximum(), 'f', decimals ) );
163  mYMinLineEdit->setText( QString::number( extent.yMinimum(), 'f', decimals ) );
164  mYMaxLineEdit->setText( QString::number( extent.yMaximum(), 'f', decimals ) );
165 
166  mExtentState = state;
167 
168  if ( isCheckable() && !isChecked() )
169  setChecked( true );
170 
171  updateTitle();
172 
173  emit extentChanged( extent );
174 }
175 
176 
177 void QgsExtentGroupBox::setOutputExtentFromLineEdit()
178 {
179  mExtentState = UserExtent;
180 
181  updateTitle();
182 
183  emit extentChanged( outputExtent() );
184 }
185 
186 
187 void QgsExtentGroupBox::updateTitle()
188 {
189  QString msg;
190  switch ( mExtentState )
191  {
192  case OriginalExtent:
193  msg = tr( "layer" );
194  break;
195  case CurrentExtent:
196  msg = tr( "map view" );
197  break;
198  case UserExtent:
199  msg = tr( "user defined" );
200  break;
201  case ProjectLayerExtent:
202  msg = mExtentLayerName;
203  break;
204  case DrawOnCanvas:
205  msg = tr( "drawn on canvas" );
206  break;
207  }
208  if ( isCheckable() && !isChecked() )
209  msg = tr( "none" );
210  msg = tr( "%1 (current: %2)" ).arg( mTitleBase, msg );
211 
212  setTitle( msg );
213 }
214 
215 void QgsExtentGroupBox::layerMenuAboutToShow()
216 {
217  qDeleteAll( mMenuActions );
218  mMenuActions.clear();
219  mLayerMenu->clear();
220  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
221  {
222  QModelIndex index = mMapLayerModel->index( i, 0 );
223  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
224  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
225  QAction *act = new QAction( icon, text, mLayerMenu );
226  act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
227  QString layerId = mMapLayerModel->data( index, QgsMapLayerModel::LayerIdRole ).toString();
228  if ( mExtentState == ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
229  {
230  act->setCheckable( true );
231  act->setChecked( true );
232  }
233  connect( act, &QAction::triggered, this, [this, layerId]
234  {
235  setExtentToLayerExtent( layerId );
236  } );
237  mLayerMenu->addAction( act );
238  mMenuActions << act;
239  }
240 }
241 
242 void QgsExtentGroupBox::setExtentToLayerExtent( const QString &layerId )
243 {
244  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
245  if ( !layer )
246  return;
247 
248  setOutputExtentFromLayer( layer );
249 }
250 
252 {
253  if ( mCanvas )
254  {
255  // Use unrotated visible extent to insure output size and scale matches canvas
256  QgsMapSettings ms = mCanvas->mapSettings();
257  ms.setRotation( 0 );
258  setOutputExtent( ms.visibleExtent(), ms.destinationCrs(), CurrentExtent );
259  }
260  else
261  {
262  setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
263  }
264 }
265 
266 
268 {
269  setOutputExtent( mOriginalExtent, mOriginalCrs, OriginalExtent );
270 }
271 
273 {
274  setOutputExtent( extent, crs, UserExtent );
275 }
276 
278 {
279  if ( !layer )
280  return;
281 
282  mExtentLayer = layer;
283  mExtentLayerName = layer->name();
284 
285  setOutputExtent( layer->extent(), layer->crs(), ProjectLayerExtent );
286 }
287 
289 {
290  if ( mCanvas )
291  {
292  mMapToolPrevious = mCanvas->mapTool();
293  if ( !mMapToolExtent )
294  {
295  mMapToolExtent.reset( new QgsMapToolExtent( mCanvas ) );
296  connect( mMapToolExtent.get(), &QgsMapToolExtent::extentChanged, this, &QgsExtentGroupBox::extentDrawn );
297  connect( mMapToolExtent.get(), &QgsMapTool::deactivated, this, [ = ]
298  {
299  window()->setVisible( true );
300  mMapToolPrevious = nullptr;
301  } );
302  }
303  mMapToolExtent->setRatio( mRatio );
304  mCanvas->setMapTool( mMapToolExtent.get() );
305  window()->setVisible( false );
306  }
307 }
308 
309 void QgsExtentGroupBox::extentDrawn( const QgsRectangle &extent )
310 {
311  setOutputExtent( extent, mCanvas->mapSettings().destinationCrs(), DrawOnCanvas );
312  mCanvas->setMapTool( mMapToolPrevious );
313  window()->setVisible( true );
314  mMapToolPrevious = nullptr;
315 }
316 
317 void QgsExtentGroupBox::groupBoxClicked()
318 {
319  if ( !isCheckable() )
320  return;
321 
322  updateTitle();
323 
324  // output extent just went from null to something (or vice versa)
325  emit extentChanged( outputExtent() );
326 }
327 
328 
330 {
331  if ( isCheckable() && !isChecked() )
332  return QgsRectangle();
333 
334  return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(),
335  mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
336 }
337 
338 void QgsExtentGroupBox::setTitleBase( const QString &title )
339 {
340  mTitleBase = title;
341  updateTitle();
342 }
343 
344 QString QgsExtentGroupBox::titleBase() const
345 {
346  return mTitleBase;
347 }
348 
350 {
351  if ( canvas )
352  {
353  mCanvas = canvas;
354  mButtonDrawOnCanvas->setVisible( true );
355  mCurrentExtentButton->setVisible( true );
356  }
357  else
358  {
359  mButtonDrawOnCanvas->setVisible( false );
360  mCurrentExtentButton->setVisible( false );
361  }
362 }
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.