35#include <QResizeEvent>
37#include <QRegularExpression>
47 lstCoordinateSystems->setModel( mCrsModel );
48 lstCoordinateSystems->setSelectionBehavior( QAbstractItemView::SelectRows );
50 QFont f = teProjection->font();
51 f.setPointSize( f.pointSize() - 2 );
52 teProjection->setFont( f );
54 leSearch->setShowSearchIcon(
true );
56 connect( lstCoordinateSystems, &QTreeView::doubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked );
57 connect( lstRecent, &QTreeWidget::itemDoubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked );
58 connect( lstCoordinateSystems->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged );
59 connect( lstRecent, &QTreeWidget::currentItemChanged,
this, &QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged );
60 connect( cbxHideDeprecated, &QCheckBox::toggled,
this, [ = ](
bool selected )
63 filterRecentCrsList();
65 connect( leSearch, &QgsFilterLineEdit::textChanged,
this, [ = ](
const QString & filter )
68 filterRecentCrsList();
71 mAreaCanvas->setVisible( mShowMap );
73 lstCoordinateSystems->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
76 lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
77 lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
78 lstRecent->header()->setSectionResizeMode( QgisCrsIdColumn, QHeaderView::Fixed );
79 lstRecent->setColumnHidden( QgisCrsIdColumn,
true );
82 lstRecent->header()->setMinimumSectionSize( 10 );
83 lstRecent->header()->setStretchLastSection(
false );
84 lstRecent->header()->resizeSection( ClearColumn, 20 );
87 lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
88 connect( lstRecent, &QTreeWidget::customContextMenuRequested,
this, [
this](
const QPoint & pos )
91 if ( lstRecent->topLevelItemCount() == 0 )
95 QTreeWidgetItem *currentItem = lstRecent->itemAt( pos );
98 QAction *clearSelected = menu.addAction(
QgsApplication::getThemeIcon(
"/mIconClearItem.svg" ), tr(
"Remove Selected CRS from Recently Used CRS" ) );
99 connect( clearSelected, &QAction::triggered,
this, [
this, currentItem ] { removeRecentCrsItem( currentItem ); } );
103 QAction *clearAll = menu.addAction(
QgsApplication::getThemeIcon(
"/console/iconClearConsole.svg" ), tr(
"Clear All Recently Used CRS" ) );
105 menu.exec( lstRecent->viewport()->mapToGlobal( pos ) );
109 lstRecent->installEventFilter(
this );
117 mCheckBoxNoProjection->setHidden(
true );
118 mCheckBoxNoProjection->setEnabled(
false );
119 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ]
121 if ( !mBlockSignals )
127 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ](
bool checked )
129 if ( mCheckBoxNoProjection->isEnabled() )
131 mFrameProjections->setDisabled( checked );
136 mSplitter->restoreState( settings.value( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ) ).toByteArray() );
142 settings.
setValue( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ), mSplitter->saveState() );
152 lstCoordinateSystems->header()->resizeSection( NameColumn, event->size().width() - 240 );
153 lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
154 lstCoordinateSystems->header()->resizeSection( QgisCrsIdColumn, 0 );
156 lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
157 lstRecent->header()->resizeSection( AuthidColumn, 240 );
158 lstRecent->header()->resizeSection( QgisCrsIdColumn, 0 );
159 lstRecent->header()->resizeSection( ClearColumn, 20 );
164 if ( obj != lstRecent )
167 if ( ev->type() != QEvent::KeyPress )
170 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( ev );
171 if ( keyEvent->matches( QKeySequence::Delete ) )
173 removeRecentCrsItem( lstRecent->currentItem() );
180void QgsProjectionSelectionTreeWidget::selectCrsByAuthId(
const QString &authid )
183 if ( !sourceIndex.isValid() )
186 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
187 if ( proxyIndex.isValid() )
189 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
190 lstCoordinateSystems->scrollTo( proxyIndex );
195 lstCoordinateSystems->clearSelection();
196 lstRecent->clearSelection();
197 teProjection->clear();
204 if ( !sourceIndex.isValid() )
207 QTreeWidgetItem *item =
new QTreeWidgetItem( lstRecent, QStringList()
212 QToolButton *clearButton =
new QToolButton();
214 clearButton->setAutoRaise(
true );
215 clearButton->setToolTip( tr(
"Remove from recently used CRS" ) );
216 connect( clearButton, &QToolButton::clicked,
this, [
this, item] { removeRecentCrsItem( item ); } );
217 lstRecent->setItemWidget( item, ClearColumn, clearButton );
219 lstRecent->insertTopLevelItem( 0, item );
226 mCheckBoxNoProjection->setChecked(
true );
230 mBlockSignals =
true;
231 mCheckBoxNoProjection->setChecked(
false );
232 mBlockSignals =
false;
237 loadUnknownCrs(
crs );
250 mAreaCanvas->setCanvasRect( rect );
255 return mAreaCanvas->canvasRect();
270 if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
273 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
275 if ( !authid.isEmpty() )
285 if ( !wkt.isEmpty() )
287 else if ( !proj.isEmpty() )
296 mCheckBoxNoProjection->setVisible( show );
297 mCheckBoxNoProjection->setEnabled( show );
300 mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
307 mAreaCanvas->setVisible( show );
312 return !mCheckBoxNoProjection->isHidden();
317 mCheckBoxNoProjection->setText( text );
327 if ( mCheckBoxNoProjection->isChecked() )
333 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
337 return !authid.isEmpty() || !wkt.isEmpty() || !proj.isEmpty();
349 lstCoordinateSystems->selectionModel()->select( mCrsModel->mapFromSource( sourceIndex ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
350 lstCoordinateSystems->scrollTo( mCrsModel->mapFromSource( sourceIndex ) );
354void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged(
const QItemSelection &selected,
const QItemSelection & )
356 if ( selected.isEmpty() )
362 const QModelIndex selectedProxyIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
363 if ( !selectedProxyIndex.isValid() )
366 lstCoordinateSystems->scrollTo( selectedProxyIndex );
367 const QModelIndex sourceIndex = mCrsModel->mapToSource( selectedProxyIndex );
374 if ( !mBlockSignals )
380 updateBoundsPreview();
383 if ( !crsAuthId.isEmpty() )
385 QList<QTreeWidgetItem *> nodes = lstRecent->findItems( crsAuthId, Qt::MatchExactly, AuthidColumn );
386 if ( !nodes.isEmpty() )
388 QgsDebugMsgLevel( QStringLiteral(
"found srs %1 in recent" ).arg( crsAuthId ), 4 );
389 lstRecent->setCurrentItem( nodes.first() );
393 QgsDebugMsgLevel( QStringLiteral(
"srs %1 not recent" ).arg( crsAuthId ), 4 );
394 lstRecent->clearSelection();
395 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
400 lstRecent->clearSelection();
401 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
407 teProjection->clear();
408 lstRecent->clearSelection();
413void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked(
const QModelIndex &index )
415 if ( !index.isValid() )
427void QgsProjectionSelectionTreeWidget::lstRecent_currentItemChanged( QTreeWidgetItem *current, QTreeWidgetItem * )
437 lstRecent->scrollToItem( current );
439 const QString selectedAuthId = current->text( AuthidColumn );
441 if ( sourceIndex.isValid() )
443 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
444 if ( proxyIndex.isValid() )
446 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
447 lstCoordinateSystems->scrollTo( proxyIndex );
452void QgsProjectionSelectionTreeWidget::lstRecent_itemDoubleClicked( QTreeWidgetItem *current,
int column )
464 const QString selectedAuthId = current->text( AuthidColumn );
466 if ( sourceIndex.isValid() )
468 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
469 if ( proxyIndex.isValid() )
476void QgsProjectionSelectionTreeWidget::filterRecentCrsList()
479 const thread_local QRegularExpression filterRx( QStringLiteral(
"\\s+" ) );
480 filterTxtCopy.replace( filterRx, QStringLiteral(
".*" ) );
481 const QRegularExpression re( filterTxtCopy, QRegularExpression::PatternOption::CaseInsensitiveOption );
483 const bool hideDeprecated = cbxHideDeprecated->isChecked();
485 QTreeWidgetItemIterator itr( lstRecent );
488 if ( ( *itr )->childCount() == 0 )
490 if ( hideDeprecated && ( *itr )->data( 0, RoleDeprecated ).toBool() )
492 ( *itr )->setHidden(
true );
493 if ( ( *itr )->isSelected() )
495 ( *itr )->setSelected(
false );
496 teProjection->clear();
499 else if ( ( *itr )->text( NameColumn ).contains( re )
500 || ( *itr )->text( AuthidColumn ).contains( re )
503 ( *itr )->setHidden(
false );
504 QTreeWidgetItem *parent = ( *itr )->parent();
507 parent->setExpanded(
true );
508 parent->setHidden(
false );
509 parent = parent->parent();
514 ( *itr )->setHidden(
true );
519 ( *itr )->setHidden(
true );
529void QgsProjectionSelectionTreeWidget::updateBoundsPreview()
536 QString extentString = tr(
"Extent not known" );
537 mAreaCanvas->setPreviewRect( rect );
540 extentString = QStringLiteral(
"%1, %2, %3, %4" )
547 QStringList properties;
549 properties << tr(
"Geographic (uses latitude and longitude for coordinates)" );
554 properties << ( currentCrs.
isDynamic() ? tr(
"Dynamic (relies on a datum which is not plate-fixed)" ) : tr(
"Static (relies on a datum which is plate-fixed)" ) );
559 if ( !celestialBody.isEmpty() )
561 properties << tr(
"Celestial body: %1" ).arg( celestialBody );
575 if ( !ensemble.
code().isEmpty() )
576 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
578 id = QStringLiteral(
"<i>%</i>”" ).arg( ensemble.
name() );
581 properties << tr(
"Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg(
id ).arg( ensemble.
accuracy() );
585 properties << tr(
"Based on %1, which has a limited accuracy." ).arg(
id );
595 properties << tr(
"Method: %1" ).arg( operation.
description() );
597 const QString propertiesString = QStringLiteral(
"<dt><b>%1</b></dt><dd><ul><li>%2</li></ul></dd>" ).arg( tr(
"Properties" ),
598 properties.join( QLatin1String(
"</li><li>" ) ) );
600 const QString extentHtml = QStringLiteral(
"<dt><b>%1</b></dt><dd>%2</dd>" ).arg( tr(
"Extent" ), extentString );
601 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(
" " ) ) );
602 const QString proj4String = QStringLiteral(
"<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr(
"Proj4" ), currentCrs.
toProj() );
605 const int smallerPointSize = std::max( font().pointSize() - 1, 8 );
607 const int smallerPointSize = std::max( font().pointSize() - 2, 6 );
610 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
611 QString selectedName;
612 if ( currentIndex.isValid() )
616 teProjection->setText( QStringLiteral(
"<div style=\"font-size: %1pt\"><h3>%2</h3><dl>" ).arg( smallerPointSize ).arg( selectedName ) + propertiesString + wktString + proj4String + extentHtml + QStringLiteral(
"</dl></div>" ) );
622 if ( lstRecent->topLevelItemCount() == 0 )
628 if ( QMessageBox::question(
this, tr(
"Clear Recent CRS" ),
629 tr(
"Are you sure you want to clear the list of recently used coordinate reference system?" ),
630 QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
638void QgsProjectionSelectionTreeWidget::removeRecentCrsItem( QTreeWidgetItem *item )
643 int index = lstRecent->indexOfTopLevelItem( item );
647 const QString selectedAuthId = item->text( AuthidColumn );
648 if ( !selectedAuthId.isEmpty() )
653 lstRecent->takeTopLevelItem( index );
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex addCustomCrs(const QgsCoordinateReferenceSystem &crs)
Adds a custom crs to the model.
@ RoleProj
The coordinate reference system's PROJ representation. This is only used for non-standard CRS (i....
@ RoleName
The coordinate reference system name.
@ RoleWkt
The coordinate reference system's WKT representation. This is only used for non-standard CRS (i....
@ RoleAuthId
The coordinate reference system authority name and id.
QModelIndex authIdToIndex(const QString &authId) const
Retrieves the model index corresponding to a CRS with the specified authId.
QVariant data(const QModelIndex &index, int role) const override
A sort/filter proxy model for coordinate reference systems.
void setFilterDeprecated(bool filter)
Sets whether deprecated CRS should be filtered from the results.
Filters filters() const
Returns any filters that affect how CRS are filtered.
QgsCoordinateReferenceSystemModel * coordinateReferenceSystemModel()
Returns the underlying source model.
void setFilterString(const QString &filter)
Sets a filter string, such that only coordinate reference systems matching the specified string will ...
void setFilterAuthIds(const QSet< QString > &filter)
Sets a filter list of CRS auth ID strings, such that only coordinate reference systems matching the s...
void setFilters(QgsCoordinateReferenceSystemProxyModel::Filters filters)
Set filters that affect how CRS are filtered.
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.
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.
static void removeRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the 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.
QString celestialBodyName() const
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
@ 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,...
Qgis::DistanceUnit mapUnits
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).
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 area() const
Returns the area of the rectangle.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of 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)
#define QgsDebugMsgLevel(str, level)
const QgsCoordinateReferenceSystem & crs