12#include "moc_qgsprojectionselectiontreewidget.cpp"
36#include <QResizeEvent>
38#include <QRegularExpression>
40#ifdef ENABLE_MODELTEST
52 mRecentCrsModel =
new QgsRecentCoordinateReferenceSystemTableModel(
this );
53 mRecentCrsModel->setFilters(
filters );
55 lstCoordinateSystems->setModel( mCrsModel );
56 lstCoordinateSystems->setSelectionBehavior( QAbstractItemView::SelectRows );
58 lstRecent->setModel( mRecentCrsModel );
59 lstRecent->viewport()->setAttribute( Qt::WA_Hover );
60 lstRecent->setSelectionBehavior( QAbstractItemView::SelectRows );
61 lstRecent->setRootIsDecorated(
false );
63 RemoveRecentCrsDelegate *removeDelegate =
new RemoveRecentCrsDelegate( lstRecent );
64 lstRecent->setItemDelegateForColumn( 2, removeDelegate );
65 lstRecent->viewport()->installEventFilter( removeDelegate );
67 if ( mCrsModel->rowCount() == 1 )
70 lstCoordinateSystems->expand( mCrsModel->index( 0, 0, QModelIndex() ) );
73 QFont f = teProjection->font();
74 f.setPointSize( f.pointSize() - 2 );
75 teProjection->setFont( f );
77 leSearch->setShowSearchIcon(
true );
79 connect( lstCoordinateSystems, &QTreeView::doubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked );
80 connect( lstRecent, &QTreeView::doubleClicked,
this, &QgsProjectionSelectionTreeWidget::lstRecentDoubleClicked );
81 connect( lstRecent, &QTreeView::clicked,
this, &QgsProjectionSelectionTreeWidget::lstRecentClicked );
82 connect( lstCoordinateSystems->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged );
83 connect( lstRecent->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsProjectionSelectionTreeWidget::lstRecentSelectionChanged );
84 connect( cbxHideDeprecated, &QCheckBox::toggled,
this, [=](
bool selected ) {
86 mRecentCrsModel->setFilterDeprecated( selected );
88 connect( leSearch, &QgsFilterLineEdit::textChanged,
this, [=](
const QString &filter ) {
90 mRecentCrsModel->setFilterString( filter );
91 if ( filter.length() >= 3 )
92 lstCoordinateSystems->expandAll();
95 mAreaCanvas->setVisible( mShowMap );
97 lstCoordinateSystems->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
98 lstRecent->header()->setSectionResizeMode( AuthidColumn, QHeaderView::Stretch );
101 lstRecent->header()->setMinimumSectionSize( 10 );
102 lstRecent->header()->setStretchLastSection(
false );
103 lstRecent->header()->resizeSection( ClearColumn, 20 );
106 lstRecent->setContextMenuPolicy( Qt::CustomContextMenu );
107 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, [=] {
132 if ( !mBlockSignals )
138 connect( mCheckBoxNoProjection, &QCheckBox::toggled,
this, [=](
bool checked ) {
139 if ( mCheckBoxNoProjection->isEnabled() )
141 mFrameProjections->setDisabled( checked );
146 mSplitter->restoreState( settings.value( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ) ).toByteArray() );
152 settings.
setValue( QStringLiteral(
"Windows/ProjectionSelector/splitterState" ), mSplitter->saveState() );
162 lstCoordinateSystems->header()->resizeSection( NameColumn, event->size().width() - 240 );
163 lstCoordinateSystems->header()->resizeSection( AuthidColumn, 240 );
165 lstRecent->header()->resizeSection( NameColumn, event->size().width() - 260 );
166 lstRecent->header()->resizeSection( AuthidColumn, 240 );
167 lstRecent->header()->resizeSection( ClearColumn, 20 );
172 if ( obj != lstRecent )
175 if ( ev->type() != QEvent::KeyPress )
178 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( ev );
179 if ( keyEvent->matches( QKeySequence::Delete ) )
181 const QModelIndex currentIndex = lstRecent->selectionModel()->selectedRows( 0 ).value( 0 );
182 if ( currentIndex.isValid() )
183 removeRecentCrsItem( currentIndex );
190void QgsProjectionSelectionTreeWidget::selectCrsByAuthId(
const QString &authid )
193 if ( !sourceIndex.isValid() )
196 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
197 if ( proxyIndex.isValid() )
199 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
200 lstCoordinateSystems->scrollTo( proxyIndex );
205 lstCoordinateSystems->clearSelection();
206 lstRecent->clearSelection();
207 teProjection->clear();
215 mCheckBoxNoProjection->setChecked(
true );
219 mBlockSignals =
true;
220 mCheckBoxNoProjection->setChecked(
false );
221 mBlockSignals =
false;
226 loadUnknownCrs(
crs );
239 mAreaCanvas->setCanvasRect( rect );
244 return mAreaCanvas->canvasRect();
255 mRecentCrsModel->setFilters(
filters );
256 if ( mCrsModel->rowCount() == 1 )
259 lstCoordinateSystems->expand( mCrsModel->index( 0, 0, QModelIndex() ) );
265 if ( mCheckBoxNoProjection->isEnabled() && mCheckBoxNoProjection->isChecked() )
268 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
270 if ( !authid.isEmpty() )
280 if ( !wkt.isEmpty() )
282 else if ( !proj.isEmpty() )
291 mCheckBoxNoProjection->setVisible( show );
292 mCheckBoxNoProjection->setEnabled( show );
295 mFrameProjections->setDisabled( mCheckBoxNoProjection->isChecked() );
302 mAreaCanvas->setVisible( show );
307 return !mCheckBoxNoProjection->isHidden();
312 mCheckBoxNoProjection->setText( text );
322 if ( mCheckBoxNoProjection->isChecked() )
328 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
332 return !authid.isEmpty() || !wkt.isEmpty() || !proj.isEmpty();
344 lstCoordinateSystems->selectionModel()->select( mCrsModel->mapFromSource( sourceIndex ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
345 lstCoordinateSystems->scrollTo( mCrsModel->mapFromSource( sourceIndex ) );
349void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsSelectionChanged(
const QItemSelection &selected,
const QItemSelection & )
351 if ( selected.isEmpty() )
357 const QModelIndex selectedProxyIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
358 if ( !selectedProxyIndex.isValid() )
361 lstCoordinateSystems->scrollTo( selectedProxyIndex );
362 const QModelIndex sourceIndex = mCrsModel->mapToSource( selectedProxyIndex );
369 if ( !mBlockSignals )
375 updateBoundsPreview();
378 if ( !crsAuthId.isEmpty() )
381 if ( !recentMatches.isEmpty() )
383 QgsDebugMsgLevel( QStringLiteral(
"found srs %1 in recent" ).arg( crsAuthId ), 4 );
385 lstRecent->selectionModel()->select( recentMatches.at( 0 ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
386 lstRecent->scrollTo( recentMatches.at( 0 ) );
390 QgsDebugMsgLevel( QStringLiteral(
"srs %1 not recent" ).arg( crsAuthId ), 4 );
391 lstRecent->clearSelection();
392 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
397 lstRecent->clearSelection();
398 lstCoordinateSystems->setFocus( Qt::OtherFocusReason );
404 teProjection->clear();
405 lstRecent->clearSelection();
410void QgsProjectionSelectionTreeWidget::lstCoordinateSystemsDoubleClicked(
const QModelIndex &index )
412 if ( !index.isValid() )
424void QgsProjectionSelectionTreeWidget::lstRecentSelectionChanged(
const QItemSelection &selected,
const QItemSelection & )
426 if ( selected.isEmpty() )
432 const QModelIndex selectedIndex = lstRecent->selectionModel()->selectedRows( 0 ).value( 0 );
433 if ( !selectedIndex.isValid() )
436 lstRecent->scrollTo( selectedIndex );
438 const QString selectedAuthId = mRecentCrsModel->crs( selectedIndex ).authid();
440 if ( sourceIndex.isValid() )
442 const QModelIndex proxyIndex = mCrsModel->mapFromSource( sourceIndex );
443 if ( proxyIndex.isValid() )
445 lstCoordinateSystems->selectionModel()->select( proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
446 lstCoordinateSystems->scrollTo( proxyIndex );
451void QgsProjectionSelectionTreeWidget::lstRecentDoubleClicked(
const QModelIndex &index )
454 if ( !index.isValid() )
463void QgsProjectionSelectionTreeWidget::lstRecentClicked(
const QModelIndex &index )
465 if ( index.column() == ClearColumn )
467 removeRecentCrsItem( index );
475void QgsProjectionSelectionTreeWidget::updateBoundsPreview()
482 QString extentString = tr(
"Extent not known" );
483 mAreaCanvas->setPreviewRect( rect );
486 extentString = QStringLiteral(
"%1, %2, %3, %4" )
493 QStringList properties;
495 properties << tr(
"Geographic (uses latitude and longitude for coordinates)" );
500 properties << ( currentCrs.
isDynamic() ? tr(
"Dynamic (relies on a datum which is not plate-fixed)" ) : tr(
"Static (relies on a datum which is plate-fixed)" ) );
505 if ( !celestialBody.isEmpty() )
507 properties << tr(
"Celestial body: %1" ).arg( celestialBody );
520 if ( !ensemble.
code().isEmpty() )
521 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
523 id = QStringLiteral(
"<i>%</i>”" ).arg( ensemble.
name() );
526 properties << tr(
"Based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg(
id ).arg( ensemble.
accuracy() );
530 properties << tr(
"Based on %1, which has a limited accuracy." ).arg(
id );
539 properties << tr(
"Method: %1" ).arg( operation.
description() );
541 const QString propertiesString = QStringLiteral(
"<dt><b>%1</b></dt><dd><ul><li>%2</li></ul></dd>" ).arg( tr(
"Properties" ), properties.join( QLatin1String(
"</li><li>" ) ) );
543 const QString extentHtml = QStringLiteral(
"<dt><b>%1</b></dt><dd>%2</dd>" ).arg( tr(
"Extent" ), extentString );
544 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(
" " ) ) );
545 const QString proj4String = QStringLiteral(
"<dt><b>%1</b></dt><dd><code>%2</code></dd>" ).arg( tr(
"Proj4" ), currentCrs.
toProj() );
548 const int smallerPointSize = std::max( font().pointSize() - 1, 8 );
550 const int smallerPointSize = std::max( font().pointSize() - 2, 6 );
553 const QModelIndex currentIndex = lstCoordinateSystems->selectionModel()->selectedRows( 0 ).value( 0 );
554 QString selectedName;
555 if ( currentIndex.isValid() )
559 teProjection->setText( QStringLiteral(
"<div style=\"font-size: %1pt\"><h3>%2</h3><dl>" ).arg( smallerPointSize ).arg( selectedName ) + propertiesString + wktString + proj4String + extentHtml + QStringLiteral(
"</dl></div>" ) );
571 if ( QMessageBox::question(
this, tr(
"Clear Recent CRS" ), tr(
"Are you sure you want to clear the list of recently used coordinate reference system?" ), QMessageBox::Yes | QMessageBox::No ) != QMessageBox::Yes )
578void QgsProjectionSelectionTreeWidget::removeRecentCrsItem(
const QModelIndex &index )
586QgsRecentCoordinateReferenceSystemTableModel::QgsRecentCoordinateReferenceSystemTableModel( QObject *parent )
589#ifdef ENABLE_MODELTEST
590 new ModelTest(
this,
this );
594QVariant QgsRecentCoordinateReferenceSystemTableModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
596 if ( orientation == Qt::Horizontal )
600 case Qt::DisplayRole:
604 return tr(
"Coordinate Reference System" );
606 return tr(
"Authority ID" );
621QVariant QgsRecentCoordinateReferenceSystemTableModel::data(
const QModelIndex &index,
int role )
const
623 if ( !index.isValid() )
626 const int column = index.column();
634 case Qt::DisplayRole:
635 case Qt::ToolTipRole:
648 case Qt::ToolTipRole:
649 return tr(
"Remove from recently used CRS" );
660 return QgsRecentCoordinateReferenceSystemsProxyModel::data( index, role );
668RemoveRecentCrsDelegate::RemoveRecentCrsDelegate( QObject *parent )
669 : QStyledItemDelegate( parent )
673bool RemoveRecentCrsDelegate::eventFilter( QObject *obj, QEvent *event )
675 if ( event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverMove )
677 QHoverEvent *hoverEvent =
static_cast<QHoverEvent *
>( event );
678 if ( QAbstractItemView *view = qobject_cast<QAbstractItemView *>( obj->parent() ) )
680 const QModelIndex indexUnderMouse = view->indexAt( hoverEvent->pos() );
681 setHoveredIndex( indexUnderMouse );
682 view->viewport()->update();
685 else if ( event->type() == QEvent::HoverLeave )
687 setHoveredIndex( QModelIndex() );
688 qobject_cast<QWidget *>( obj )->update();
690 return QStyledItemDelegate::eventFilter( obj, event );
693void RemoveRecentCrsDelegate::paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
695 QStyledItemDelegate::paint( painter, option, index );
697 if ( index == mHoveredIndex )
699 QStyleOptionButton buttonOption;
700 buttonOption.initFrom( option.widget );
701 buttonOption.rect = option.rect;
703 option.widget->style()->drawControl( QStyle::CE_PushButton, &buttonOption, painter );
707 const QRect iconRect( option.rect.left() + ( option.rect.width() - 16 ) / 2, option.rect.top() + ( option.rect.height() - 16 ) / 2, 16, 16 );
709 icon.paint( painter, iconRect );
712void RemoveRecentCrsDelegate::setHoveredIndex(
const QModelIndex &index )
714 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.
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