QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  if ( !mMessage.isEmpty() )
174  dlg.setMessage( mMessage );
175  dlg.setCrs( mCrs );
176 
177  if ( optionVisible( QgsProjectionSelectionWidget::CrsOption::CrsNotSet ) )
178  {
179  dlg.setShowNoProjection( true );
180  }
181 
182  if ( dlg.exec() )
183  {
184  mCrsComboBox->blockSignals( true );
185  mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
186  mCrsComboBox->blockSignals( false );
188  setCrs( crs );
189  emit crsChanged( crs );
190  }
191  else
192  {
193  QApplication::restoreOverrideCursor();
194  }
195 }
196 
197 void QgsProjectionSelectionWidget::addNotSetOption()
198 {
199  mCrsComboBox->insertItem( 0, mNotSetText, QgsProjectionSelectionWidget::CrsNotSet );
200  if ( !mCrs.isValid() )
201  whileBlocking( mCrsComboBox )->setCurrentIndex( 0 );
202 }
203 
204 void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
205 {
206  switch ( ( CrsOption )mCrsComboBox->itemData( idx ).toInt() )
207  {
209  emit crsChanged( mLayerCrs );
210  return;
212  emit crsChanged( mProjectCrs );
213  return;
215  emit crsChanged( mCrs );
216  return;
218  emit crsChanged( mDefaultCrs );
219  return;
221  {
222  long srsid = mCrsComboBox->itemData( idx, Qt::UserRole + 1 ).toLongLong();
224  emit crsChanged( crs );
225  return;
226  }
228  emit cleared();
230  return;
231  }
232 }
233 
235 {
236  if ( crs.isValid() )
237  {
240  mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
241  crsOptionText( crs ) );
242  mCrsComboBox->blockSignals( true );
243  mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
244  mCrsComboBox->blockSignals( false );
245  }
246  else
247  {
248  int crsNotSetIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::CrsNotSet );
249  if ( crsNotSetIndex >= 0 )
250  {
251  mCrsComboBox->blockSignals( true );
252  mCrsComboBox->setCurrentIndex( crsNotSetIndex );
253  mCrsComboBox->blockSignals( false );
254  }
255  else
256  {
257  mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
258  crsOptionText( crs ) );
259  }
260  }
261  if ( mCrs != crs )
262  {
263  mCrs = crs;
264  emit crsChanged( crs );
265  }
266 }
267 
269 {
270  int layerItemIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::LayerCrs );
271  if ( crs.isValid() )
272  {
273  if ( layerItemIndex > -1 )
274  {
275  mCrsComboBox->setItemText( layerItemIndex, tr( "Layer CRS: %1 - %2" ).arg( crs.authid(), crs.description() ) );
276  }
277  else
278  {
279  mCrsComboBox->insertItem( firstRecentCrsIndex(), tr( "Layer CRS: %1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::LayerCrs );
280  }
281  }
282  else
283  {
284  if ( layerItemIndex > -1 )
285  {
286  mCrsComboBox->removeItem( layerItemIndex );
287  }
288  }
289  mLayerCrs = crs;
290 }
291 
292 void QgsProjectionSelectionWidget::addProjectCrsOption()
293 {
294  if ( mProjectCrs.isValid() )
295  {
296  mCrsComboBox->addItem( tr( "Project CRS: %1 - %2" ).arg( mProjectCrs.authid(), mProjectCrs.description() ), QgsProjectionSelectionWidget::ProjectCrs );
297  }
298 }
299 
300 void QgsProjectionSelectionWidget::addDefaultCrsOption()
301 {
302  mCrsComboBox->addItem( tr( "Default CRS: %1 - %2" ).arg( mDefaultCrs.authid(), mDefaultCrs.description() ), QgsProjectionSelectionWidget::DefaultCrs );
303 }
304 
305 void QgsProjectionSelectionWidget::addCurrentCrsOption()
306 {
307  int index = optionVisible( CrsNotSet ) ? 1 : 0;
308  mCrsComboBox->insertItem( index, crsOptionText( mCrs ), QgsProjectionSelectionWidget::CurrentCrs );
309 
310 }
311 
313 {
314  if ( crs.isValid() )
315  return tr( "%1 - %2" ).arg( crs.authid(), crs.description() );
316  else
317  return tr( "invalid projection" );
318 }
319 
320 void QgsProjectionSelectionWidget::addRecentCrs()
321 {
322  QStringList recentProjections = QgsCoordinateReferenceSystem::recentProjections();
323  int i = 0;
324  const auto constRecentProjections = recentProjections;
325  for ( const QString &projection : constRecentProjections )
326  {
327  long srsid = projection.toLong();
328 
329  //check if already shown
330  if ( crsIsShown( srsid ) )
331  {
332  continue;
333  }
334 
335  i++;
337  if ( crs.isValid() )
338  {
339  mCrsComboBox->addItem( tr( "%1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::RecentCrs );
340  mCrsComboBox->setItemData( mCrsComboBox->count() - 1, QVariant( ( long long )srsid ), Qt::UserRole + 1 );
341  }
342  if ( i >= 4 )
343  {
344  //limit to 4 recent projections to avoid clutter
345  break;
346  }
347  }
348 }
349 
350 bool QgsProjectionSelectionWidget::crsIsShown( const long srsid ) const
351 {
352  return srsid == mLayerCrs.srsid() || srsid == mDefaultCrs.srsid() || srsid == mProjectCrs.srsid();
353 }
354 
355 int QgsProjectionSelectionWidget::firstRecentCrsIndex() const
356 {
357  for ( int i = 0; i < mCrsComboBox->count(); ++i )
358  {
359  if ( ( CrsOption )mCrsComboBox->itemData( i ).toInt() == RecentCrs )
360  {
361  return i;
362  }
363  }
364  return -1;
365 }
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:70
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:227
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
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.