QGIS API Documentation  2.99.0-Master (53aba61)
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 "qgsrasterblock.h"
21 #include "qgsmapcanvas.h"
22 #include "qgsmaplayermodel.h"
23 #include "qgsexception.h"
24 #include "qgsproject.h"
25 
26 #include <QMenu>
27 #include <QAction>
28 
30  : QgsCollapsibleGroupBox( parent )
31  , mTitleBase( tr( "Extent" ) )
32  , mExtentState( OriginalExtent )
33 {
34  setupUi( this );
35 
36  mLayerMenu = new QMenu( this );
37  mButtonCalcFromLayer->setMenu( mLayerMenu );
38  connect( mLayerMenu, &QMenu::aboutToShow, this, &QgsExtentGroupBox::layerMenuAboutToShow );
39  mMapLayerModel = new QgsMapLayerModel( this );
40 
41  mXMinLineEdit->setValidator( new QDoubleValidator( this ) );
42  mXMaxLineEdit->setValidator( new QDoubleValidator( this ) );
43  mYMinLineEdit->setValidator( new QDoubleValidator( this ) );
44  mYMaxLineEdit->setValidator( new QDoubleValidator( this ) );
45 
46  mOriginalExtentButton->setVisible( false );
47  mButtonDrawOnCanvas->setVisible( false );
48 
49  connect( mCurrentExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromCurrent );
50  connect( mOriginalExtentButton, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromOriginal );
51  connect( mButtonDrawOnCanvas, &QAbstractButton::clicked, this, &QgsExtentGroupBox::setOutputExtentFromDrawOnCanvas );
52 
53  connect( this, &QGroupBox::clicked, this, &QgsExtentGroupBox::groupBoxClicked );
54 }
55 
57 {
58  mOriginalExtent = originalExtent;
59  mOriginalCrs = originalCrs;
60 
61  mOriginalExtentButton->setVisible( true );
62 }
63 
64 
66 {
67  mCurrentExtent = currentExtent;
68  mCurrentCrs = currentCrs;
69 }
70 
72 {
73  if ( mOutputCrs != outputCrs )
74  {
75  switch ( mExtentState )
76  {
77  case CurrentExtent:
78  mOutputCrs = outputCrs;
80  break;
81 
82  case OriginalExtent:
83  mOutputCrs = outputCrs;
85  break;
86 
87  case ProjectLayerExtent:
88  mOutputCrs = outputCrs;
89  setOutputExtentFromLayer( mExtentLayer.data() );
90  break;
91 
92  case DrawOnCanvas:
93  mOutputCrs = outputCrs;
94  extentDrawn( outputExtent() );
95  break;
96 
97  case UserExtent:
98  try
99  {
100  QgsCoordinateTransform ct( mOutputCrs, outputCrs );
102  mOutputCrs = outputCrs;
103  setOutputExtentFromUser( extent, outputCrs );
104  }
105  catch ( QgsCsException & )
106  {
107  // can't reproject
108  mOutputCrs = outputCrs;
109  }
110  break;
111  }
112 
113  }
114 
115 }
116 
117 void QgsExtentGroupBox::setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, ExtentState state )
118 {
119  QgsRectangle extent;
120  if ( mOutputCrs == srcCrs )
121  {
122  extent = r;
123  }
124  else
125  {
126  try
127  {
128  QgsCoordinateTransform ct( srcCrs, mOutputCrs );
129  extent = ct.transformBoundingBox( r );
130  }
131  catch ( QgsCsException & )
132  {
133  // can't reproject
134  extent = r;
135  }
136  }
137 
138  mXMinLineEdit->setText( QgsRasterBlock::printValue( extent.xMinimum() ) );
139  mXMaxLineEdit->setText( QgsRasterBlock::printValue( extent.xMaximum() ) );
140  mYMinLineEdit->setText( QgsRasterBlock::printValue( extent.yMinimum() ) );
141  mYMaxLineEdit->setText( QgsRasterBlock::printValue( extent.yMaximum() ) );
142 
143  mExtentState = state;
144 
145  if ( isCheckable() && !isChecked() )
146  setChecked( true );
147 
148  updateTitle();
149 
150  emit extentChanged( extent );
151 }
152 
153 
154 void QgsExtentGroupBox::setOutputExtentFromLineEdit()
155 {
156  mExtentState = UserExtent;
157 
158  updateTitle();
159 
160  emit extentChanged( outputExtent() );
161 }
162 
163 
164 void QgsExtentGroupBox::updateTitle()
165 {
166  QString msg;
167  switch ( mExtentState )
168  {
169  case OriginalExtent:
170  msg = tr( "layer" );
171  break;
172  case CurrentExtent:
173  msg = tr( "map view" );
174  break;
175  case UserExtent:
176  msg = tr( "user defined" );
177  break;
178  case ProjectLayerExtent:
179  msg = mExtentLayerName;
180  break;
181  case DrawOnCanvas:
182  msg = tr( "drawn on canvas" );
183  break;
184  }
185  if ( isCheckable() && !isChecked() )
186  msg = tr( "none" );
187  msg = tr( "%1 (current: %2)" ).arg( mTitleBase, msg );
188 
189  setTitle( msg );
190 }
191 
192 void QgsExtentGroupBox::layerMenuAboutToShow()
193 {
194  qDeleteAll( mMenuActions );
195  mMenuActions.clear();
196  mLayerMenu->clear();
197  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
198  {
199  QModelIndex index = mMapLayerModel->index( i, 0 );
200  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
201  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
202  QAction *act = new QAction( icon, text, mLayerMenu );
203  act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
204  QString layerId = mMapLayerModel->data( index, QgsMapLayerModel::LayerIdRole ).toString();
205  if ( mExtentState == ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
206  {
207  act->setCheckable( true );
208  act->setChecked( true );
209  }
210  connect( act, &QAction::triggered, this, [this, layerId]
211  {
212  setExtentToLayerExtent( layerId );
213  } );
214  mLayerMenu->addAction( act );
215  mMenuActions << act;
216  }
217 }
218 
219 void QgsExtentGroupBox::setExtentToLayerExtent( const QString &layerId )
220 {
221  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
222  if ( !layer )
223  return;
224 
225  setOutputExtentFromLayer( layer );
226 }
227 
229 {
230  if ( mCanvas )
231  {
232  // Use unrotated visible extent to insure output size and scale matches canvas
233  QgsMapSettings ms = mCanvas->mapSettings();
234  ms.setRotation( 0 );
235  setOutputExtent( ms.visibleExtent(), ms.destinationCrs(), CurrentExtent );
236  }
237  else
238  {
239  setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
240  }
241 }
242 
243 
245 {
246  setOutputExtent( mOriginalExtent, mOriginalCrs, OriginalExtent );
247 }
248 
250 {
251  setOutputExtent( extent, crs, UserExtent );
252 }
253 
255 {
256  if ( !layer )
257  return;
258 
259  mExtentLayer = layer;
260  mExtentLayerName = layer->name();
261 
262  setOutputExtent( layer->extent(), layer->crs(), ProjectLayerExtent );
263 }
264 
266 {
267  if ( mCanvas )
268  {
269  mMapToolPrevious = mCanvas->mapTool();
270  if ( !mMapToolExtent )
271  {
272  mMapToolExtent.reset( new QgsMapToolExtent( mCanvas ) );
273  connect( mMapToolExtent.get(), &QgsMapToolExtent::extentChanged, this, &QgsExtentGroupBox::extentDrawn );
274  connect( mMapToolExtent.get(), &QgsMapTool::deactivated, this, [ = ]
275  {
276  window()->setVisible( true );
277  mMapToolPrevious = nullptr;
278  } );
279  }
280  mMapToolExtent->setRatio( mRatio );
281  mCanvas->setMapTool( mMapToolExtent.get() );
282  window()->setVisible( false );
283  }
284 }
285 
286 void QgsExtentGroupBox::extentDrawn( const QgsRectangle &extent )
287 {
288  setOutputExtent( extent, mCanvas->mapSettings().destinationCrs(), DrawOnCanvas );
289  mCanvas->setMapTool( mMapToolPrevious );
290  window()->setVisible( true );
291  mMapToolPrevious = nullptr;
292 }
293 
294 void QgsExtentGroupBox::groupBoxClicked()
295 {
296  if ( !isCheckable() )
297  return;
298 
299  updateTitle();
300 
301  // output extent just went from null to something (or vice versa)
302  emit extentChanged( outputExtent() );
303 }
304 
305 
307 {
308  if ( isCheckable() && !isChecked() )
309  return QgsRectangle();
310 
311  return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(),
312  mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
313 }
314 
315 void QgsExtentGroupBox::setTitleBase( const QString &title )
316 {
317  mTitleBase = title;
318  updateTitle();
319 }
320 
321 QString QgsExtentGroupBox::titleBase() const
322 {
323  return mTitleBase;
324 }
325 
327 {
328  if ( canvas )
329  {
330  mCanvas = canvas;
331  mButtonDrawOnCanvas->setVisible( true );
332  }
333  else
334  {
335  mButtonDrawOnCanvas->setVisible( false );
336  }
337 }
Extent manually entered/modified by the user.
A rectangle specified with double values.
Definition: qgsrectangle.h:38
Base class for all map layer types.
Definition: qgsmaplayer.h:54
QgsRectangle originalExtent() const
Returns the original extent set for the widget.
static QString printValue(double value)
Print double value with all necessary significant digits.
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.
QgsExtentGroupBox(QWidget *parent=0)
Constructor for QgsExtentGroupBox.
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:73
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.
void setMapTool(QgsMapTool *mapTool)
Sets the map tool currently being used on the canvas.
Extent taken from a rectangled drawn onto the map 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
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.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:111
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:96
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
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:379
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:101
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:106
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QString name
Definition: qgsmaplayer.h:58
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:64
void setOutputExtentFromOriginal()
Sets the output extent to be the same as original extent (may be transformed to output CRS)...
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.