QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  bool prevExtentEnabled = isChecked();
82  switch ( mExtentState )
83  {
84  case CurrentExtent:
85  mOutputCrs = outputCrs;
87  break;
88 
89  case OriginalExtent:
90  mOutputCrs = outputCrs;
92  break;
93 
94  case ProjectLayerExtent:
95  mOutputCrs = outputCrs;
96  setOutputExtentFromLayer( mExtentLayer.data() );
97  break;
98 
99  case DrawOnCanvas:
100  mOutputCrs = outputCrs;
101  extentDrawn( outputExtent() );
102  break;
103 
104  case UserExtent:
105  try
106  {
107  QgsCoordinateTransform ct( mOutputCrs, outputCrs, QgsProject::instance() );
109  mOutputCrs = outputCrs;
110  setOutputExtentFromUser( extent, outputCrs );
111  }
112  catch ( QgsCsException & )
113  {
114  // can't reproject
115  mOutputCrs = outputCrs;
116  }
117  break;
118  }
119 
120  if ( !prevExtentEnabled )
121  setChecked( false );
122  }
123 
124 }
125 
126 void QgsExtentGroupBox::setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, ExtentState state )
127 {
128  QgsRectangle extent;
129  if ( mOutputCrs == srcCrs )
130  {
131  extent = r;
132  }
133  else
134  {
135  try
136  {
137  QgsCoordinateTransform ct( srcCrs, mOutputCrs, QgsProject::instance() );
138  extent = ct.transformBoundingBox( r );
139  }
140  catch ( QgsCsException & )
141  {
142  // can't reproject
143  extent = r;
144  }
145  }
146 
147  int decimals = 4;
148  switch ( mOutputCrs.mapUnits() )
149  {
152  decimals = 9;
153  break;
162  decimals = 4;
163  break;
164  }
165  mXMinLineEdit->setText( QString::number( extent.xMinimum(), 'f', decimals ) );
166  mXMaxLineEdit->setText( QString::number( extent.xMaximum(), 'f', decimals ) );
167  mYMinLineEdit->setText( QString::number( extent.yMinimum(), 'f', decimals ) );
168  mYMaxLineEdit->setText( QString::number( extent.yMaximum(), 'f', decimals ) );
169 
170  mExtentState = state;
171 
172  if ( isCheckable() && !isChecked() )
173  setChecked( true );
174 
175  updateTitle();
176 
177  emit extentChanged( extent );
178 }
179 
180 
181 void QgsExtentGroupBox::setOutputExtentFromLineEdit()
182 {
183  mExtentState = UserExtent;
184 
185  updateTitle();
186 
187  emit extentChanged( outputExtent() );
188 }
189 
190 
191 void QgsExtentGroupBox::updateTitle()
192 {
193  QString msg;
194  switch ( mExtentState )
195  {
196  case OriginalExtent:
197  msg = tr( "layer" );
198  break;
199  case CurrentExtent:
200  msg = tr( "map view" );
201  break;
202  case UserExtent:
203  msg = tr( "user defined" );
204  break;
205  case ProjectLayerExtent:
206  msg = mExtentLayerName;
207  break;
208  case DrawOnCanvas:
209  msg = tr( "drawn on canvas" );
210  break;
211  }
212  if ( isCheckable() && !isChecked() )
213  msg = tr( "none" );
214  msg = tr( "%1 (current: %2)" ).arg( mTitleBase, msg );
215 
216  setTitle( msg );
217 }
218 
219 void QgsExtentGroupBox::layerMenuAboutToShow()
220 {
221  qDeleteAll( mMenuActions );
222  mMenuActions.clear();
223  mLayerMenu->clear();
224  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
225  {
226  QModelIndex index = mMapLayerModel->index( i, 0 );
227  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
228  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
229  QAction *act = new QAction( icon, text, mLayerMenu );
230  act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
231  QString layerId = mMapLayerModel->data( index, QgsMapLayerModel::LayerIdRole ).toString();
232  if ( mExtentState == ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
233  {
234  act->setCheckable( true );
235  act->setChecked( true );
236  }
237  connect( act, &QAction::triggered, this, [this, layerId]
238  {
239  setExtentToLayerExtent( layerId );
240  } );
241  mLayerMenu->addAction( act );
242  mMenuActions << act;
243  }
244 }
245 
246 void QgsExtentGroupBox::setExtentToLayerExtent( const QString &layerId )
247 {
248  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
249  if ( !layer )
250  return;
251 
252  setOutputExtentFromLayer( layer );
253 }
254 
256 {
257  if ( mCanvas )
258  {
259  // Use unrotated visible extent to insure output size and scale matches canvas
260  QgsMapSettings ms = mCanvas->mapSettings();
261  ms.setRotation( 0 );
262  setOutputExtent( ms.visibleExtent(), ms.destinationCrs(), CurrentExtent );
263  }
264  else
265  {
266  setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
267  }
268 }
269 
270 
272 {
273  setOutputExtent( mOriginalExtent, mOriginalCrs, OriginalExtent );
274 }
275 
277 {
278  setOutputExtent( extent, crs, UserExtent );
279 }
280 
282 {
283  if ( !layer )
284  return;
285 
286  mExtentLayer = layer;
287  mExtentLayerName = layer->name();
288 
289  setOutputExtent( layer->extent(), layer->crs(), ProjectLayerExtent );
290 }
291 
293 {
294  if ( mCanvas )
295  {
296  mMapToolPrevious = mCanvas->mapTool();
297  if ( !mMapToolExtent )
298  {
299  mMapToolExtent.reset( new QgsMapToolExtent( mCanvas ) );
300  connect( mMapToolExtent.get(), &QgsMapToolExtent::extentChanged, this, &QgsExtentGroupBox::extentDrawn );
301  connect( mMapToolExtent.get(), &QgsMapTool::deactivated, this, [ = ]
302  {
303  window()->setVisible( true );
304  mMapToolPrevious = nullptr;
305  } );
306  }
307  mMapToolExtent->setRatio( mRatio );
308  mCanvas->setMapTool( mMapToolExtent.get() );
309  window()->setVisible( false );
310  }
311 }
312 
313 void QgsExtentGroupBox::extentDrawn( const QgsRectangle &extent )
314 {
315  setOutputExtent( extent, mCanvas->mapSettings().destinationCrs(), DrawOnCanvas );
316  mCanvas->setMapTool( mMapToolPrevious );
317  window()->setVisible( true );
318  mMapToolPrevious = nullptr;
319 }
320 
321 void QgsExtentGroupBox::groupBoxClicked()
322 {
323  if ( !isCheckable() )
324  return;
325 
326  updateTitle();
327 
328  // output extent just went from null to something (or vice versa)
329  emit extentChanged( outputExtent() );
330 }
331 
332 
334 {
335  if ( isCheckable() && !isChecked() )
336  return QgsRectangle();
337 
338  return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(),
339  mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
340 }
341 
342 void QgsExtentGroupBox::setTitleBase( const QString &title )
343 {
344  mTitleBase = title;
345  updateTitle();
346 }
347 
348 QString QgsExtentGroupBox::titleBase() const
349 {
350  return mTitleBase;
351 }
352 
354 {
355  if ( canvas )
356  {
357  mCanvas = canvas;
358  mButtonDrawOnCanvas->setVisible( true );
359  mCurrentExtentButton->setVisible( true );
360  }
361  else
362  {
363  mButtonDrawOnCanvas->setVisible( false );
364  mCurrentExtentButton->setVisible( false );
365  }
366 }
Extent manually entered/modified by the user.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Base class for all map layer types.
Definition: qgsmaplayer.h:63
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.
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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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.
const QgsCoordinateReferenceSystem & crs
QgsCoordinateReferenceSystem currentCrs() const
Returns the coordinate reference system for the current extent set for the widget.
QString titleBase() const
Returns the base part of title of the group box (will be appended with extent state).
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
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.
QgsRectangle originalExtent() const
Returns the original extent set for the widget.
Extent taken from a layer within the project.
QgsCoordinateReferenceSystem outputCrs() const
Returns the current output CRS, used in the display.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
virtual QgsRectangle extent() const
Returns the extent of the layer.
void extentChanged(const QgsRectangle &extent)
signal emitted on extent change
The QgsMapLayerModel class is a model to display layers in widgets.
QgsRectangle outputExtent() const
Returns the extent shown in the widget - in output CRS coordinates.
QgsCoordinateReferenceSystem originalCrs() const
Returns the original coordinate reference system set for the widget.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:61
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...
void setOutputExtentFromLayer(const QgsMapLayer *layer)
Sets the output extent to match a layer&#39;s extent (may be transformed to output CRS).
A map tool that emits an extent from a rectangle drawn onto the map canvas.
QgsExtentGroupBox(QWidget *parent=nullptr)
Constructor for QgsExtentGroupBox.
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
Unknown distance unit.
Definition: qgsunittypes.h:64
void setTitleBase(const QString &title)
Sets the base part of title of the group box (will be appended with extent state) ...
QgsRectangle currentExtent() const
Returns the current extent set for the widget.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void deactivated()
signal emitted once the map tool is deactivated
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:411
This class represents a coordinate reference system (CRS).
Class for doing transforms between two map coordinate systems.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QString name
Definition: qgsmaplayer.h:67
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:60
void setOriginalExtent(const QgsRectangle &originalExtent, const QgsCoordinateReferenceSystem &originalCrs)
Sets the original extent and coordinate reference system for the widget.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:70