QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsprojectionselectionwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprojectionselectionwidget.cpp
3  --------------------------------------
4  Date : 05.01.2015
5  Copyright : (C) 2015 Denis Rouzaud
6  Email : [email protected]
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 <QHBoxLayout>
17 
19 #include "qgsapplication.h"
21 #include "qgsproject.h"
22 #include "qgssettings.h"
23 
25  : QWidget( parent )
26 {
27 
28 
29  QHBoxLayout *layout = new QHBoxLayout();
30  layout->setContentsMargins( 0, 0, 0, 0 );
31  layout->setSpacing( 6 );
32  setLayout( layout );
33 
34  mCrsComboBox = new QComboBox( this );
35  mCrsComboBox->addItem( tr( "invalid projection" ), QgsProjectionSelectionWidget::CurrentCrs );
36  mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
37 
38  mProjectCrs = QgsProject::instance()->crs();
39  addProjectCrsOption();
40 
41  QgsSettings settings;
42  mDefaultCrs = QgsCoordinateReferenceSystem( settings.value( QStringLiteral( "/projections/defaultProjectCrs" ), GEO_EPSG_CRS_AUTHID, QgsSettings::App ).toString() );
43  if ( mDefaultCrs.authid() != mProjectCrs.authid() )
44  {
45  //only show default CRS option if it's different to the project CRS, avoids
46  //needlessly cluttering the widget
47  addDefaultCrsOption();
48  }
49 
50  addRecentCrs();
51 
52  layout->addWidget( mCrsComboBox );
53 
54  mButton = new QToolButton( this );
55  mButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionSetProjection.svg" ) ) );
56  mButton->setToolTip( tr( "Select CRS" ) );
57  layout->addWidget( mButton );
58 
59  setFocusPolicy( Qt::StrongFocus );
60  setFocusProxy( mButton );
61 
62  connect( mButton, &QToolButton::clicked, this, &QgsProjectionSelectionWidget::selectCrs );
63  connect( mCrsComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsProjectionSelectionWidget::comboIndexChanged );
64 }
65 
67 {
68  switch ( ( CrsOption )mCrsComboBox->currentData().toInt() )
69  {
71  return mLayerCrs;
73  return mProjectCrs;
75  return mDefaultCrs;
77  return mCrs;
79  {
80  long srsid = mCrsComboBox->currentData( Qt::UserRole + 1 ).toLongLong();
82  return crs;
83  }
86  }
87  return mCrs;
88 }
89 
91 {
92  int optionIndex = mCrsComboBox->findData( option );
93 
94  if ( visible && optionIndex < 0 )
95  {
96  //add missing CRS option
97  switch ( option )
98  {
100  {
101  setLayerCrs( mLayerCrs );
102  return;
103  }
105  {
106  addProjectCrsOption();
107  return;
108  }
110  {
111  addDefaultCrsOption();
112  return;
113  }
115  {
116  addCurrentCrsOption();
117  return;
118  }
120  //recently used CRS option cannot be readded
121  return;
123  {
124  addNotSetOption();
125 
126  if ( optionVisible( CurrentCrs ) && !mCrs.isValid() )
127  {
128  // hide invalid option if not set option is shown
129  setOptionVisible( CurrentCrs, false );
130  }
131 
132  return;
133  }
134  }
135  }
136  else if ( !visible && optionIndex >= 0 )
137  {
138  //remove CRS option
139  mCrsComboBox->removeItem( optionIndex );
140 
141  if ( option == CrsNotSet )
142  {
143  setOptionVisible( CurrentCrs, true );
144  }
145  }
146 }
147 
149 {
150  mNotSetText = text;
151  int optionIndex = mCrsComboBox->findData( CrsNotSet );
152  if ( optionIndex >= 0 )
153  {
154  mCrsComboBox->setItemText( optionIndex, mNotSetText );
155  }
156 }
157 
158 void QgsProjectionSelectionWidget::setMessage( const QString &text )
159 {
160  mMessage = text;
161 }
162 
164 {
165  int optionIndex = mCrsComboBox->findData( option );
166  return optionIndex >= 0;
167 }
168 
170 {
171  //find out crs id of current proj4 string
172  QgsProjectionSelectionDialog dlg( this );
173  dlg.setMessage( mMessage );
174  dlg.setCrs( mCrs );
175 
176  if ( optionVisible( QgsProjectionSelectionWidget::CrsOption::CrsNotSet ) )
177  {
178  dlg.setShowNoProjection( true );
179  }
180 
181  if ( dlg.exec() )
182  {
183  mCrsComboBox->blockSignals( true );
184  mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
185  mCrsComboBox->blockSignals( false );
187  setCrs( crs );
188  emit crsChanged( crs );
189  }
190  else
191  {
192  QApplication::restoreOverrideCursor();
193  }
194 }
195 
196 void QgsProjectionSelectionWidget::addNotSetOption()
197 {
198  mCrsComboBox->insertItem( 0, mNotSetText, QgsProjectionSelectionWidget::CrsNotSet );
199  if ( !mCrs.isValid() )
200  whileBlocking( mCrsComboBox )->setCurrentIndex( 0 );
201 }
202 
203 void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
204 {
205  switch ( ( CrsOption )mCrsComboBox->itemData( idx ).toInt() )
206  {
208  emit crsChanged( mLayerCrs );
209  return;
211  emit crsChanged( mProjectCrs );
212  return;
214  emit crsChanged( mCrs );
215  return;
217  emit crsChanged( mDefaultCrs );
218  return;
220  {
221  long srsid = mCrsComboBox->itemData( idx, Qt::UserRole + 1 ).toLongLong();
223  emit crsChanged( crs );
224  return;
225  }
227  emit cleared();
229  return;
230  }
231 }
232 
234 {
235  if ( crs.isValid() )
236  {
239  mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
240  crsOptionText( crs ) );
241  mCrsComboBox->blockSignals( true );
242  mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
243  mCrsComboBox->blockSignals( false );
244  }
245  else
246  {
247  int crsNotSetIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::CrsNotSet );
248  if ( crsNotSetIndex >= 0 )
249  {
250  mCrsComboBox->blockSignals( true );
251  mCrsComboBox->setCurrentIndex( crsNotSetIndex );
252  mCrsComboBox->blockSignals( false );
253  }
254  else
255  {
256  mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
257  crsOptionText( crs ) );
258  }
259  }
260  if ( mCrs != crs )
261  {
262  mCrs = crs;
263  emit crsChanged( crs );
264  }
265 }
266 
268 {
269  int layerItemIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::LayerCrs );
270  if ( crs.isValid() )
271  {
272  if ( layerItemIndex > -1 )
273  {
274  mCrsComboBox->setItemText( layerItemIndex, tr( "Layer CRS: %1 - %2" ).arg( crs.authid(), crs.description() ) );
275  }
276  else
277  {
278  mCrsComboBox->insertItem( firstRecentCrsIndex(), tr( "Layer CRS: %1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::LayerCrs );
279  }
280  }
281  else
282  {
283  if ( layerItemIndex > -1 )
284  {
285  mCrsComboBox->removeItem( layerItemIndex );
286  }
287  }
288  mLayerCrs = crs;
289 }
290 
291 void QgsProjectionSelectionWidget::addProjectCrsOption()
292 {
293  if ( mProjectCrs.isValid() )
294  {
295  mCrsComboBox->addItem( tr( "Project CRS: %1 - %2" ).arg( mProjectCrs.authid(), mProjectCrs.description() ), QgsProjectionSelectionWidget::ProjectCrs );
296  }
297 }
298 
299 void QgsProjectionSelectionWidget::addDefaultCrsOption()
300 {
301  mCrsComboBox->addItem( tr( "Default CRS: %1 - %2" ).arg( mDefaultCrs.authid(), mDefaultCrs.description() ), QgsProjectionSelectionWidget::DefaultCrs );
302 }
303 
304 void QgsProjectionSelectionWidget::addCurrentCrsOption()
305 {
306  int index = optionVisible( CrsNotSet ) ? 1 : 0;
307  mCrsComboBox->insertItem( index, crsOptionText( mCrs ), QgsProjectionSelectionWidget::CurrentCrs );
308 
309 }
310 
312 {
313  if ( crs.isValid() )
314  return tr( "%1 - %2" ).arg( crs.authid(), crs.description() );
315  else
316  return tr( "invalid projection" );
317 }
318 
319 void QgsProjectionSelectionWidget::addRecentCrs()
320 {
321  QStringList recentProjections = QgsCoordinateReferenceSystem::recentProjections();
322  int i = 0;
323  const auto constRecentProjections = recentProjections;
324  for ( const QString &projection : constRecentProjections )
325  {
326  long srsid = projection.toLong();
327 
328  //check if already shown
329  if ( crsIsShown( srsid ) )
330  {
331  continue;
332  }
333 
334  i++;
336  if ( crs.isValid() )
337  {
338  mCrsComboBox->addItem( tr( "%1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::RecentCrs );
339  mCrsComboBox->setItemData( mCrsComboBox->count() - 1, QVariant( ( long long )srsid ), Qt::UserRole + 1 );
340  }
341  if ( i >= 4 )
342  {
343  //limit to 4 recent projections to avoid clutter
344  break;
345  }
346  }
347 }
348 
349 bool QgsProjectionSelectionWidget::crsIsShown( const long srsid ) const
350 {
351  return srsid == mLayerCrs.srsid() || srsid == mDefaultCrs.srsid() || srsid == mProjectCrs.srsid();
352 }
353 
354 int QgsProjectionSelectionWidget::firstRecentCrsIndex() const
355 {
356  for ( int i = 0; i < mCrsComboBox->count(); ++i )
357  {
358  if ( ( CrsOption )mCrsComboBox->itemData( i ).toInt() == RecentCrs )
359  {
360  return i;
361  }
362  }
363  return -1;
364 }
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the current CRS for the widget.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Current project CRS (if OTF reprojection enabled)
void setMessage(const QString &message)
Sets a message to show in the dialog.
void setNotSetText(const QString &text)
Sets the text to show for the not set option.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void setShowNoProjection(bool show)
Sets whether a "no/invalid" projection option should be shown.
QgsProjectionSelectionWidget(QWidget *parent=nullptr)
Constructor for QgsProjectionSelectionWidget.
QgsCoordinateReferenceSystem crs() const
Returns the CRS currently selected in the widget.
A generic dialog to prompt the user for a Coordinate Reference System.
QgsCoordinateReferenceSystem crs() const
Returns the currently selected CRS for the widget.
CrsOption
Predefined CRS options shown in widget.
static QString crsOptionText(const QgsCoordinateReferenceSystem &crs)
Returns display text for the specified crs.
void selectCrs()
Opens the dialog for selecting a new CRS.
static QStringList recentProjections()
Returns a list of recently used projections.
void setMessage(const QString &text)
Sets a message to show in the dialog.
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:95
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
Definition: qgis.cpp:69
void cleared()
Emitted when the not set option is selected.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the initial crs to show within the dialog.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:212
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:438
This class represents a coordinate reference system (CRS).
long srsid() const
Returns the internal CRS ID, if available.
bool optionVisible(CrsOption option) const
Returns whether the specified CRS option is visible in the widget.
void setOptionVisible(CrsOption option, bool visible)
Sets whether a predefined CRS option should be shown in the widget.
QString authid() const
Returns the authority identifier for the CRS.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
void setLayerCrs(const QgsCoordinateReferenceSystem &crs)
Sets the layer CRS for the widget.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.