36#include <QResizeEvent>
38#include <QRegularExpression>
45 QFont f = teProjection->font();
46 f.setPointSize( f.pointSize() - 2 );
47 teProjection->setFont( f );
49 leSearch->setShowSearchIcon(
true );
51 connect( lstCoordinateSystems, &QTreeWidget::itemDoubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystems_itemDoubleClicked );
52 connect( lstRecent, &QTreeWidget::itemDoubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked );
53 connect( lstCoordinateSystems, &QTreeWidget::currentItemChanged,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystems_currentItemChanged );
54 connect( lstRecent, &QTreeWidget::currentItemChanged,
this, &QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged );
55 connect( cbxHideDeprecated, &QCheckBox::stateChanged,
this, &QgsProjectionSelectionTreeWidget::updateFilter );
56 connect( leSearch, &QgsFilterLineEdit::textChanged,
this, &QgsProjectionSelectionTreeWidget::updateFilter );
58 mAreaCanvas->setVisible( mShowMap );
63 lstCoordinateSystems->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
64 lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );
65 lstCoordinateSystems->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
68 lstCoordinateSystems->setColumnHidden( QgisCrsIdColumn,
true );
69 lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
70 lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
71 lstRecent->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
72 lstRecent->setColumnHidden( QgisCrsIdColumn,
true );
75 lstRecent->header()->setMinimumSectionSize( 10 );
76 lstRecent->header()->setStretchLastSection(
false );
77 lstRecent->header()->resizeSection( ClearColumn, 20 );
80 lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
81 connect( lstRecent, &QTreeWidget::customContextMenuRequested,
this, [
this](
const QPoint & pos )
84 if ( lstRecent->topLevelItemCount() == 0 )
88 QTreeWidgetItem *currentItem = lstRecent->itemAt( pos );
91 QAction *clearSelected = menu.addAction(
QgsApplication::getThemeIcon(
"/mIconClearItem.svg" ), tr(
"Remove selected CRS from recently used CRS" ) );
92 connect( clearSelected, &QAction::triggered,
this, [
this, currentItem ] { removeRecentCrsItem( currentItem ); } );
96 QAction *clearAll = menu.addAction(
QgsApplication::getThemeIcon(
"/console/iconClearConsole.svg" ), tr(
"Clear all recently used CRS" ) );
98 menu.exec( lstRecent->viewport()->mapToGlobal( pos ) );
102 lstRecent->installEventFilter(
this );
106 mCheckBoxNoProjection->setHidden(
true );
107 mCheckBoxNoProjection->setEnabled(
false );
108 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ]
110 if ( !mBlockSignals )
116 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ](
bool checked )
118 if ( mCheckBoxNoProjection->isEnabled() )
120 mFrameProjections->setDisabled( checked );
125 mSplitter->restoreState( settings.value( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ) ).toByteArray() );
131 settings.
setValue( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ), mSplitter->saveState() );
141 lstCoordinateSystems->header()->resizeSection( NameColumn, event->size().width() - 240 );
142 lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
143 lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );
145 lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
146 lstRecent->header()->resizeSection( AuthidColumn, 240 );
147 lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
148 lstRecent->header()->resizeSection( ClearColumn, 20 );
158 loadCrsList( &mCrsFilter );
159 loadUserCrsList( &mCrsFilter );
161 if ( !mRecentProjListDone )
165 mRecentProjListDone =
true;
169 mBlockSignals =
true;
171 mBlockSignals =
false;
176 QWidget::showEvent( event );
183 if ( obj != lstRecent )
186 if ( ev->type() != QEvent::KeyPress )
189 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( ev );
190 if ( keyEvent->matches( QKeySequence::Delete ) )
192 removeRecentCrsItem( lstRecent->currentItem() );
199QString QgsProjectionSelectionTreeWidget::ogcWmsCrsFilterAsSqlExpression( QSet<QString> *crsFilter )
201 QString sqlExpression = QStringLiteral(
"1" );
202 QMap<QString, QStringList> authParts;
205 return sqlExpression;
225 const auto authIds { *crsFilter };
226 for (
const QString &auth_id : authIds )
228 QStringList parts = auth_id.split(
':' );
230 if ( parts.size() < 2 )
233 authParts[ parts.at( 0 ).toUpper()].append( parts.at( 1 ).toUpper() );
236 if ( authParts.isEmpty() )
237 return sqlExpression;
239 if ( !authParts.isEmpty() )
241 QString prefix = QStringLiteral(
" AND (" );
242 for (
auto it = authParts.constBegin(); it != authParts.constEnd(); ++it )
244 sqlExpression += QStringLiteral(
"%1(upper(auth_name)='%2' AND upper(auth_id) IN ('%3'))" )
247 it.value().join( QLatin1String(
"','" ) ) );
248 prefix = QStringLiteral(
" OR " );
250 sqlExpression +=
')';
255 return sqlExpression;
258void QgsProjectionSelectionTreeWidget::applySelection(
int column, QString value )
260 if ( !mProjListDone || !mUserProjListDone )
263 mSearchColumn = column;
264 mSearchValue = value;
268 if ( column == QgsProjectionSelectionTreeWidget::None )
271 column = mSearchColumn;
272 value = mSearchValue;
274 mSearchColumn = QgsProjectionSelectionTreeWidget::None;
275 mSearchValue.clear();
278 if ( column == QgsProjectionSelectionTreeWidget::None )
281 QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( value, Qt::MatchExactly | Qt::MatchRecursive, column );
282 if ( !nodes.isEmpty() )
284 QgsDebugMsgLevel( QStringLiteral(
"found %1,%2" ).arg( column ).arg( value ), 4 );
285 lstCoordinateSystems->setCurrentItem( nodes.first() );
289 QgsDebugMsgLevel( QStringLiteral(
"nothing found for %1,%2" ).arg( column ).arg( value ), 4 );
291 lstCoordinateSystems->clearSelection();
292 lstRecent->clearSelection();
293 teProjection->clear();
299 if ( !mProjListDone || !mUserProjListDone )
302 QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( QString::number(
crs.
srsid() ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
303 if ( nodes.isEmpty() )
306 QTreeWidgetItem *item =
new QTreeWidgetItem( lstRecent, QStringList()
307 << nodes.first()->text( NameColumn )
308 << nodes.first()->text( AuthidColumn )
309 << nodes.first()->text( QgisCrsIdColumn ) );
312 QToolButton *clearButton =
new QToolButton();
314 clearButton->setAutoRaise(
true );
315 clearButton->setToolTip( tr(
"Remove from recently used CRS" ) );
316 connect( clearButton, &QToolButton::clicked,
this, [
this, item] { removeRecentCrsItem( item ); } );
317 lstRecent->setItemWidget( item, ClearColumn, clearButton );
320 lstRecent->insertTopLevelItem( 0, item );
325QString QgsProjectionSelectionTreeWidget::selectedName()
328 QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
329 return lvi ? lvi->text( NameColumn ) : QString();
336 mCheckBoxNoProjection->setChecked(
true );
340 bool changed =
false;
343 changed = mDeferredLoadCrs !=
crs;
344 mDeferredLoadCrs =
crs;
346 mBlockSignals =
true;
347 mCheckBoxNoProjection->setChecked(
false );
348 mBlockSignals =
false;
351 applySelection( AuthidColumn,
crs.
authid() );
353 loadUnknownCrs(
crs );
364 mAreaCanvas->setCanvasRect( rect );
369 return mAreaCanvas->canvasRect();
372QString QgsProjectionSelectionTreeWidget::expressionForItem( QTreeWidgetItem *item,
const QString &expression )
const
377 if ( !item || item->text( QgisCrsIdColumn ).isEmpty() )
383 QString databaseFileName;
387 if ( !QFileInfo::exists( databaseFileName ) )
394 databaseFileName = mSrsDatabaseFileName;
402 int rc = sqlite3_open_v2( databaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY,
nullptr );
406 "Because of this the projection selector will not work…" ).arg( databaseFileName ),
407 Qgis::MessageLevel::Critical );
412 const char *tail =
nullptr;
413 sqlite3_stmt *stmt =
nullptr;
414 QString sql = QStringLiteral(
"select %1 from tbl_srs where srs_id=%2" )
416 item->text( QgisCrsIdColumn ) );
418 QgsDebugMsgLevel( QStringLiteral(
"Finding selected attribute using : %1" ).arg( sql ), 4 );
419 rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
421 QString attributeValue;
422 if ( rc == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
425 attributeValue = QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) );
429 sqlite3_finalize( stmt );
431 sqlite3_close( database );
434 return attributeValue;
441 if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
444 if ( !mInitialized && mDeferredLoadCrs.
isValid() )
445 return mDeferredLoadCrs;
447 const QString srsIdString = expressionForItem( item, QStringLiteral(
"srs_id" ) );
448 if ( !srsIdString.isEmpty() )
450 int srid = srsIdString.toLong();
459 if ( item && item->data( 0, RoleWkt ).isValid() )
461 else if ( item && item->data( 0, RoleProj ).isValid() )
470 return crsForItem( lstCoordinateSystems->currentItem() );
475 mCheckBoxNoProjection->setVisible( show );
476 mCheckBoxNoProjection->setEnabled( show );
479 mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
486 mAreaCanvas->setVisible( show );
491 return !mCheckBoxNoProjection->isHidden();
496 mCheckBoxNoProjection->setText( text );
506 QTreeWidgetItem *item = lstCoordinateSystems->currentItem();
507 if ( mCheckBoxNoProjection->isChecked() )
509 else if ( !mInitialized && mDeferredLoadCrs.
isValid() )
512 return item && ( !item->text( QgisCrsIdColumn ).isEmpty() || item->data( 0, RoleWkt ).isValid() );
515long QgsProjectionSelectionTreeWidget::selectedCrsId()
517 QTreeWidgetItem *item = lstCoordinateSystems->currentItem();
519 if ( item && !item->text( QgisCrsIdColumn ).isEmpty() )
520 return lstCoordinateSystems->currentItem()->text( QgisCrsIdColumn ).toLong();
528 mCrsFilter = crsFilter;
529 mProjListDone =
false;
530 mUserProjListDone =
false;
531 lstCoordinateSystems->clear();
534void QgsProjectionSelectionTreeWidget::loadUserCrsList( QSet<QString> *crsFilter )
536 if ( mUserProjListDone )
539 QgsDebugMsgLevel( QStringLiteral(
"Fetching user projection list..." ), 4 );
543 mUserProjList =
new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr(
"User Defined Coordinate Systems" ) ) );
544 mUserProjList->setFlags( mUserProjList->flags() & ~Qt::ItemIsSelectable );
546 QFont fontTemp = mUserProjList->font( 0 );
547 fontTemp.setItalic(
true );
548 fontTemp.setBold(
true );
549 mUserProjList->setFont( 0, fontTemp );
555 const QString authid = QStringLiteral(
"USER:%1" ).arg( details.id );
556 if ( crsFilter && !crsFilter->isEmpty() && !crsFilter->contains( authid ) && !crsFilter->contains( authid.toLower() ) )
559 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mUserProjList, QStringList() << details.name );
560 newItem->setText( QgisCrsIdColumn, QString::number( details.id ) );
561 newItem->setText( AuthidColumn, authid );
564 mUserProjListDone =
true;
567void QgsProjectionSelectionTreeWidget::loadCrsList( QSet<QString> *crsFilter )
573 QString sqlFilter = ogcWmsCrsFilterAsSqlExpression( crsFilter );
579 mGeoList =
new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr(
"Geographic Coordinate Systems" ) ) );
580 mGeoList->setFlags( mGeoList->flags() & ~Qt::ItemIsSelectable );
582 QFont fontTemp = mGeoList->font( 0 );
583 fontTemp.setItalic(
true );
584 fontTemp.setBold(
true );
585 mGeoList->setFont( 0, fontTemp );
589 mProjList =
new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr(
"Projected Coordinate Systems" ) ) );
590 mProjList->setFlags( mProjList->flags() & ~Qt::ItemIsSelectable );
592 fontTemp = mProjList->font( 0 );
593 fontTemp.setItalic(
true );
594 fontTemp.setBold(
true );
595 mProjList->setFont( 0, fontTemp );
603 if ( !QFileInfo::exists( mSrsDatabaseFileName ) )
605 mProjListDone =
true;
611 int rc = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY,
nullptr );
616 showDBMissingWarning( mSrsDatabaseFileName );
620 const char *tail =
nullptr;
621 sqlite3_stmt *stmt =
nullptr;
625 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" )
628 rc = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
630 if ( rc == SQLITE_OK )
632 QTreeWidgetItem *newItem =
nullptr;
635 QString previousSrsType;
636 QTreeWidgetItem *previousSrsTypeNode =
nullptr;
638 while ( sqlite3_step( stmt ) == SQLITE_ROW )
641 int isGeo = sqlite3_column_int( stmt, 3 );
646 newItem =
new QTreeWidgetItem( mGeoList, QStringList( QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) ) ) );
649 newItem->setText( AuthidColumn, QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 2 ) ) );
652 newItem->setText( QgisCrsIdColumn, QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 1 ) ) );
657 QTreeWidgetItem *node =
nullptr;
658 QString srsType = QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 4 ) );
659 if ( srsType.isEmpty() )
660 srsType = tr(
"Other" );
664 if ( srsType == previousSrsType )
666 node = previousSrsTypeNode;
671 QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( srsType, Qt::MatchExactly | Qt::MatchRecursive, NameColumn );
672 if ( nodes.isEmpty() )
676 node =
new QTreeWidgetItem( mProjList, QStringList( srsType ) );
677 node->setFlags( node->flags() & ~Qt::ItemIsSelectable );
679 QFont fontTemp = node->font( 0 );
680 fontTemp.setItalic(
true );
681 node->setFont( 0, fontTemp );
685 node = nodes.first();
688 previousSrsType = srsType;
689 previousSrsTypeNode = node;
692 newItem =
new QTreeWidgetItem( node, QStringList( QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) ) ) );
694 newItem->setText( AuthidColumn, QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 2 ) ) );
696 newItem->setText( QgisCrsIdColumn, QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 1 ) ) );
698 newItem->parent()->setExpanded(
true );
702 newItem->setData( 0, RoleDeprecated, QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 6 ) ) );
703 newItem->setHidden( cbxHideDeprecated->isChecked() );
705 mProjList->setExpanded(
true );
709 sqlite3_finalize( stmt );
711 sqlite3_close( database );
713 mProjListDone =
true;
720 mUnknownList =
new QTreeWidgetItem( lstCoordinateSystems, QStringList( tr(
"Custom Coordinate Systems" ) ) );
721 mUnknownList->setFlags( mUnknownList->flags() & ~Qt::ItemIsSelectable );
723 QFont fontTemp = mUnknownList->font( 0 );
724 fontTemp.setItalic(
true );
725 fontTemp.setBold(
true );
726 mUnknownList->setFont( 0, fontTemp );
730 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mUnknownList, QStringList(
crs.
description().isEmpty() ? QObject::tr(
"Custom CRS" ) :
crs.
description() ) );
732 newItem->setData( 0, RoleProj,
crs.
toProj() );
734 lstCoordinateSystems->setCurrentItem( newItem );
738void QgsProjectionSelectionTreeWidget::lstCoordinateSystems_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem * )
748 lstCoordinateSystems->scrollToItem( current );
752 if ( current->childCount() == 0 )
755 if ( !mBlockSignals )
761 updateBoundsPreview();
763 const QString crsId = current->text( QgisCrsIdColumn );
764 if ( !crsId.isEmpty() )
766 QList<QTreeWidgetItem *> nodes = lstRecent->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly, QgisCrsIdColumn );
767 if ( !nodes.isEmpty() )
769 QgsDebugMsgLevel( QStringLiteral(
"found srs %1 in recent" ).arg( current->text( QgisCrsIdColumn ) ), 4 );
770 lstRecent->setCurrentItem( nodes.first() );
774 QgsDebugMsgLevel( QStringLiteral(
"srs %1 not recent" ).arg( current->text( QgisCrsIdColumn ) ), 4 );
775 lstRecent->clearSelection();
776 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
781 lstRecent->clearSelection();
782 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
788 current->setSelected(
false );
789 teProjection->clear();
790 lstRecent->clearSelection();
795void QgsProjectionSelectionTreeWidget::lstCoordinateSystems_itemDoubleClicked( QTreeWidgetItem *current,
int column )
809 if ( current->childCount() == 0 )
813void QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem * )
823 lstRecent->scrollToItem( current );
825 QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
826 if ( !nodes.isEmpty() )
827 lstCoordinateSystems->setCurrentItem( nodes.first() );
830void QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked( QTreeWidgetItem *current,
int column )
842 QList<QTreeWidgetItem *> nodes = lstCoordinateSystems->findItems( current->text( QgisCrsIdColumn ), Qt::MatchExactly | Qt::MatchRecursive, QgisCrsIdColumn );
843 if ( !nodes.isEmpty() )
847void QgsProjectionSelectionTreeWidget::updateFilter()
850 const thread_local QRegularExpression filterRx( QStringLiteral(
"\\s+" ) );
851 filterTxtCopy.replace( filterRx, QStringLiteral(
".*" ) );
852 const QRegularExpression re( filterTxtCopy, QRegularExpression::PatternOption::CaseInsensitiveOption );
854 const bool hideDeprecated = cbxHideDeprecated->isChecked();
856 auto filterTreeWidget = [ = ]( QTreeWidget * tree )
858 QTreeWidgetItemIterator itr( tree );
861 if ( ( *itr )->childCount() == 0 )
863 if ( hideDeprecated && ( *itr )->data( 0, RoleDeprecated ).toBool() )
865 ( *itr )->setHidden(
true );
866 if ( ( *itr )->isSelected() )
868 ( *itr )->setSelected(
false );
869 teProjection->clear();
872 else if ( ( *itr )->text( NameColumn ).contains( re )
873 || ( *itr )->text( AuthidColumn ).contains( re )
876 ( *itr )->setHidden(
false );
877 QTreeWidgetItem *parent = ( *itr )->parent();
880 parent->setExpanded(
true );
881 parent->setHidden(
false );
882 parent = parent->parent();
887 ( *itr )->setHidden(
true );
892 ( *itr )->setHidden(
true );
899 filterTreeWidget( lstRecent );
902 filterTreeWidget( lstCoordinateSystems );
909long QgsProjectionSelectionTreeWidget::getLargestCrsIdMatch(
const QString &sql )
918 const char *tail =
nullptr;
919 sqlite3_stmt *stmt =
nullptr;
926 if ( QFileInfo::exists( databaseFileName ) )
928 result = sqlite3_open_v2( databaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY,
nullptr );
935 showDBMissingWarning( databaseFileName );
939 result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
941 if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
943 QString srsIdString = QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) );
944 srsId = srsIdString.toLong();
946 sqlite3_finalize( stmt );
947 sqlite3_close( database );
954 result = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY,
nullptr );
957 QgsDebugError( QStringLiteral(
"Can't open * user * database: %1" ).arg( sqlite3_errmsg( database ) ) );
963 result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
965 if ( result == SQLITE_OK && sqlite3_step( stmt ) == SQLITE_ROW )
967 QString srsIdString = QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) );
968 srsId = srsIdString.toLong();
972 sqlite3_finalize( stmt );
973 sqlite3_close( database );
978void QgsProjectionSelectionTreeWidget::updateBoundsPreview()
980 QTreeWidgetItem *lvi = lstCoordinateSystems->currentItem();
981 if ( !lvi || ( lvi->text( QgisCrsIdColumn ).isEmpty() && !lvi->data( 0, RoleWkt ).isValid() ) )
989 QString extentString = tr(
"Extent not known" );
990 mAreaCanvas->setPreviewRect( rect );
993 extentString = QStringLiteral(
"%1, %2, %3, %4" )
1000 QStringList properties;
1002 properties << tr(
"Geographic (uses latitude and longitude for coordinates)" );
1007 properties << ( currentCrs.
isDynamic() ? tr(
"Dynamic (relies on a datum which is not plate-fixed)" ) : tr(
"Static (relies on a datum which is plate-fixed)" ) );
1012 if ( !celestialBody.isEmpty() )
1014 properties << tr(
"Celestial body: %1" ).arg( celestialBody );
1028 if ( !ensemble.
code().isEmpty() )
1029 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
1031 id = QStringLiteral(
"<i>%</i>”" ).arg( ensemble.
name() );
1034 properties << tr(
"Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg(
id ).arg( ensemble.
accuracy() );
1038 properties << tr(
"Based on %1, which has a limited accuracy." ).arg(
id );
1048 properties << tr(
"Method: %1" ).arg( operation.
description() );
1050 const QString propertiesString = QStringLiteral(
"<dt><b>%1</b></dt><dd><ul><li>%2</li></ul></dd>" ).arg( tr(
"Properties" ),
1051 properties.join( QLatin1String(
"</li><li>" ) ) );
1053 const QString extentHtml = QStringLiteral(
"<dt><b>%1</b></dt><dd>%2</dd>" ).arg( tr(
"Extent" ), extentString );
1054 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(
" " ) ) );
1055 const QString proj4String = QStringLiteral(
"<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr(
"Proj4" ), currentCrs.
toProj() );
1058 const int smallerPointSize = std::max( font().pointSize() - 1, 8 );
1060 const int smallerPointSize = std::max( font().pointSize() - 2, 6 );
1063 teProjection->setText( QStringLiteral(
"<div style=\"font-size: %1pt\"><h3>%2</h3><dl>" ).arg( smallerPointSize ).arg( selectedName() ) + propertiesString + wktString + proj4String + extentHtml + QStringLiteral(
"</dl></div>" ) );
1066QStringList QgsProjectionSelectionTreeWidget::authorities()
1069 const char *tail =
nullptr;
1070 sqlite3_stmt *stmt =
nullptr;
1072 int result = sqlite3_open_v2( mSrsDatabaseFileName.toUtf8().constData(), &database, SQLITE_OPEN_READONLY,
nullptr );
1075 QgsDebugError( QStringLiteral(
"Can't open * user * database: %1" ).arg( sqlite3_errmsg( database ) ) );
1077 return QStringList();
1080 QString sql = QStringLiteral(
"select distinct auth_name from tbl_srs" );
1081 result = sqlite3_prepare( database, sql.toUtf8(), sql.toUtf8().length(), &stmt, &tail );
1083 QStringList authorities;
1084 if ( result == SQLITE_OK )
1086 while ( sqlite3_step( stmt ) == SQLITE_ROW )
1088 authorities << QString::fromUtf8( (
char * )sqlite3_column_text( stmt, 0 ) );
1094 sqlite3_finalize( stmt );
1095 sqlite3_close( database );
1100QString QgsProjectionSelectionTreeWidget::sqlSafeString(
const QString &theSQL )
const
1102 QString retval = theSQL;
1103 retval.replace(
'\\', QLatin1String(
"\\\\" ) );
1104 retval.replace(
'\"', QLatin1String(
"\\\"" ) );
1105 retval.replace(
'\'', QLatin1String(
"\\'" ) );
1106 retval.replace(
'%', QLatin1String(
"\\%" ) );
1110void QgsProjectionSelectionTreeWidget::showDBMissingWarning(
const QString &fileName )
1113 QMessageBox::critical(
this, tr(
"Resource Location Error" ),
1114 tr(
"Error reading database file from: \n %1\n"
1115 "Because of this the projection selector will not work…" )
1122 if ( lstRecent->topLevelItemCount() == 0 )
1128 if ( QMessageBox::question(
this, tr(
"Clear Recent CRS" ),
1129 tr(
"Are you sure you want to clear the list of recently used coordinate reference system?" ),
1130 QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
1139void QgsProjectionSelectionTreeWidget::removeRecentCrsItem( QTreeWidgetItem *item )
1141 int index = lstRecent->indexOfTopLevelItem( item );
1146 lstRecent->takeTopLevelItem( index );
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsCoordinateReferenceSystemRegistry * coordinateReferenceSystemRegistry()
Returns the application's coordinate reference system (CRS) registry, which handles known CRS definit...
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
Contains details of a custom (user defined) CRS.
QList< QgsCoordinateReferenceSystemRegistry::UserCrsDetails > userCrsList() const
Returns a list containing the details of all registered custom (user-defined) CRSes.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Q_GADGET Qgis::DistanceUnit mapUnits
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
QString toProj() const
Returns a Proj string representation of this CRS.
static void pushRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
QgsDatumEnsemble datumEnsemble() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve datum ensemble details from the CRS.
static void removeRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
bool isDynamic() const
Returns true if the CRS is a dynamic CRS.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
static QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
static void clearRecentCoordinateReferenceSystems()
Cleans the list of recently used CRS.
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
QgsProjOperation operation() const
Returns information about the PROJ operation associated with the coordinate reference system,...
long srsid() const
Returns the internal CRS ID, if available.
QString celestialBodyName() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
Contains information about a datum ensemble.
QString code() const
Identification code, e.g.
QString authority() const
Authority name, e.g.
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
QString name() const
Display name of datum ensemble.
double accuracy() const
Positional accuracy (in meters).
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).
Custom exception class which is raised when an operation is not supported.
Contains information about a PROJ operation.
QString description() const
Description.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double area() const SIP_HOLDGIL
Returns the area of the rectangle.
This class is a composition of two QSettings instances:
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QString qRegExpEscape(const QString &string)
Returns an escaped string matching the behavior of QRegExp::escape.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/....
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
const QgsCoordinateReferenceSystem & crs