QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsprojectionselectiontreewidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * qgsprojectionselector.cpp *
3  * Copyright (C) 2005 by Tim Sutton *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License as published by *
8  * the Free Software Foundation; either version 2 of the License, or *
9  * (at your option) any later version. *
10  ***************************************************************************/
12 
13 //standard includes
14 #include <sqlite3.h>
15 
16 //qgis includes
17 #include "qgis.h" //magic numbers here
18 #include "qgsapplication.h"
19 #include "qgslogger.h"
21 #include "qgsmessagelog.h"
22 #include "qgssettings.h"
23 #include "qgsrectangle.h"
25 #include "qgsdatums.h"
26 #include "qgsprojoperation.h"
27 #include "qgsstringutils.h"
28 
29 //qt includes
30 #include <QFileInfo>
31 #include <QHeaderView>
32 #include <QResizeEvent>
33 #include <QMessageBox>
34 #include <QRegularExpression>
35 
37  : QWidget( parent )
38 {
39  setupUi( this );
40 
41  QFont f = teProjection->font();
42  f.setPointSize( f.pointSize() - 2 );
43  teProjection->setFont( f );
44 
45  leSearch->setShowSearchIcon( true );
46 
47  connect( lstCoordinateSystems, &QTreeWidget::itemDoubleClicked, this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystems_itemDoubleClicked );
48  connect( lstRecent, &QTreeWidget::itemDoubleClicked, this, &QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked );
49  connect( lstCoordinateSystems, &QTreeWidget::currentItemChanged, this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystems_currentItemChanged );
50  connect( lstRecent, &QTreeWidget::currentItemChanged, this, &QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged );
51  connect( cbxHideDeprecated, &QCheckBox::stateChanged, this, &QgsProjectionSelectionTreeWidget::updateFilter );
52  connect( leSearch, &QgsFilterLineEdit::textChanged, this, &QgsProjectionSelectionTreeWidget::updateFilter );
53 
54  mAreaCanvas->setVisible( mShowMap );
55 
56  // Get the full path name to the sqlite3 spatial reference database.
57  mSrsDatabaseFileName = QgsApplication::srsDatabaseFilePath();
58 
59  lstCoordinateSystems->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
60  lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );
61  lstCoordinateSystems->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
62 
63  // Hide (internal) ID column
64  lstCoordinateSystems->setColumnHidden( QgisCrsIdColumn, true );
65 
66  lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
67  lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
68  lstRecent->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
69 
70  // Hide (internal) ID column
71  lstRecent->setColumnHidden( QgisCrsIdColumn, true );
72 
74 
75  mCheckBoxNoProjection->setHidden( true );
76  mCheckBoxNoProjection->setEnabled( false );
77  connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]
78  {
79  if ( !mBlockSignals )
80  {
81  emit crsSelected();
83  }
84  } );
85  connect( mCheckBoxNoProjection, &QCheckBox::toggled, this, [ = ]( bool checked )
86  {
87  if ( mCheckBoxNoProjection->isEnabled() )
88  {
89  mFrameProjections->setDisabled( checked );
90  }
91  } );
92 
93  QgsSettings settings;
94  mSplitter->restoreState( settings.value( QStringLiteral( "Windows/ProjectionSelector/splitterState" ) ).toByteArray() );
95 }
96 
98 {
99  QgsSettings settings;
100  settings.setValue( QStringLiteral( "Windows/ProjectionSelector/splitterState" ), mSplitter->saveState() );
101 
102  // Push current projection to front, only if set
103  const QgsCoordinateReferenceSystem selectedCrs = crs();
104  if ( selectedCrs.isValid() )
106 }
107 
109 {
110  lstCoordinateSystems->header()->resizeSection( NameColumn, event->size().width() - 240 );
111  lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
112  lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );
113 
114  lstRecent->header()->resizeSection( NameColumn, event->size().width() - 240 );
115  lstRecent->header()->resizeSection( AuthidColumn, 240 );
116  lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
117 }
118 
120 {
121  if ( mInitialized )
122  return;
123 
124  // ensure the projection list view is actually populated
125  // before we show this widget
126  loadCrsList( &mCrsFilter );
127  loadUserCrsList( &mCrsFilter );
128 
129  if ( !mRecentProjListDone )
130  {
131  for ( const QgsCoordinateReferenceSystem &crs : std::as_const( mRecentProjections ) )
132  insertRecent( crs );
133  mRecentProjListDone = true;
134  }
135 
136  // apply deferred selection
137  mBlockSignals = true; // we've already emitted the signal, when the deferred crs was first set
138  applySelection();
139  mBlockSignals = false;
140 
141  emit initialized();
142 
143  // Pass up the inheritance hierarchy
144  QWidget::showEvent( event );
145  mInitialized = true;
146 }
147 
148 QString QgsProjectionSelectionTreeWidget::ogcWmsCrsFilterAsSqlExpression( QSet<QString> *crsFilter )
149 {
150  QString sqlExpression = QStringLiteral( "1" ); // it's "SQL" for "true"
151  QMap<QString, QStringList> authParts;
152 
153  if ( !crsFilter )
154  return sqlExpression;
155 
156  /*
157  Ref: WMS 1.3.0, section 6.7.3 "Layer CRS":
158 
159  Every Layer CRS has an identifier that is a character string. Two types of
160  Layer CRS identifiers are permitted: "label" and "URL" identifiers:
161 
162  Label: The identifier includes a namespace prefix, a colon, a numeric or
163  string code, and in some instances a comma followed by additional
164  parameters. This International Standard defines three namespaces:
165  CRS, EpsgCrsId and AUTO2 [...]
166 
167  URL: The identifier is a fully-qualified Uniform Resource Locator that
168  references a publicly-accessible file containing a definition of the CRS
169  that is compliant with ISO 19111.
170  */
171 
172  // iterate through all incoming CRSs
173 
174  const auto authIds { *crsFilter };
175  for ( const QString &auth_id : authIds )
176  {
177  QStringList parts = auth_id.split( ':' );
178 
179  if ( parts.size() < 2 )
180  continue;
181 
182  authParts[ parts.at( 0 ).toUpper()].append( parts.at( 1 ).toUpper() );
183  }
184 
185  if ( authParts.isEmpty() )
186  return sqlExpression;
187 
188  if ( !authParts.isEmpty() )
189  {
190  QString prefix = QStringLiteral( " AND (" );
191  for ( auto it = authParts.constBegin(); it != authParts.constEnd(); ++it )
192  {
193  sqlExpression += QStringLiteral( "%1(upper(auth_name)='%2' AND upper(auth_id) IN ('%3'))" )
194  .arg( prefix,
195  it.key(),
196  it.value().join( QLatin1String( "','" ) ) );
197  prefix = QStringLiteral( " OR " );
198  }
199  sqlExpression += ')';
200  }
201 
202  QgsDebugMsgLevel( "exiting with '" + sqlExpression + "'.", 4 );
203 
204  return sqlExpression;
205 }
206 
207 void QgsProjectionSelectionTreeWidget::applySelection( int column, QString value )
208 {
209  if ( !mProjListDone || !mUserProjListDone )
210  {
211  // defer selection until loaded
212  mSearchColumn = column;
213  mSearchValue = value;
214  return;
215  }
216 
217  if ( column == QgsProjectionSelectionTreeWidget::None )
218  {
219  // invoked deferred selection
220  column = mSearchColumn;
221  value = mSearchValue;
222 
223  mSearchColumn = QgsProjectionSelectionTreeWidget::None;
224  mSearchValue.clear();
225  }
226 
227  if ( column == QgsProjectionSelectionTreeWidget::None )
228  return;
229 
230  QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( value, Qt::MatchExactly | Qt::MatchRecursive, column );
231  if ( !nodes.isEmpty() )
232  {
233  QgsDebugMsgLevel( QStringLiteral( "found %1,%2" ).arg( column ).arg( value ), 4 );
234  lstCoordinateSystems->setCurrentItem( nodes.first() );
235  }
236  else
237  {
238  QgsDebugMsgLevel( QStringLiteral( "nothing found for %1,%2" ).arg( column ).arg( value ), 4 );
239  // deselect the selected item to avoid confusing the user
240  lstCoordinateSystems->clearSelection();
241  lstRecent->clearSelection();
242  teProjection->clear();
243  }
244 }
245 
246 void QgsProjectionSelectionTreeWidget::insertRecent( const QgsCoordinateReferenceSystem &crs )
247 {
248  if ( !mProjListDone || !mUserProjListDone )
249  return;
250 
251  QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( QString::number( crs.srsid() ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
252  if ( nodes.isEmpty() )
253  return;
254 
255  lstRecent->insertTopLevelItem( 0, new QTreeWidgetItem( lstRecent, QStringList()
256  << nodes.first()->text( NameColumn )
257  << nodes.first()->text( AuthidColumn )
258  << nodes.first()->text( QgisCrsIdColumn ) ) );
259 }
260 
261 //note this line just returns the projection name!
262 QString QgsProjectionSelectionTreeWidget::selectedName()
263 {
264  // return the selected wkt name from the list view
265  QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
266  return lvi ? lvi->text( NameColumn ) : QString();
267 }
268 
270 {
271  if ( !crs.isValid() )
272  {
273  mCheckBoxNoProjection->setChecked( true );
274  }
275  else
276  {
277  bool changed = false;
278  if ( !mInitialized )
279  {
280  changed = mDeferredLoadCrs != crs;
281  mDeferredLoadCrs = crs;
282  }
283  mBlockSignals = true;
284  mCheckBoxNoProjection->setChecked( false );
285  mBlockSignals = false;
286 
287  if ( !crs.authid().isEmpty() )
288  applySelection( AuthidColumn, crs.authid() );
289  else
290  loadUnknownCrs( crs );
291  if ( changed )
292  {
293  emit crsSelected();
295  }
296  }
297 }
298 
300 {
301  mAreaCanvas->setCanvasRect( rect );
302 }
303 
305 {
306  return mAreaCanvas->canvasRect();
307 }
308 
309 QString QgsProjectionSelectionTreeWidget::getSelectedExpression( const QString &expression ) const
310 {
311  // Only return the attribute if there is a node in the tree
312  // selected that has an srs_id. This prevents error if the user
313  // selects a top-level node rather than an actual coordinate
314  // system
315  //
316  // Get the selected node and make sure it is a srs andx
317  // not a top-level projection node
318  QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
319  if ( !lvi || lvi->text( QgisCrsIdColumn ).isEmpty() )
320  return QString();
321 
322  //
323  // Determine if this is a user projection or a system on
324  // user projection defs all have srs_id >= 100000
325  //
326  QString databaseFileName;
327  if ( lvi->text( QgisCrsIdColumn ).toLong() >= USER_CRS_START_ID )
328  {
329  databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
330  if ( !QFileInfo::exists( databaseFileName ) )
331  {
332  return QString();
333  }
334  }
335  else
336  {
337  databaseFileName = mSrsDatabaseFileName;
338  }
339 
340  //
341  // set up the database
342  // XXX We could probably hold the database open for the life of this object,
343  // assuming that it will never be used anywhere else. Given the low overhead,
344  // opening it each time seems to be a reasonable approach at this time.
345  sqlite3 *database = nullptr;
346  int rc = sqlite3_open_v2( databaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
347  if ( rc )
348  {
349  QgsMessageLog::logMessage( tr( "Resource Location Error" ), tr( "Error reading database file from: \n %1\n"
350  "Because of this the projection selector will not work…" ).arg( databaseFileName ),
351  Qgis::MessageLevel::Critical );
352  return QString();
353  }
354 
355  // prepare the sql statement
356  const char *tail = nullptr;
357  sqlite3_stmt *stmt = nullptr;
358  QString sql = QStringLiteral( "select %1 from tbl_srs where srs_id=%2" )
359  .arg( expression,
360  lvi->text( QgisCrsIdColumn ) );
361 
362  QgsDebugMsgLevel( QStringLiteral( "Finding selected attribute using : %1" ).arg( sql ), 4 );
363  rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
364  // XXX Need to free memory from the error msg if one is set
365  QString attributeValue;
366  if ( rc == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
367  {
368  // get the first row of the result set
369  attributeValue = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
370  }
371 
372  // close the statement
373  sqlite3_finalize( stmt );
374  // close the database
375  sqlite3_close( database );
376 
377  // return the srs
378  return attributeValue;
379 }
380 
382 {
383  if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
385 
386  if ( !mInitialized && mDeferredLoadCrs.isValid() )
387  return mDeferredLoadCrs;
388 
389  const QString srsIdString = getSelectedExpression( QStringLiteral( "srs_id" ) );
390  if ( !srsIdString.isEmpty() )
391  {
392  int srid = srsIdString.toLong();
393  if ( srid >= USER_CRS_START_ID )
394  return QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "USER:%1" ).arg( srid ) );
395  else
396  return QgsCoordinateReferenceSystem::fromOgcWmsCrs( getSelectedExpression( QStringLiteral( "upper(auth_name||':'||auth_id)" ) ) );
397  }
398  else
399  {
400  // custom CRS
401  QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
402  if ( lvi && lvi->data( 0, RoleWkt ).isValid() )
403  return QgsCoordinateReferenceSystem::fromWkt( lvi->data( 0, RoleWkt ).toString() );
404  else if ( lvi && lvi->data( 0, RoleProj ).isValid() )
405  return QgsCoordinateReferenceSystem::fromProj( lvi->data( 0, RoleProj ).toString() );
406  else
408  }
409 }
410 
412 {
413  mCheckBoxNoProjection->setVisible( show );
414  mCheckBoxNoProjection->setEnabled( show );
415  if ( show )
416  {
417  mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
418  }
419 }
420 
422 {
423  mShowMap = show;
424  mAreaCanvas->setVisible( show );
425 }
426 
428 {
429  return !mCheckBoxNoProjection->isHidden();
430 }
431 
433 {
434  mCheckBoxNoProjection->setText( text );
435 }
436 
438 {
439  return mShowMap;
440 }
441 
443 {
444  QTreeWidgetItem *item = lstCoordinateSystems->currentItem();
445  if ( mCheckBoxNoProjection->isChecked() )
446  return true;
447  else if ( !mInitialized && mDeferredLoadCrs.isValid() )
448  return true;
449  else
450  return item && ( !item->text( QgisCrsIdColumn ).isEmpty() || item->data( 0, RoleWkt ).isValid() );
451 }
452 
453 long QgsProjectionSelectionTreeWidget::selectedCrsId()
454 {
455  QTreeWidgetItem *item = lstCoordinateSystems->currentItem();
456 
457  if ( item && !item->text( QgisCrsIdColumn ).isEmpty() )
458  return lstCoordinateSystems->currentItem()->text( QgisCrsIdColumn ).toLong();
459  else
460  return 0;
461 }
462 
463 
464 void QgsProjectionSelectionTreeWidget::setOgcWmsCrsFilter( const QSet<QString> &crsFilter )
465 {
466  mCrsFilter = crsFilter;
467  mProjListDone = false;
468  mUserProjListDone = false;
469  lstCoordinateSystems->clear();
470 }
471 
472 void QgsProjectionSelectionTreeWidget::loadUserCrsList( QSet<QString> *crsFilter )
473 {
474  if ( mUserProjListDone )
475  return;
476 
477  QgsDebugMsgLevel( QStringLiteral( "Fetching user projection list..." ), 4 );
478 
479  // User defined coordinate system node
480  // Make in an italic font to distinguish them from real projections
481  mUserProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "User Defined Coordinate Systems" ) ) );
482  mUserProjList->setFlags( mUserProjList->flags() & ~Qt::ItemIsSelectable );
483 
484  QFont fontTemp = mUserProjList->font( 0 );
485  fontTemp.setItalic( true );
486  fontTemp.setBold( true );
487  mUserProjList->setFont( 0, fontTemp );
488  mUserProjList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) ) );
489 
490  const QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> userCrsList = QgsApplication::coordinateReferenceSystemRegistry()->userCrsList();
491  for ( const QgsCoordinateReferenceSystemRegistry::UserCrsDetails &details : userCrsList )
492  {
493  const QString authid = QStringLiteral( "USER:%1" ).arg( details.id );
494  if ( crsFilter && !crsFilter->isEmpty() && !crsFilter->contains( authid ) && !crsFilter->contains( authid.toLower() ) )
495  continue;
496 
497  QTreeWidgetItem *newItem = new QTreeWidgetItem( mUserProjList, QStringList() << details.name );
498  newItem->setText( QgisCrsIdColumn, QString::number( details.id ) );
499  newItem->setText( AuthidColumn, authid );
500  }
501 
502  mUserProjListDone = true;
503 }
504 
505 void QgsProjectionSelectionTreeWidget::loadCrsList( QSet<QString> *crsFilter )
506 {
507  if ( mProjListDone )
508  return;
509 
510  // convert our Coordinate Reference System filter into the SQL expression
511  QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );
512 
513  // Create the top-level nodes for the list view of projections
514  // Make in an italic font to distinguish them from real projections
515  //
516  // Geographic coordinate system node
517  mGeoList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Geographic Coordinate Systems" ) ) );
518  mGeoList->setFlags( mGeoList->flags() & ~Qt::ItemIsSelectable );
519 
520  QFont fontTemp = mGeoList->font( 0 );
521  fontTemp.setItalic( true );
522  fontTemp.setBold( true );
523  mGeoList->setFont( 0, fontTemp );
524  mGeoList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) ) );
525 
526  // Projected coordinate system node
527  mProjList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Projected Coordinate Systems" ) ) );
528  mProjList->setFlags( mProjList->flags() & ~Qt::ItemIsSelectable );
529 
530  fontTemp = mProjList->font( 0 );
531  fontTemp.setItalic( true );
532  fontTemp.setBold( true );
533  mProjList->setFont( 0, fontTemp );
534  mProjList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) ) );
535 
536  //bail out in case the projections db does not exist
537  //this is necessary in case the pc is running linux with a
538  //read only filesystem because otherwise sqlite will try
539  //to create the db file on the fly
540 
541  if ( !QFileInfo::exists( mSrsDatabaseFileName ) )
542  {
543  mProjListDone = true;
544  return;
545  }
546 
547  // open the database containing the spatial reference data
548  sqlite3 *database = nullptr;
549  int rc = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
550  if ( rc )
551  {
552  // XXX This will likely never happen since on open, sqlite creates the
553  // database if it does not exist.
554  showDBMissingWarning( mSrsDatabaseFileName );
555  return;
556  }
557 
558  const char *tail = nullptr;
559  sqlite3_stmt *stmt = nullptr;
560  // Set up the query to retrieve the projection information needed to populate the list
561  //note I am giving the full field names for clarity here and in case someone
562  //changes the underlying view TS
563  QString sql = QStringLiteral( "select description, srs_id, upper(auth_name||':'||auth_id), is_geo, name, parameters, deprecated from vw_srs where %1 order by name,description" )
564  .arg( sqlFilter );
565 
566  rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
567  // XXX Need to free memory from the error msg if one is set
568  if ( rc == SQLITE_OK )
569  {
570  QTreeWidgetItem *newItem = nullptr;
571  // Cache some stuff to speed up creating of the list of projected
572  // spatial reference systems
573  QString previousSrsType;
574  QTreeWidgetItem *previousSrsTypeNode = nullptr;
575 
576  while ( sqlite3_step( stmt ) == SQLITE_ROW )
577  {
578  // check to see if the srs is geographic
579  int isGeo = sqlite3_column_int( stmt, 3 );
580  if ( isGeo )
581  {
582  // this is a geographic coordinate system
583  // Add it to the tree (field 0)
584  newItem = new QTreeWidgetItem( mGeoList, QStringList( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) ) ) );
585 
586  // display the authority name (field 2) in the second column of the list view
587  newItem->setText( AuthidColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 2 ) ) );
588 
589  // display the qgis srs_id (field 1) in the third column of the list view
590  newItem->setText( QgisCrsIdColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ) );
591  }
592  else
593  {
594  // This is a projected srs
595  QTreeWidgetItem *node = nullptr;
596  QString srsType = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 4 ) );
597  if ( srsType.isEmpty() )
598  srsType = tr( "Other" );
599 
600  // Find the node for this type and add the projection to it
601  // If the node doesn't exist, create it
602  if ( srsType == previousSrsType )
603  {
604  node = previousSrsTypeNode;
605  }
606  else
607  {
608  // Different from last one, need to search
609  QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( srsType, Qt::MatchExactly | Qt::MatchRecursive, NameColumn );
610  if ( nodes.isEmpty() )
611  {
612  // the node doesn't exist -- create it
613  // Make in an italic font to distinguish them from real projections
614  node = new QTreeWidgetItem( mProjList, QStringList( srsType ) );
615  node->setFlags( node->flags() & ~Qt::ItemIsSelectable );
616 
617  QFont fontTemp = node->font( 0 );
618  fontTemp.setItalic( true );
619  node->setFont( 0, fontTemp );
620  }
621  else
622  {
623  node = nodes.first();
624  }
625  // Update the cache.
626  previousSrsType = srsType;
627  previousSrsTypeNode = node;
628  }
629  // add the item, setting the projection name in the first column of the list view
630  newItem = new QTreeWidgetItem( node, QStringList( QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) ) ) );
631  // display the authority id (field 2) in the second column of the list view
632  newItem->setText( AuthidColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 2 ) ) );
633  // display the qgis srs_id (field 1) in the third column of the list view
634  newItem->setText( QgisCrsIdColumn, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 1 ) ) );
635  // expand also parent node
636  newItem->parent()->setExpanded( true );
637  }
638 
639  // display the qgis deprecated in the user data of the item
640  newItem->setData( 0, RoleDeprecated, QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 6 ) ) );
641  newItem->setHidden( cbxHideDeprecated->isChecked() );
642  }
643  mProjList->setExpanded( true );
644  }
645 
646  // close the sqlite3 statement
647  sqlite3_finalize( stmt );
648  // close the database
649  sqlite3_close( database );
650 
651  mProjListDone = true;
652 }
653 
654 void QgsProjectionSelectionTreeWidget::loadUnknownCrs( const QgsCoordinateReferenceSystem &crs )
655 {
656  if ( !mUnknownList )
657  {
658  mUnknownList = new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr( "Custom Coordinate Systems" ) ) );
659  mUnknownList->setFlags( mUnknownList->flags() & ~Qt::ItemIsSelectable );
660 
661  QFont fontTemp = mUnknownList->font( 0 );
662  fontTemp.setItalic( true );
663  fontTemp.setBold( true );
664  mUnknownList->setFont( 0, fontTemp );
665  mUnknownList->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) ) );
666  }
667 
668  QTreeWidgetItem *newItem = new QTreeWidgetItem( mUnknownList, QStringList( crs.description().isEmpty() ? QObject::tr( "Custom CRS" ) : crs.description() ) );
669  newItem->setData( 0, RoleWkt, crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) );
670  newItem->setData( 0, RoleProj, crs.toProj() );
671 
672  lstCoordinateSystems->setCurrentItem( newItem );
673 }
674 
675 // New coordinate system selected from the list
676 void QgsProjectionSelectionTreeWidget::lstCoordinateSystems_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem * )
677 {
678  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
679 
680  if ( !current )
681  {
682  QgsDebugMsgLevel( QStringLiteral( "no current item" ), 4 );
683  return;
684  }
685 
686  lstCoordinateSystems->scrollToItem( current );
687 
688  // If the item has children, it's not an end node in the tree, and
689  // hence is just a grouping thingy, not an actual CRS.
690  if ( current->childCount() == 0 )
691  {
692  // Found a real CRS
693  if ( !mBlockSignals )
694  {
695  emit crsSelected();
696  emit hasValidSelectionChanged( true );
697  }
698 
699  updateBoundsPreview();
700 
701  const QString crsId = current->text( QgisCrsIdColumn );
702  if ( !crsId.isEmpty() )
703  {
704  QList<QTreeWidgetItem *> nodes = lstRecent->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly, QgisCrsIdColumn );
705  if ( !nodes.isEmpty() )
706  {
707  QgsDebugMsgLevel( QStringLiteral( "found srs %1 in recent" ).arg( current->text( QgisCrsIdColumn ) ), 4 );
708  lstRecent->setCurrentItem( nodes.first() );
709  }
710  else
711  {
712  QgsDebugMsgLevel( QStringLiteral( "srs %1 not recent" ).arg( current->text( QgisCrsIdColumn ) ), 4 );
713  lstRecent->clearSelection();
714  lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
715  }
716  }
717  else
718  {
719  lstRecent->clearSelection();
720  lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
721  }
722  }
723  else
724  {
725  // Not a CRS - remove the highlight so the user doesn't get too confused
726  current->setSelected( false );
727  teProjection->clear();
728  lstRecent->clearSelection();
729  emit hasValidSelectionChanged( false );
730  }
731 }
732 
733 void QgsProjectionSelectionTreeWidget::lstCoordinateSystems_itemDoubleClicked( QTreeWidgetItem *current, int column )
734 {
735  Q_UNUSED( column )
736 
737  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
738 
739  if ( !current )
740  {
741  QgsDebugMsgLevel( QStringLiteral( "no current item" ), 4 );
742  return;
743  }
744 
745  // If the item has children, it's not an end node in the tree, and
746  // hence is just a grouping thingy, not an actual CRS.
747  if ( current->childCount() == 0 )
749 }
750 
751 void QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem * )
752 {
753  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
754 
755  if ( !current )
756  {
757  QgsDebugMsgLevel( QStringLiteral( "no current item" ), 4 );
758  return;
759  }
760 
761  lstRecent->scrollToItem( current );
762 
763  QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
764  if ( !nodes.isEmpty() )
765  lstCoordinateSystems->setCurrentItem( nodes.first() );
766 }
767 
768 void QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked( QTreeWidgetItem *current, int column )
769 {
770  Q_UNUSED( column )
771 
772  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
773 
774  if ( !current )
775  {
776  QgsDebugMsgLevel( QStringLiteral( "no current item" ), 4 );
777  return;
778  }
779 
780  QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
781  if ( !nodes.isEmpty() )
783 }
784 
785 void QgsProjectionSelectionTreeWidget::updateFilter()
786 {
787  QString filterTxtCopy = QgsStringUtils::qRegExpEscape( leSearch->text() );
788  filterTxtCopy.replace( QRegularExpression( "\\s+" ), QStringLiteral( ".*" ) );
789  const QRegularExpression re( filterTxtCopy, QRegularExpression::PatternOption::CaseInsensitiveOption );
790 
791  const bool hideDeprecated = cbxHideDeprecated->isChecked();
792 
793  auto filterTreeWidget = [ = ]( QTreeWidget * tree )
794  {
795  QTreeWidgetItemIterator itr( tree );
796  while ( *itr )
797  {
798  if ( ( *itr )->childCount() == 0 ) // it's an end node aka a projection
799  {
800  if ( hideDeprecated && ( *itr )->data( 0, RoleDeprecated ).toBool() )
801  {
802  ( *itr )->setHidden( true );
803  if ( ( *itr )->isSelected() )
804  {
805  ( *itr )->setSelected( false );
806  teProjection->clear();
807  }
808  }
809  else if ( ( *itr )->text( NameColumn ).contains( re )
810  || ( *itr )->text( AuthidColumn ).contains( re )
811  )
812  {
813  ( *itr )->setHidden( false );
814  QTreeWidgetItem *parent = ( *itr )->parent();
815  while ( parent )
816  {
817  parent->setExpanded( true );
818  parent->setHidden( false );
819  parent = parent->parent();
820  }
821  }
822  else
823  {
824  ( *itr )->setHidden( true );
825  }
826  }
827  else
828  {
829  ( *itr )->setHidden( true );
830  }
831  ++itr;
832  }
833  };
834 
835  // filter recent crs's
836  filterTreeWidget( lstRecent );
837 
838  // filter crs's
839  filterTreeWidget( lstCoordinateSystems );
840 }
841 
843 {
844 }
845 
846 long QgsProjectionSelectionTreeWidget::getLargestCrsIdMatch( const QString &sql )
847 {
848  long srsId = 0;
849 
850  //
851  // Now perform the actual search
852  //
853 
854  sqlite3 *database = nullptr;
855  const char *tail = nullptr;
856  sqlite3_stmt *stmt = nullptr;
857  int result;
858 
859  // first we search the users db as any srsid there will be definition be greater than in sys db
860 
861  //check the db is available
862  QString databaseFileName = QgsApplication::qgisUserDatabaseFilePath();
863  if ( QFileInfo::exists( databaseFileName ) ) //only bother trying to open if the file exists
864  {
865  result = sqlite3_open_v2( databaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
866  if ( result )
867  {
868  // XXX This will likely never happen since on open, sqlite creates the
869  // database if it does not exist. But we checked earlier for its existence
870  // and aborted in that case. This is because we may be running from read only
871  // media such as live cd and don't want to force trying to create a db.
872  showDBMissingWarning( databaseFileName );
873  return 0;
874  }
875 
876  result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
877  // XXX Need to free memory from the error msg if one is set
878  if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
879  {
880  QString srsIdString = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
881  srsId = srsIdString.toLong();
882  // close the sqlite3 statement
883  sqlite3_finalize( stmt );
884  sqlite3_close( database );
885  return srsId;
886  }
887  }
888  else
889  {
890  //only bother looking in srs.db if it wasn't found above
891  result = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
892  if ( result )
893  {
894  QgsDebugMsg( QStringLiteral( "Can't open * user * database: %1" ).arg( sqlite3_errmsg( database ) ) );
895  //no need for assert because user db may not have been created yet
896  return 0;
897  }
898  }
899 
900  result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
901  // XXX Need to free memory from the error msg if one is set
902  if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
903  {
904  QString srsIdString = QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
905  srsId = srsIdString.toLong();
906  }
907 
908  // close the sqlite3 statement
909  sqlite3_finalize( stmt );
910  sqlite3_close( database );
911 
912  return srsId;
913 }
914 
915 void QgsProjectionSelectionTreeWidget::updateBoundsPreview()
916 {
917  QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
918  if ( !lvi || ( lvi->text( QgisCrsIdColumn ).isEmpty() && !lvi->data( 0, RoleWkt ).isValid() ) )
919  return;
920 
921  QgsCoordinateReferenceSystem currentCrs = crs();
922  if ( !currentCrs.isValid() )
923  return;
924 
925  QgsRectangle rect = currentCrs.bounds();
926  QString extentString = tr( "Extent not known" );
927  mAreaCanvas->setPreviewRect( rect );
928  if ( !qgsDoubleNear( rect.area(), 0.0 ) )
929  {
930  extentString = QStringLiteral( "%1, %2, %3, %4" )
931  .arg( rect.xMinimum(), 0, 'f', 2 )
932  .arg( rect.yMinimum(), 0, 'f', 2 )
933  .arg( rect.xMaximum(), 0, 'f', 2 )
934  .arg( rect.yMaximum(), 0, 'f', 2 );
935  }
936 
937  QStringList properties;
938  if ( currentCrs.isGeographic() )
939  properties << tr( "Geographic (uses latitude and longitude for coordinates)" );
940  else
941  {
942  properties << tr( "Units: %1" ).arg( QgsUnitTypes::toString( currentCrs.mapUnits() ) );
943  }
944  properties << ( currentCrs.isDynamic() ? tr( "Dynamic (relies on a datum which is not plate-fixed)" ) : tr( "Static (relies on a datum which is plate-fixed)" ) );
945 
946  try
947  {
948  const QString celestialBody = currentCrs.celestialBodyName();
949  if ( !celestialBody.isEmpty() )
950  {
951  properties << tr( "Celestial body: %1" ).arg( celestialBody );
952  }
953  }
954  catch ( QgsNotSupportedException & )
955  {
956 
957  }
958 
959  try
960  {
961  const QgsDatumEnsemble ensemble = currentCrs.datumEnsemble();
962  if ( ensemble.isValid() )
963  {
964  QString id;
965  if ( !ensemble.code().isEmpty() )
966  id = QStringLiteral( "<i>%1</i> (%2:%3)" ).arg( ensemble.name(), ensemble.authority(), ensemble.code() );
967  else
968  id = QStringLiteral( "<i>%</i>”" ).arg( ensemble.name() );
969  if ( ensemble.accuracy() > 0 )
970  {
971  properties << tr( "Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg( id ).arg( ensemble.accuracy() );
972  }
973  else
974  {
975  properties << tr( "Based on %1, which has a limited accuracy." ).arg( id );
976  }
977  }
978  }
979  catch ( QgsNotSupportedException & )
980  {
981 
982  }
983 
984  const QgsProjOperation operation = currentCrs.operation();
985  properties << tr( "Method: %1" ).arg( operation.description() );
986 
987  const QString propertiesString = QStringLiteral( "<dt><b>%1</b></dt><dd><ul><li>%2</li></ul></dd>" ).arg( tr( "Properties" ),
988  properties.join( QLatin1String( "</li><li>" ) ) );
989 
990  const QString extentHtml = QStringLiteral( "<dt><b>%1</b></dt><dd>%2</dd>" ).arg( tr( "Extent" ), extentString );
991  const QString wktString = QStringLiteral( "<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr( "WKT" ), currentCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED, true ).replace( '\n', QLatin1String( "<br>" ) ).replace( ' ', QLatin1String( "&nbsp;" ) ) );
992  const QString proj4String = QStringLiteral( "<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr( "Proj4" ), currentCrs.toProj() );
993 
994 #ifdef Q_OS_WIN
995  const int smallerPointSize = std::max( font().pointSize() - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
996 #else
997  const int smallerPointSize = std::max( font().pointSize() - 2, 6 );
998 #endif
999 
1000  teProjection->setText( QStringLiteral( "<div style=\"font-size: %1pt\"><h3>%2</h3><dl>" ).arg( smallerPointSize ).arg( selectedName() ) + propertiesString + wktString + proj4String + extentHtml + QStringLiteral( "</dl></div>" ) );
1001 }
1002 
1003 QStringList QgsProjectionSelectionTreeWidget::authorities()
1004 {
1005  sqlite3 *database = nullptr;
1006  const char *tail = nullptr;
1007  sqlite3_stmt *stmt = nullptr;
1008 
1009  int result = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY, nullptr );
1010  if ( result )
1011  {
1012  QgsDebugMsg( QStringLiteral( "Can't open * user * database: %1" ).arg( sqlite3_errmsg( database ) ) );
1013  //no need for assert because user db may not have been created yet
1014  return QStringList();
1015  }
1016 
1017  QString sql = QStringLiteral( "select distinct auth_name from tbl_srs" );
1018  result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
1019 
1020  QStringList authorities;
1021  if ( result == SQLITE_OK )
1022  {
1023  while ( sqlite3_step( stmt ) == SQLITE_ROW )
1024  {
1025  authorities << QString::fromUtf8( ( char * )sqlite3_column_text( stmt, 0 ) );
1026  }
1027 
1028  }
1029 
1030  // close the sqlite3 statement
1031  sqlite3_finalize( stmt );
1032  sqlite3_close( database );
1033 
1034  return authorities;
1035 }
1036 
1037 QString QgsProjectionSelectionTreeWidget::sqlSafeString( const QString &theSQL ) const
1038 {
1039  QString retval = theSQL;
1040  retval.replace( '\\', QLatin1String( "\\\\" ) );
1041  retval.replace( '\"', QLatin1String( "\\\"" ) );
1042  retval.replace( '\'', QLatin1String( "\\'" ) );
1043  retval.replace( '%', QLatin1String( "\\%" ) );
1044  return retval;
1045 }
1046 
1047 void QgsProjectionSelectionTreeWidget::showDBMissingWarning( const QString &fileName )
1048 {
1049 
1050  QMessageBox::critical( this, tr( "Resource Location Error" ),
1051  tr( "Error reading database file from: \n %1\n"
1052  "Because of this the projection selector will not work…" )
1053  .arg( fileName ) );
1054 }
QgsProjectionSelectionTreeWidget::projectionDoubleClicked
void projectionDoubleClicked()
Emitted when a projection is double clicked in the list.
QgsProjectionSelectionTreeWidget::hasValidSelectionChanged
void hasValidSelectionChanged(bool isValid)
Emitted when the selection in the tree is changed from a valid selection to an invalid selection,...
QgsCoordinateReferenceSystem::pushRecentCoordinateReferenceSystem
static void pushRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
Definition: qgscoordinatereferencesystem.cpp:2890
QgsCoordinateReferenceSystem::isDynamic
bool isDynamic() const
Returns true if the CRS is a dynamic CRS.
Definition: qgscoordinatereferencesystem.cpp:1314
qgsprojectionselectiontreewidget.h
QgsProjectionSelectionTreeWidget::setNotSetText
void setNotSetText(const QString &text)
Sets the text to show for the not set option.
Definition: qgsprojectionselectiontreewidget.cpp:432
QgsProjectionSelectionTreeWidget::setShowNoProjection
void setShowNoProjection(bool show)
Sets whether a "no/invalid" projection option should be shown.
Definition: qgsprojectionselectiontreewidget.cpp:411
USER_CRS_START_ID
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/....
Definition: qgis.h:2768
qgsrectangle.h
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
sqlite3
struct sqlite3 sqlite3
Definition: qgscoordinatereferencesystem.h:61
QgsCoordinateReferenceSystem::WKT_PREFERRED
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Definition: qgscoordinatereferencesystem.h:680
qgsstringutils.h
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:195
QgsCoordinateReferenceSystem::fromProj
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
Definition: qgscoordinatereferencesystem.cpp:221
QgsCoordinateReferenceSystem::description
QString description
Definition: qgscoordinatereferencesystem.h:218
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
qgis.h
qgsprojoperation.h
QgsProjOperation::description
QString description() const
Description.
Definition: qgsprojoperation.h:61
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsProjectionSelectionTreeWidget::previewRect
QgsRectangle previewRect() const
The initial "preview" rectangle for the bounds overview map.
Definition: qgsprojectionselectiontreewidget.cpp:304
QgsStringUtils::qRegExpEscape
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
Definition: qgsstringutils.cpp:710
QgsProjectionSelectionTreeWidget::QgsProjectionSelectionTreeWidget
QgsProjectionSelectionTreeWidget(QWidget *parent=nullptr)
Constructor for QgsProjectionSelectionTreeWidget.
Definition: qgsprojectionselectiontreewidget.cpp:36
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsProjOperation
Contains information about a PROJ operation.
Definition: qgsprojoperation.h:30
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsCoordinateReferenceSystem::bounds
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
Definition: qgscoordinatereferencesystem.cpp:1470
qgsapplication.h
QgsProjectionSelectionTreeWidget::setShowBoundsMap
void setShowBoundsMap(bool show)
Sets whether to show the bounds preview map.
Definition: qgsprojectionselectiontreewidget.cpp:421
QgsProjectionSelectionTreeWidget::crs
QgsCoordinateReferenceSystem crs() const
Returns the CRS currently selected in the widget.
Definition: qgsprojectionselectiontreewidget.cpp:381
QgsApplication::srsDatabaseFilePath
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
Definition: qgsapplication.cpp:1124
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsProjectionSelectionTreeWidget::showBoundsMap
bool showBoundsMap() const
Returns whether the bounds preview map is shown.
Definition: qgsprojectionselectiontreewidget.cpp:437
QgsProjectionSelectionTreeWidget::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the initial crs to show within the dialog.
Definition: qgsprojectionselectiontreewidget.cpp:269
QgsCoordinateReferenceSystem::isGeographic
bool isGeographic
Definition: qgscoordinatereferencesystem.h:216
QgsDatumEnsemble::accuracy
double accuracy() const
Positional accuracy (in meters).
Definition: qgsdatums.h:112
QgsCoordinateReferenceSystem::srsid
long srsid() const
Returns the internal CRS ID, if available.
Definition: qgscoordinatereferencesystem.cpp:1185
QgsCoordinateReferenceSystemRegistry::userCrsList
QList< QgsCoordinateReferenceSystemRegistry::UserCrsDetails > userCrsList() const
Returns a list containing the details of all registered custom (user-defined) CRSes.
Definition: qgscoordinatereferencesystemregistry.cpp:43
QgsCoordinateReferenceSystemRegistry::UserCrsDetails
Contains details of a custom (user defined) CRS.
Definition: qgscoordinatereferencesystemregistry.h:56
qgsdatums.h
QgsRectangle::area
double area() const SIP_HOLDGIL
Returns the area of the rectangle.
Definition: qgsrectangle.h:239
QgsProjectionSelectionTreeWidget::crsSelected
void crsSelected()
Emitted when a projection is selected in the widget.
QgsUnitTypes::toString
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Definition: qgsunittypes.cpp:199
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsCoordinateReferenceSystem::celestialBodyName
QString celestialBodyName() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
Definition: qgscoordinatereferencesystem.cpp:1323
QgsApplication::coordinateReferenceSystemRegistry
static QgsCoordinateReferenceSystemRegistry * coordinateReferenceSystemRegistry()
Returns the application's coordinate reference system (CRS) registry, which handles known CRS definit...
Definition: qgsapplication.cpp:2355
QgsProjectionSelectionTreeWidget::resizeEvent
void resizeEvent(QResizeEvent *event) override
Definition: qgsprojectionselectiontreewidget.cpp:108
QgsCoordinateReferenceSystem::toWkt
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1810
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:977
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:279
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1293
QgsCoordinateReferenceSystem::operation
QgsProjOperation operation() const
Returns information about the PROJ operation associated with the coordinate reference system,...
Definition: qgscoordinatereferencesystem.cpp:1440
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsProjectionSelectionTreeWidget::showEvent
void showEvent(QShowEvent *event) override
Definition: qgsprojectionselectiontreewidget.cpp:119
QgsProjectionSelectionTreeWidget::pushProjectionToFront
Q_DECL_DEPRECATED void pushProjectionToFront()
Marks the current selected projection for push to front of recent projections list.
Definition: qgsprojectionselectiontreewidget.cpp:842
QgsProjectionSelectionTreeWidget::showNoProjection
bool showNoProjection() const
Returns whether the "no/invalid" projection option is shown.
Definition: qgsprojectionselectiontreewidget.cpp:427
QgsProjectionSelectionTreeWidget::~QgsProjectionSelectionTreeWidget
~QgsProjectionSelectionTreeWidget() override
Definition: qgsprojectionselectiontreewidget.cpp:97
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:215
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsCoordinateReferenceSystem::datumEnsemble
QgsDatumEnsemble datumEnsemble() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve datum ensemble details from the CRS.
Definition: qgscoordinatereferencesystem.cpp:1355
qgssettings.h
QgsDatumEnsemble::authority
QString authority() const
Authority name, e.g.
Definition: qgsdatums.h:117
QgsApplication::qgisUserDatabaseFilePath
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
Definition: qgsapplication.cpp:1104
QgsCoordinateReferenceSystem::authid
QString authid
Definition: qgscoordinatereferencesystem.h:217
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsNotSupportedException
Custom exception class which is raised when an operation is not supported.
Definition: qgsexception.h:117
qgslogger.h
QgsProjectionSelectionTreeWidget::setOgcWmsCrsFilter
void setOgcWmsCrsFilter(const QSet< QString > &crsFilter)
filters this widget by the given CRSs
Definition: qgsprojectionselectiontreewidget.cpp:464
QgsProjectionSelectionTreeWidget::setPreviewRect
void setPreviewRect(const QgsRectangle &rect)
Sets the initial "preview" rectangle for the bounds overview map.
Definition: qgsprojectionselectiontreewidget.cpp:299
QgsProjectionSelectionTreeWidget::initialized
void initialized()
Notifies others that the widget is now fully initialized, including deferred selection of projection.
qgscoordinatereferencesystem.h
qgscoordinatereferencesystemregistry.h
QgsDatumEnsemble::name
QString name() const
Display name of datum ensemble.
Definition: qgsdatums.h:107
QgsCoordinateReferenceSystem::fromWkt
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
Definition: qgscoordinatereferencesystem.cpp:228
QgsDatumEnsemble::isValid
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
Definition: qgsdatums.h:102
QgsDatumEnsemble
Contains information about a datum ensemble.
Definition: qgsdatums.h:94
QgsDatumEnsemble::code
QString code() const
Identification code, e.g.
Definition: qgsdatums.h:122
QgsCoordinateReferenceSystem::recentCoordinateReferenceSystems
static QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
Definition: qgscoordinatereferencesystem.cpp:2859
QgsProjectionSelectionTreeWidget::hasValidSelection
bool hasValidSelection() const
Returns true if the current selection in the widget is a valid choice.
Definition: qgsprojectionselectiontreewidget.cpp:442
qgsmessagelog.h