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