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