26#include "moc_qgscoordinatereferencesystemmodel.cpp"
28using namespace Qt::StringLiterals;
31 : QAbstractItemModel(
parent )
32 , mRootNode( std::make_unique<QgsCoordinateReferenceSystemModelGroupNode>( QString(), QIcon(), QString() ) )
45 if ( !
index.isValid() )
47 return Qt::ItemFlags();
50 QgsCoordinateReferenceSystemModelNode *n = index2node(
index );
52 return Qt::ItemFlags();
54 switch ( n->nodeType() )
56 case QgsCoordinateReferenceSystemModelNode::NodeGroup:
57 return index.column() == 0 ? Qt::ItemIsEnabled : Qt::ItemFlags();
58 case QgsCoordinateReferenceSystemModelNode::NodeCrs:
59 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
66 if ( !
index.isValid() )
69 QgsCoordinateReferenceSystemModelNode *n = index2node(
index );
76 switch ( n->nodeType() )
78 case QgsCoordinateReferenceSystemModelNode::NodeGroup:
80 QgsCoordinateReferenceSystemModelGroupNode *groupNode = qgis::down_cast<QgsCoordinateReferenceSystemModelGroupNode *>( n );
83 case Qt::DecorationRole:
84 switch (
index.column() )
87 return groupNode->icon();
95 switch (
index.column() )
98 return groupNode->name();
108 font.setItalic(
true );
109 if ( groupNode->parent() == mRootNode.get() )
111 font.setBold(
true );
117 return groupNode->id();
121 case QgsCoordinateReferenceSystemModelNode::NodeCrs:
123 QgsCoordinateReferenceSystemModelCrsNode *crsNode = qgis::down_cast<QgsCoordinateReferenceSystemModelCrsNode *>( n );
126 case Qt::DisplayRole:
127 case Qt::ToolTipRole:
128 switch (
index.column() )
131 return crsNode->record().description;
135 if ( crsNode->record().authName ==
"CUSTOM"_L1 )
137 return u
"%1:%2"_s.arg( crsNode->record().authName, crsNode->record().authId );
146 return crsNode->record().description;
149 if ( !crsNode->record().authId.isEmpty() )
150 return u
"%1:%2"_s.arg( crsNode->record().authName, crsNode->record().authId );
155 return crsNode->record().deprecated;
158 return QVariant::fromValue( crsNode->record().type );
161 return crsNode->wkt();
164 return crsNode->proj();
167 return crsNode->group();
170 return crsNode->projection();
182 if ( orientation == Qt::Horizontal )
186 case Qt::DisplayRole:
190 return tr(
"Coordinate Reference System" );
192 return tr(
"Authority ID" );
207 QgsCoordinateReferenceSystemModelNode *n = index2node(
parent );
211 return n->children().count();
221 if ( !hasIndex( row, column,
parent ) )
222 return QModelIndex();
224 QgsCoordinateReferenceSystemModelNode *n = index2node(
parent );
226 return QModelIndex();
228 return createIndex( row, column, n->children().at( row ) );
233 if ( !child.isValid() )
234 return QModelIndex();
236 if ( QgsCoordinateReferenceSystemModelNode *n = index2node( child ) )
238 return indexOfParentTreeNode( n->parent() );
243 return QModelIndex();
249 const QModelIndex startIndex =
index( 0, 0 );
250 const QModelIndexList hits = match( startIndex,
static_cast<int>(
CustomRole::AuthId ), authid, 1, Qt::MatchRecursive );
251 return hits.value( 0 );
254void QgsCoordinateReferenceSystemModel::rebuild()
258 mRootNode->deleteChildren();
260 for (
const QgsCrsDbRecord &record : std::as_const( mCrsDbRecords ) )
266 for (
const QgsCoordinateReferenceSystemRegistry::UserCrsDetails &details : userCrsList )
268 QgsCrsDbRecord userRecord;
270 userRecord.
authId = QString::number( details.id );
273 addRecord( userRecord );
279void QgsCoordinateReferenceSystemModel::userCrsAdded(
const QString &
id )
282 for (
const QgsCoordinateReferenceSystemRegistry::UserCrsDetails &details : userCrsList )
284 if ( u
"USER:%1"_s.arg( details.id ) ==
id )
286 QgsCrsDbRecord userRecord;
288 userRecord.
authId = QString::number( details.id );
291 QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( u
"USER"_s );
294 auto newGroup = std::make_unique<QgsCoordinateReferenceSystemModelGroupNode>( tr(
"User-defined" ),
QgsApplication::getThemeIcon( u
"/user.svg"_s ), u
"USER"_s );
295 beginInsertRows( QModelIndex(), mRootNode->children().length(), mRootNode->children().length() );
296 group = qgis::down_cast<QgsCoordinateReferenceSystemModelGroupNode *>( mRootNode->addChildNode( std::move( newGroup ) ) );
304 const QModelIndex parentGroupIndex = node2index( group );
306 beginInsertRows( parentGroupIndex, group->children().size(), group->children().size() );
307 QgsCoordinateReferenceSystemModelCrsNode *crsNode = addRecord( userRecord );
308 crsNode->setProj( details.proj );
309 crsNode->setWkt( details.wkt );
316void QgsCoordinateReferenceSystemModel::userCrsRemoved(
long id )
318 QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( u
"USER"_s );
321 for (
int row = 0; row < group->children().size(); ++row )
323 if ( QgsCoordinateReferenceSystemModelCrsNode *crsNode =
dynamic_cast<QgsCoordinateReferenceSystemModelCrsNode *
>( group->children().at( row ) ) )
325 if ( crsNode->record().authId == QString::number(
id ) )
327 const QModelIndex parentIndex = node2index( group );
328 beginRemoveRows( parentIndex, row, row );
329 delete group->takeChild( crsNode );
338void QgsCoordinateReferenceSystemModel::userCrsChanged(
const QString &
id )
340 QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( u
"USER"_s );
343 for (
int row = 0; row < group->children().size(); ++row )
345 if ( QgsCoordinateReferenceSystemModelCrsNode *crsNode =
dynamic_cast<QgsCoordinateReferenceSystemModelCrsNode *
>( group->children().at( row ) ) )
347 if ( u
"USER:%1"_s.arg( crsNode->record().authId ) ==
id )
350 const QModelIndex parentIndex = node2index( group );
351 beginRemoveRows( parentIndex, row, row );
352 delete group->takeChild( crsNode );
363QgsCoordinateReferenceSystemModelCrsNode *QgsCoordinateReferenceSystemModel::addRecord(
const QgsCrsDbRecord &record )
365 QgsCoordinateReferenceSystemModelGroupNode *parentNode = mRootNode.get();
366 auto crsNode = std::make_unique<QgsCoordinateReferenceSystemModelCrsNode>( record );
373 groupName = tr(
"User-defined" );
377 else if ( record.
authName ==
"CUSTOM"_L1 )
380 groupId = u
"CUSTOM"_s;
385 switch ( record.
type )
390 groupName = tr(
"Geodetic" );
394 groupName = tr(
"Geocentric" );
398 groupName = tr(
"Geographic (2D)" );
403 groupName = tr(
"Geographic (3D)" );
408 groupName = tr(
"Vertical" );
413 groupName = tr(
"Projected" );
418 groupName = tr(
"Compound" );
422 groupName = tr(
"Temporal" );
426 groupName = tr(
"Engineering" );
430 groupName = tr(
"Bound" );
434 groupName = tr(
"Other" );
438 crsNode->setGroup( groupName );
440 if ( QgsCoordinateReferenceSystemModelGroupNode *group = parentNode->getChildGroupNode( groupId ) )
446 auto newGroup = std::make_unique<QgsCoordinateReferenceSystemModelGroupNode>( groupName, groupIcon, groupId );
447 parentNode = qgis::down_cast< QgsCoordinateReferenceSystemModelGroupNode * >( parentNode->addChildNode( std::move( newGroup ) ) );
453 if ( projectionName.isEmpty() )
454 projectionName = tr(
"Other" );
456 crsNode->setProjection( projectionName );
458 if ( QgsCoordinateReferenceSystemModelGroupNode *group = parentNode->getChildGroupNode( record.
projectionAcronym ) )
464 auto newGroup = std::make_unique<QgsCoordinateReferenceSystemModelGroupNode>( projectionName, QIcon(), record.
projectionAcronym );
465 parentNode = qgis::down_cast< QgsCoordinateReferenceSystemModelGroupNode * >( parentNode->addChildNode( std::move( newGroup ) ) );
469 return qgis::down_cast< QgsCoordinateReferenceSystemModelCrsNode * >( parentNode->addChildNode( std::move( crsNode ) ) );
479 QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( u
"CUSTOM"_s );
482 auto newGroup = std::make_unique<QgsCoordinateReferenceSystemModelGroupNode>( tr(
"Custom" ),
QgsApplication::getThemeIcon( u
"/user.svg"_s ), u
"CUSTOM"_s );
483 beginInsertRows( QModelIndex(), mRootNode->children().length(), mRootNode->children().length() );
484 group = qgis::down_cast< QgsCoordinateReferenceSystemModelGroupNode * >( mRootNode->addChildNode( std::move( newGroup ) ) );
489 return QModelIndex();
491 const QModelIndex parentGroupIndex = node2index( group );
493 const int newRow = group->children().size();
494 beginInsertRows( parentGroupIndex, newRow, newRow );
495 QgsCoordinateReferenceSystemModelCrsNode *node = addRecord( userRecord );
497 node->setProj( crs.
toProj() );
500 return index( newRow, 0, parentGroupIndex );
503QgsCoordinateReferenceSystemModelNode *QgsCoordinateReferenceSystemModel::index2node(
const QModelIndex &index )
const
505 if ( !
index.isValid() )
506 return mRootNode.get();
508 return reinterpret_cast<QgsCoordinateReferenceSystemModelNode *
>(
index.internalPointer() );
511QModelIndex QgsCoordinateReferenceSystemModel::node2index( QgsCoordinateReferenceSystemModelNode *node )
const
513 if ( !node || !node->parent() )
514 return QModelIndex();
516 QModelIndex parentIndex = node2index( node->parent() );
518 int row = node->parent()->children().indexOf( node );
519 Q_ASSERT( row >= 0 );
520 return index( row, 0, parentIndex );
523QModelIndex QgsCoordinateReferenceSystemModel::indexOfParentTreeNode( QgsCoordinateReferenceSystemModelNode *parentNode )
const
525 Q_ASSERT( parentNode );
527 QgsCoordinateReferenceSystemModelNode *grandParentNode = parentNode->parent();
528 if ( !grandParentNode )
529 return QModelIndex();
531 int row = grandParentNode->children().indexOf( parentNode );
532 Q_ASSERT( row >= 0 );
534 return createIndex( row, 0, parentNode );
538QgsCoordinateReferenceSystemModelNode::~QgsCoordinateReferenceSystemModelNode()
540 qDeleteAll( mChildren );
543QgsCoordinateReferenceSystemModelNode *QgsCoordinateReferenceSystemModelNode::takeChild( QgsCoordinateReferenceSystemModelNode *node )
545 return mChildren.takeAt( mChildren.indexOf( node ) );
548QgsCoordinateReferenceSystemModelNode *QgsCoordinateReferenceSystemModelNode::addChildNode( std::unique_ptr<QgsCoordinateReferenceSystemModelNode> node )
553 Q_ASSERT( !node->mParent );
554 node->mParent =
this;
556 mChildren.append( node.release() );
557 return mChildren.back();
560void QgsCoordinateReferenceSystemModelNode::deleteChildren()
562 qDeleteAll( mChildren );
566QgsCoordinateReferenceSystemModelGroupNode *QgsCoordinateReferenceSystemModelNode::getChildGroupNode(
const QString &
id )
568 for ( QgsCoordinateReferenceSystemModelNode *node : std::as_const( mChildren ) )
570 if ( node->nodeType() == NodeGroup )
572 QgsCoordinateReferenceSystemModelGroupNode *groupNode = qgis::down_cast<QgsCoordinateReferenceSystemModelGroupNode *>( node );
573 if ( groupNode && groupNode->id() ==
id )
580QgsCoordinateReferenceSystemModelGroupNode::QgsCoordinateReferenceSystemModelGroupNode(
const QString &name,
const QIcon &icon,
const QString &
id )
586QgsCoordinateReferenceSystemModelCrsNode::QgsCoordinateReferenceSystemModelCrsNode(
const QgsCrsDbRecord &record )
597 : QSortFilterProxyModel( parent )
600 setSourceModel( mModel );
601 setDynamicSortFilter(
true );
602 setSortLocaleAware(
true );
603 setFilterCaseSensitivity( Qt::CaseInsensitive );
604 setRecursiveFilteringEnabled(
true );
629 mFilterString = filter;
635 if ( mFilterAuthIds == filter )
638 mFilterAuthIds.clear();
639 mFilterAuthIds.reserve( filter.size() );
640 for (
const QString &
id : filter )
642 mFilterAuthIds.insert(
id.toUpper() );
649 if ( mFilterDeprecated == filter )
652 mFilterDeprecated = filter;
658 if ( mFilterString.trimmed().isEmpty() && !mFilters && !mFilterDeprecated && mFilterAuthIds.isEmpty() )
661 const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
662 const QgsCoordinateReferenceSystemModelNode::NodeType nodeType =
static_cast<QgsCoordinateReferenceSystemModelNode::NodeType
>(
667 case QgsCoordinateReferenceSystemModelNode::NodeGroup:
669 case QgsCoordinateReferenceSystemModelNode::NodeCrs:
674 if ( mFilterDeprecated && deprecated )
712 if ( !mFilterAuthIds.isEmpty() )
714 if ( !mFilterAuthIds.contains( authid.toUpper() ) )
718 if ( !mFilterString.trimmed().isEmpty() )
721 QString candidate = name;
723 if ( !groupName.isEmpty() )
724 candidate +=
' ' + groupName;
726 if ( !projectionName.isEmpty() )
727 candidate +=
' ' + projectionName;
737 QgsCoordinateReferenceSystemModelNode::NodeType leftType =
static_cast<QgsCoordinateReferenceSystemModelNode::NodeType
>(
740 QgsCoordinateReferenceSystemModelNode::NodeType rightType =
static_cast<QgsCoordinateReferenceSystemModelNode::NodeType
>(
744 if ( leftType != rightType )
746 if ( leftType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
748 else if ( rightType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
752 const QString leftStr = sourceModel()->data( left ).toString().toLower();
753 const QString rightStr = sourceModel()->data( right ).toString().toLower();
755 if ( leftType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
760 if ( leftGroupId ==
"USER"_L1 )
762 if ( rightGroupId ==
"USER"_L1 )
765 if ( leftGroupId ==
"CUSTOM"_L1 )
767 if ( rightGroupId ==
"CUSTOM"_L1 )
772 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
CrsType
Coordinate reference system types.
@ Compound
Compound (horizontal + vertical) CRS.
@ Projected
Projected CRS.
@ DerivedProjected
Derived projected CRS.
@ Engineering
Engineering CRS.
@ Geographic3d
3D geopraphic CRS
@ Geographic2d
2D geographic CRS
@ Geocentric
Geocentric CRS.
@ 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...
A tree model for display of known coordinate reference systems.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex addCustomCrs(const QgsCoordinateReferenceSystem &crs)
Adds a custom crs to the model.
QModelIndex parent(const QModelIndex &index) const override
QgsCoordinateReferenceSystemModel(QObject *parent=nullptr)
Constructor for QgsCoordinateReferenceSystemModel, with the specified parent object.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QModelIndex authIdToIndex(const QString &authId) const
Retrieves the model index corresponding to a CRS with the specified authId.
@ Deprecated
true if the CRS is deprecated
@ AuthId
The coordinate reference system authority name and id.
@ Projection
Projection name.
@ GroupId
The node ID (for group nodes).
@ Name
The coordinate reference system name.
@ NodeType
Corresponds to the node's type.
@ Wkt
The coordinate reference system's WKT representation. This is only used for non-standard CRS (i....
@ Type
The coordinate reference system type.
@ 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
Qt::ItemFlags flags(const QModelIndex &index) const override
int columnCount(const QModelIndex &=QModelIndex()) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QgsCoordinateReferenceSystemProxyModel(QObject *parent=nullptr)
Constructor for QgsCoordinateReferenceSystemProxyModel, with the given parent object.
void setFilterDeprecated(bool filter)
Sets whether deprecated CRS should be filtered from the results.
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Filters filters() const
Returns any filters that affect how CRS are filtered.
@ FilterVertical
Include vertical CRS (excludes compound CRS containing a vertical component).
@ FilterCompound
Include compound CRS.
@ FilterHorizontal
Include horizontal CRS (excludes compound CRS containing a horizontal component).
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.
QList< QgsCrsDbRecord > crsDbRecords() const
Returns the list of records from the QGIS srs db.
void userCrsAdded(const QString &id)
Emitted whenever a new user CRS definition is added.
void userCrsChanged(const QString &id)
Emitted whenever an existing user CRS definition is changed.
void userCrsRemoved(long id)
Emitted when the user CRS with matching id is removed from the database.
QList< QgsCoordinateReferenceSystemRegistry::UserCrsDetails > userCrsList() const
Returns a list containing the details of all registered custom (user-defined) CRSes.
static QString translateProjection(const QString &projection)
Returns a translated string for a projection method.
Represents a coordinate reference system (CRS).
QString toProj() const
Returns a Proj string representation of this CRS.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Qgis::CrsType type() const
Returns the type of the CRS.
static bool containsByWord(const QString &candidate, const QString &words, Qt::CaseSensitivity sensitivity=Qt::CaseInsensitive)
Given a candidate string, returns true if the candidate contains all the individual words from anothe...
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define BUILTIN_UNREACHABLE
QString projectionAcronym