35#include <QResizeEvent>
37#include <QRegularExpression>
39#ifdef ENABLE_MODELTEST
51 mRecentCrsModel =
new QgsRecentCoordinateReferenceSystemTableModel(
this );
52 mRecentCrsModel->setFilters(
filters );
54 lstCoordinateSystems->setModel( mCrsModel );
55 lstCoordinateSystems->setSelectionBehavior( QAbstractItemView::SelectRows );
57 lstRecent->setModel( mRecentCrsModel );
58 lstRecent->viewport()->setAttribute( Qt::WA_Hover );
59 lstRecent->setSelectionBehavior( QAbstractItemView::SelectRows );
60 lstRecent->setRootIsDecorated(
false );
62 RemoveRecentCrsDelegate *removeDelegate =
new RemoveRecentCrsDelegate( lstRecent );
63 lstRecent->setItemDelegateForColumn( 2, removeDelegate );
64 lstRecent->viewport()->installEventFilter( removeDelegate );
66 if ( mCrsModel->rowCount() == 1 )
69 lstCoordinateSystems->expand( mCrsModel->index( 0, 0, QModelIndex() ) );
72 QFont f = teProjection->font();
73 f.setPointSize( f.pointSize() - 2 );
74 teProjection->setFont( f );
76 leSearch->setShowSearchIcon(
true );
78 connect( lstCoordinateSystems, &QTreeView::doubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked );
79 connect( lstRecent, &QTreeView::doubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstRecentDoubleClicked );
80 connect( lstRecent, &QTreeView::clicked,
this, &QgsProjectionSelectionTreeWidget::lstRecentClicked );
81 connect( lstCoordinateSystems->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged );
82 connect( lstRecent->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsProjectionSelectionTreeWidget::lstRecentSelectionChanged );
83 connect( cbxHideDeprecated, &QCheckBox::toggled,
this, [ = ](
bool selected )
86 mRecentCrsModel->setFilterDeprecated( selected );
88 connect( leSearch, &QgsFilterLineEdit::textChanged,
this, [ = ](
const QString & filter )
91 mRecentCrsModel->setFilterString( filter );
94 mAreaCanvas->setVisible( mShowMap );
96 lstCoordinateSystems->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
97 lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
100 lstRecent->header()->setMinimumSectionSize( 10 );
101 lstRecent->header()->setStretchLastSection(
false );
102 lstRecent->header()->resizeSection( ClearColumn, 20 );
105 lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
106 connect( lstRecent, &QTreeView::customContextMenuRequested,
this, [
this](
const QPoint & pos )
109 if ( lstRecent->model()->rowCount() == 0 )
113 const QModelIndex currentIndex = lstRecent->indexAt( pos );
114 if ( currentIndex.isValid() )
116 QAction *clearSelected = menu.addAction(
QgsApplication::getThemeIcon(
"/mIconClearItem.svg" ), tr(
"Remove Selected CRS from Recently Used CRS" ) );
117 connect( clearSelected, &QAction::triggered,
this, [
this, currentIndex ] { removeRecentCrsItem( currentIndex ); } );
121 QAction *clearAll = menu.addAction(
QgsApplication::getThemeIcon(
"/console/iconClearConsole.svg" ), tr(
"Clear All Recently Used CRS" ) );
123 menu.exec( lstRecent->viewport()->mapToGlobal( pos ) );
127 lstRecent->installEventFilter(
this );
129 mCheckBoxNoProjection->setHidden(
true );
130 mCheckBoxNoProjection->setEnabled(
false );
131 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ]
133 if ( !mBlockSignals )
139 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [ = ](
bool checked )
141 if ( mCheckBoxNoProjection->isEnabled() )
143 mFrameProjections->setDisabled( checked );
148 mSplitter->restoreState( settings.value( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ) ).toByteArray() );
154 settings.
setValue( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ), mSplitter->saveState() );
164 lstCoordinateSystems->header()->resizeSection( NameColumn, event->size().width() - 240 );
165 lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
167 lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
168 lstRecent->header()->resizeSection( AuthidColumn, 240 );
169 lstRecent->header()->resizeSection( ClearColumn, 20 );
174 if ( obj != lstRecent )
177 if ( ev->type() != QEvent::KeyPress )
180 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( ev );
181 if ( keyEvent->matches( QKeySequence::Delete ) )
183 const QModelIndex currentIndex = lstRecent->selectionModel()->selectedRows( 0 ).value( 0 );
184 if ( currentIndex.isValid() )
185 removeRecentCrsItem( currentIndex );
192void QgsProjectionSelectionTreeWidget::selectCrsByAuthId(
const QString &authid )
195 if ( !sourceIndex.isValid() )
198 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
199 if ( proxyIndex.isValid() )
201 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
202 lstCoordinateSystems->scrollTo( proxyIndex );
207 lstCoordinateSystems->clearSelection();
208 lstRecent->clearSelection();
209 teProjection->clear();
217 mCheckBoxNoProjection->setChecked(
true );
221 mBlockSignals =
true;
222 mCheckBoxNoProjection->setChecked(
false );
223 mBlockSignals =
false;
228 loadUnknownCrs(
crs );
241 mAreaCanvas->setCanvasRect( rect );
246 return mAreaCanvas->canvasRect();
257 mRecentCrsModel->setFilters(
filters );
258 if ( mCrsModel->rowCount() == 1 )
261 lstCoordinateSystems->expand( mCrsModel->index( 0, 0, QModelIndex() ) );
267 if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
270 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
272 if ( !authid.isEmpty() )
282 if ( !wkt.isEmpty() )
284 else if ( !proj.isEmpty() )
293 mCheckBoxNoProjection->setVisible( show );
294 mCheckBoxNoProjection->setEnabled( show );
297 mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
304 mAreaCanvas->setVisible( show );
309 return !mCheckBoxNoProjection->isHidden();
314 mCheckBoxNoProjection->setText( text );
324 if ( mCheckBoxNoProjection->isChecked() )
330 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
334 return !authid.isEmpty() || !wkt.isEmpty() || !proj.isEmpty();
346 lstCoordinateSystems->selectionModel()->select( mCrsModel->mapFromSource( sourceIndex ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
347 lstCoordinateSystems->scrollTo( mCrsModel->mapFromSource( sourceIndex ) );
351void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged(
const QItemSelection &selected,
const QItemSelection & )
353 if ( selected.isEmpty() )
359 const QModelIndex selectedProxyIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
360 if ( !selectedProxyIndex.isValid() )
363 lstCoordinateSystems->scrollTo( selectedProxyIndex );
364 const QModelIndex sourceIndex = mCrsModel->mapToSource( selectedProxyIndex );
371 if ( !mBlockSignals )
377 updateBoundsPreview();
380 if ( !crsAuthId.isEmpty() )
382 const QModelIndexList recentMatches = mRecentCrsModel->match( mRecentCrsModel->index( 0, 0 ),
385 if ( !recentMatches.isEmpty() )
387 QgsDebugMsgLevel( QStringLiteral(
"found srs %1 in recent" ).arg( crsAuthId ), 4 );
389 lstRecent->selectionModel()->select( recentMatches.at( 0 ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
390 lstRecent->scrollTo( recentMatches.at( 0 ) );
394 QgsDebugMsgLevel( QStringLiteral(
"srs %1 not recent" ).arg( crsAuthId ), 4 );
395 lstRecent->clearSelection();
396 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
401 lstRecent->clearSelection();
402 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
408 teProjection->clear();
409 lstRecent->clearSelection();
414void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked(
const QModelIndex &index )
416 if ( !index.isValid() )
428void QgsProjectionSelectionTreeWidget::lstRecentSelectionChanged(
const QItemSelection &selected,
const QItemSelection & )
430 if ( selected.isEmpty() )
436 const QModelIndex selectedIndex = lstRecent->selectionModel()->selectedRows( 0 ).value( 0 );
437 if ( !selectedIndex.isValid() )
440 lstRecent->scrollTo( selectedIndex );
442 const QString selectedAuthId = mRecentCrsModel->crs( selectedIndex ).authid();
444 if ( sourceIndex.isValid() )
446 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
447 if ( proxyIndex.isValid() )
449 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
450 lstCoordinateSystems->scrollTo( proxyIndex );
455void QgsProjectionSelectionTreeWidget::lstRecentDoubleClicked(
const QModelIndex &index )
458 if ( !index.isValid() )
467void QgsProjectionSelectionTreeWidget::lstRecentClicked(
const QModelIndex &index )
469 if ( index.column() == ClearColumn )
471 removeRecentCrsItem( index );
479void QgsProjectionSelectionTreeWidget::updateBoundsPreview()
486 QString extentString = tr(
"Extent not known" );
487 mAreaCanvas->setPreviewRect( rect );
490 extentString = QStringLiteral(
"%1, %2, %3, %4" )
497 QStringList properties;
499 properties << tr(
"Geographic (uses latitude and longitude for coordinates)" );
504 properties << ( currentCrs.
isDynamic() ? tr(
"Dynamic (relies on a datum which is not plate-fixed)" ) : tr(
"Static (relies on a datum which is plate-fixed)" ) );
509 if ( !celestialBody.isEmpty() )
511 properties << tr(
"Celestial body: %1" ).arg( celestialBody );
525 if ( !ensemble.
code().isEmpty() )
526 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
528 id = QStringLiteral(
"<i>%</i>”" ).arg( ensemble.
name() );
531 properties << tr(
"Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg(
id ).arg( ensemble.
accuracy() );
535 properties << tr(
"Based on %1, which has a limited accuracy." ).arg(
id );
545 properties << tr(
"Method: %1" ).arg( operation.
description() );
547 const QString propertiesString = QStringLiteral(
"<dt><b>%1</b></dt><dd><ul><li>%2</li></ul></dd>" ).arg( tr(
"Properties" ),
548 properties.join( QLatin1String(
"</li><li>" ) ) );
550 const QString extentHtml = QStringLiteral(
"<dt><b>%1</b></dt><dd>%2</dd>" ).arg( tr(
"Extent" ), extentString );
551 const QString wktString = QStringLiteral(
"<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr(
"WKT" ), currentCrs.
toWkt(
Qgis::CrsWktVariant::Preferred,
true ).replace(
'\n', QLatin1String(
"<br>" ) ).replace(
' ', QLatin1String(
" " ) ) );
552 const QString proj4String = QStringLiteral(
"<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr(
"Proj4" ), currentCrs.
toProj() );
555 const int smallerPointSize = std::max( font().pointSize() - 1, 8 );
557 const int smallerPointSize = std::max( font().pointSize() - 2, 6 );
560 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
561 QString selectedName;
562 if ( currentIndex.isValid() )
566 teProjection->setText( QStringLiteral(
"<div style=\"font-size: %1pt\"><h3>%2</h3><dl>" ).arg( smallerPointSize ).arg( selectedName ) + propertiesString + wktString + proj4String + extentHtml + QStringLiteral(
"</dl></div>" ) );
578 if ( QMessageBox::question(
this, tr(
"Clear Recent CRS" ),
579 tr(
"Are you sure you want to clear the list of recently used coordinate reference system?" ),
580 QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
587void QgsProjectionSelectionTreeWidget::removeRecentCrsItem(
const QModelIndex &index )
595QgsRecentCoordinateReferenceSystemTableModel::QgsRecentCoordinateReferenceSystemTableModel( QObject *parent )
598#ifdef ENABLE_MODELTEST
599 new ModelTest(
this,
this );
603QVariant QgsRecentCoordinateReferenceSystemTableModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
605 if ( orientation == Qt::Horizontal )
609 case Qt::DisplayRole:
613 return tr(
"Coordinate Reference System" );
615 return tr(
"Authority ID" );
630QVariant QgsRecentCoordinateReferenceSystemTableModel::data(
const QModelIndex &index,
int role )
const
632 if ( !index.isValid() )
635 const int column = index.column();
643 case Qt::DisplayRole:
644 case Qt::ToolTipRole:
657 case Qt::ToolTipRole:
658 return tr(
"Remove from recently used CRS" );
669 return QgsRecentCoordinateReferenceSystemsProxyModel::data( index, role );
677RemoveRecentCrsDelegate::RemoveRecentCrsDelegate( QObject *parent )
678 : QStyledItemDelegate( parent )
683bool RemoveRecentCrsDelegate::eventFilter( QObject *obj, QEvent *event )
685 if ( event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverMove )
687 QHoverEvent *hoverEvent =
static_cast<QHoverEvent *
>( event );
688 if ( QAbstractItemView *view = qobject_cast<QAbstractItemView *>( obj->parent() ) )
690 const QModelIndex indexUnderMouse = view->indexAt( hoverEvent->pos() );
691 setHoveredIndex( indexUnderMouse );
692 view->viewport()->update();
695 else if ( event->type() == QEvent::HoverLeave )
697 setHoveredIndex( QModelIndex() );
698 qobject_cast< QWidget * >( obj )->update();
700 return QStyledItemDelegate::eventFilter( obj, event );
703void RemoveRecentCrsDelegate::paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
705 QStyledItemDelegate::paint( painter, option, index );
707 if ( index == mHoveredIndex )
709 QStyleOptionButton buttonOption;
710 buttonOption.initFrom( option.widget );
711 buttonOption.rect = option.rect;
713 option.widget->style()->drawControl( QStyle::CE_PushButton, &buttonOption, painter );
717 const QRect iconRect( option.rect.left() + ( option.rect.width() - 16 ) / 2,
718 option.rect.top() + ( option.rect.height() - 16 ) / 2,
721 icon.paint( painter, iconRect );
724void RemoveRecentCrsDelegate::setHoveredIndex(
const QModelIndex &index )
726 mHoveredIndex = index;
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
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...
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex addCustomCrs(const QgsCoordinateReferenceSystem &crs)
Adds a custom crs to the model.
QModelIndex authIdToIndex(const QString &authId) const
Retrieves the model index corresponding to a CRS with the specified authId.
@ AuthId
The coordinate reference system authority name and id.
@ Name
The coordinate reference system name.
@ Wkt
The coordinate reference system's WKT representation. This is only used for non-standard CRS (i....
@ Proj
The coordinate reference system's PROJ representation. This is only used for non-standard CRS (i....
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.
void removeRecent(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
void clearRecent()
Cleans the list of recently used CRS.
void pushRecent(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
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.
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.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
QString celestialBodyName() const
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
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.
@ AuthId
CRS authority ID.
A sort/filter proxy model for recent coordinate reference systems.
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 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