QGIS API Documentation  2.99.0-Master (a411669)
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 {
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 
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 
75 {
76  if ( mOutputCrs != outputCrs )
77  {
78  switch ( mExtentState )
79  {
80  case CurrentExtent:
81  mOutputCrs = outputCrs;
83  break;
84 
85  case OriginalExtent:
86  mOutputCrs = outputCrs;
88  break;
89 
90  case ProjectLayerExtent:
91  mOutputCrs = outputCrs;
92  setOutputExtentFromLayer( mExtentLayer.data() );
93  break;
94 
95  case DrawOnCanvas:
96  mOutputCrs = outputCrs;
97  extentDrawn( outputExtent() );
98  break;
99 
100  case UserExtent:
101  try
102  {
103  QgsCoordinateTransform ct( mOutputCrs, outputCrs );
105  mOutputCrs = outputCrs;
106  setOutputExtentFromUser( extent, outputCrs );
107  }
108  catch ( QgsCsException & )
109  {
110  // can't reproject
111  mOutputCrs = outputCrs;
112  }
113  break;
114  }
115 
116  }
117 
118 }
119 
120 void QgsExtentGroupBox::setOutputExtent( const QgsRectangle &r, const QgsCoordinateReferenceSystem &srcCrs, ExtentState state )
121 {
122  QgsRectangle extent;
123  if ( mOutputCrs == srcCrs )
124  {
125  extent = r;
126  }
127  else
128  {
129  try
130  {
131  QgsCoordinateTransform ct( srcCrs, mOutputCrs );
132  extent = ct.transformBoundingBox( r );
133  }
134  catch ( QgsCsException & )
135  {
136  // can't reproject
137  extent = r;
138  }
139  }
140 
141  mXMinLineEdit->setText( QgsRasterBlock::printValue( extent.xMinimum() ) );
142  mXMaxLineEdit->setText( QgsRasterBlock::printValue( extent.xMaximum() ) );
143  mYMinLineEdit->setText( QgsRasterBlock::printValue( extent.yMinimum() ) );
144  mYMaxLineEdit->setText( QgsRasterBlock::printValue( extent.yMaximum() ) );
145 
146  mExtentState = state;
147 
148  if ( isCheckable() && !isChecked() )
149  setChecked( true );
150 
151  updateTitle();
152 
153  emit extentChanged( extent );
154 }
155 
156 
157 void QgsExtentGroupBox::setOutputExtentFromLineEdit()
158 {
159  mExtentState = UserExtent;
160 
161  updateTitle();
162 
163  emit extentChanged( outputExtent() );
164 }
165 
166 
167 void QgsExtentGroupBox::updateTitle()
168 {
169  QString msg;
170  switch ( mExtentState )
171  {
172  case OriginalExtent:
173  msg = tr( "layer" );
174  break;
175  case CurrentExtent:
176  msg = tr( "map view" );
177  break;
178  case UserExtent:
179  msg = tr( "user defined" );
180  break;
181  case ProjectLayerExtent:
182  msg = mExtentLayerName;
183  break;
184  case DrawOnCanvas:
185  msg = tr( "drawn on canvas" );
186  break;
187  }
188  if ( isCheckable() && !isChecked() )
189  msg = tr( "none" );
190  msg = tr( "%1 (current: %2)" ).arg( mTitleBase, msg );
191 
192  setTitle( msg );
193 }
194 
195 void QgsExtentGroupBox::layerMenuAboutToShow()
196 {
197  qDeleteAll( mMenuActions );
198  mMenuActions.clear();
199  mLayerMenu->clear();
200  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
201  {
202  QModelIndex index = mMapLayerModel->index( i, 0 );
203  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
204  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
205  QAction *act = new QAction( icon, text, mLayerMenu );
206  act->setToolTip( mMapLayerModel->data( index, Qt::ToolTipRole ).toString() );
207  QString layerId = mMapLayerModel->data( index, QgsMapLayerModel::LayerIdRole ).toString();
208  if ( mExtentState == ProjectLayerExtent && mExtentLayer && mExtentLayer->id() == layerId )
209  {
210  act->setCheckable( true );
211  act->setChecked( true );
212  }
213  connect( act, &QAction::triggered, this, [this, layerId]
214  {
215  setExtentToLayerExtent( layerId );
216  } );
217  mLayerMenu->addAction( act );
218  mMenuActions << act;
219  }
220 }
221 
222 void QgsExtentGroupBox::setExtentToLayerExtent( const QString &layerId )
223 {
224  QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
225  if ( !layer )
226  return;
227 
228  setOutputExtentFromLayer( layer );
229 }
230 
232 {
233  if ( mCanvas )
234  {
235  // Use unrotated visible extent to insure output size and scale matches canvas
236  QgsMapSettings ms = mCanvas->mapSettings();
237  ms.setRotation( 0 );
238  setOutputExtent( ms.visibleExtent(), ms.destinationCrs(), CurrentExtent );
239  }
240  else
241  {
242  setOutputExtent( mCurrentExtent, mCurrentCrs, CurrentExtent );
243  }
244 }
245 
246 
248 {
249  setOutputExtent( mOriginalExtent, mOriginalCrs, OriginalExtent );
250 }
251 
253 {
254  setOutputExtent( extent, crs, UserExtent );
255 }
256 
258 {
259  if ( !layer )
260  return;
261 
262  mExtentLayer = layer;
263  mExtentLayerName = layer->name();
264 
265  setOutputExtent( layer->extent(), layer->crs(), ProjectLayerExtent );
266 }
267 
269 {
270  if ( mCanvas )
271  {
272  mMapToolPrevious = mCanvas->mapTool();
273  if ( !mMapToolExtent )
274  {
275  mMapToolExtent.reset( new QgsMapToolExtent( mCanvas ) );
276  connect( mMapToolExtent.get(), &QgsMapToolExtent::extentChanged, this, &QgsExtentGroupBox::extentDrawn );
277  connect( mMapToolExtent.get(), &QgsMapTool::deactivated, this, [ = ]
278  {
279  window()->setVisible( true );
280  mMapToolPrevious = nullptr;
281  } );
282  }
283  mMapToolExtent->setRatio( mRatio );
284  mCanvas->setMapTool( mMapToolExtent.get() );
285  window()->setVisible( false );
286  }
287 }
288 
289 void QgsExtentGroupBox::extentDrawn( const QgsRectangle &extent )
290 {
291  setOutputExtent( extent, mCanvas->mapSettings().destinationCrs(), DrawOnCanvas );
292  mCanvas->setMapTool( mMapToolPrevious );
293  window()->setVisible( true );
294  mMapToolPrevious = nullptr;
295 }
296 
297 void QgsExtentGroupBox::groupBoxClicked()
298 {
299  if ( !isCheckable() )
300  return;
301 
302  updateTitle();
303 
304  // output extent just went from null to something (or vice versa)
305  emit extentChanged( outputExtent() );
306 }
307 
308 
310 {
311  if ( isCheckable() && !isChecked() )
312  return QgsRectangle();
313 
314  return QgsRectangle( mXMinLineEdit->text().toDouble(), mYMinLineEdit->text().toDouble(),
315  mXMaxLineEdit->text().toDouble(), mYMaxLineEdit->text().toDouble() );
316 }
317 
318 void QgsExtentGroupBox::setTitleBase( const QString &title )
319 {
320  mTitleBase = title;
321  updateTitle();
322 }
323 
324 QString QgsExtentGroupBox::titleBase() const
325 {
326  return mTitleBase;
327 }
328 
330 {
331  if ( canvas )
332  {
333  mCanvas = canvas;
334  mButtonDrawOnCanvas->setVisible( true );
335  }
336  else
337  {
338  mButtonDrawOnCanvas->setVisible( false );
339  }
340 }
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.
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: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.
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:119
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:104
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:109
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:114
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:66
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.