mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-05 00:09:32 -04:00
Create a QAbstractItemModel and proxy model for displaying tree
view of coordinate reference systems
This commit is contained in:
parent
ce95f9a522
commit
731123a425
@ -0,0 +1,3 @@
|
||||
# The following has been generated automatically from src/gui/qgscoordinatereferencesystemmodel.h
|
||||
QgsCoordinateReferenceSystemProxyModel.Filters.baseClass = QgsCoordinateReferenceSystemProxyModel
|
||||
Filters = QgsCoordinateReferenceSystemProxyModel # dirty hack since SIP seems to introduce the flags in module
|
@ -0,0 +1,172 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgscoordinatereferencesystemmodel.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsCoordinateReferenceSystemModel : QAbstractItemModel
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
A tree model for display of known coordinate reference systems.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgscoordinatereferencesystemmodel.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum Roles
|
||||
{
|
||||
RoleNodeType,
|
||||
RoleName,
|
||||
RoleAuthId,
|
||||
RoleDeprecated,
|
||||
RoleType,
|
||||
RoleGroupId,
|
||||
RoleWkt,
|
||||
RoleProj,
|
||||
};
|
||||
|
||||
QgsCoordinateReferenceSystemModel( QObject *parent = 0 );
|
||||
|
||||
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
|
||||
|
||||
virtual QVariant data( const QModelIndex &index, int role ) const;
|
||||
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
|
||||
|
||||
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
|
||||
|
||||
virtual int columnCount( const QModelIndex & = QModelIndex() ) const;
|
||||
|
||||
virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
|
||||
|
||||
virtual QModelIndex parent( const QModelIndex &index ) const;
|
||||
|
||||
|
||||
void addCustomCrs( const QgsCoordinateReferenceSystem &crs );
|
||||
%Docstring
|
||||
Adds a custom ``crs`` to the model.
|
||||
|
||||
This method can be used to add CRS which aren't present in either the standard PROJ SRS database or the
|
||||
user's custom CRS database to the model.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
class QgsCoordinateReferenceSystemProxyModel: QSortFilterProxyModel
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
A sort/filter proxy model for coordinate reference systems.
|
||||
|
||||
.. versionadded:: 3.34
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgscoordinatereferencesystemmodel.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum Filter
|
||||
{
|
||||
FilterHorizontal,
|
||||
FilterVertical,
|
||||
FilterCompound,
|
||||
};
|
||||
typedef QFlags<QgsCoordinateReferenceSystemProxyModel::Filter> Filters;
|
||||
|
||||
|
||||
explicit QgsCoordinateReferenceSystemProxyModel( QObject *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Constructor for QgsCoordinateReferenceSystemProxyModel, with the given ``parent`` object.
|
||||
%End
|
||||
|
||||
QgsCoordinateReferenceSystemModel *coordinateReferenceSystemModel();
|
||||
%Docstring
|
||||
Returns the underlying source model.
|
||||
%End
|
||||
|
||||
|
||||
void setFilters( QgsCoordinateReferenceSystemProxyModel::Filters filters );
|
||||
%Docstring
|
||||
Set ``filters`` that affect how CRS are filtered.
|
||||
|
||||
.. seealso:: :py:func:`filters`
|
||||
%End
|
||||
|
||||
Filters filters() const;
|
||||
%Docstring
|
||||
Returns any filters that affect how CRS are filtered.
|
||||
|
||||
.. seealso:: :py:func:`setFilters`
|
||||
%End
|
||||
|
||||
void setFilterString( const QString &filter );
|
||||
%Docstring
|
||||
Sets a ``filter`` string, such that only coordinate reference systems matching the
|
||||
specified string will be shown.
|
||||
|
||||
.. seealso:: :py:func:`filterString`
|
||||
%End
|
||||
|
||||
QString filterString() const;
|
||||
%Docstring
|
||||
Returns the current filter string, if set.
|
||||
|
||||
.. seealso:: :py:func:`setFilterString`
|
||||
%End
|
||||
|
||||
void setFilterAuthIds( const QStringList &filter );
|
||||
%Docstring
|
||||
Sets a ``filter`` list of CRS auth ID strings, such that only coordinate reference systems matching the
|
||||
specified auth IDs will be shown.
|
||||
|
||||
.. seealso:: :py:func:`filterAuthIds`
|
||||
%End
|
||||
|
||||
QStringList filterAuthIds() const;
|
||||
%Docstring
|
||||
Returns the current filter list of auth ID strings, if set.
|
||||
|
||||
.. seealso:: :py:func:`setFilterString`
|
||||
%End
|
||||
|
||||
void setFilterDeprecated( bool filter );
|
||||
%Docstring
|
||||
Sets whether deprecated CRS should be filtered from the results.
|
||||
|
||||
.. seealso:: :py:func:`filterDeprecated`
|
||||
%End
|
||||
|
||||
bool filterDeprecated() const;
|
||||
%Docstring
|
||||
Returns whether deprecated CRS will be filtered from the results.
|
||||
|
||||
.. seealso:: :py:func:`setFilterDeprecated`
|
||||
%End
|
||||
|
||||
virtual bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const;
|
||||
|
||||
virtual bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgscoordinatereferencesystemmodel.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -38,6 +38,7 @@
|
||||
%Include auto_generated/qgsconfigureshortcutsdialog.sip
|
||||
%Include auto_generated/qgscoordinateboundspreviewmapwidget.sip
|
||||
%Include auto_generated/qgscoordinateoperationwidget.sip
|
||||
%Include auto_generated/qgscoordinatereferencesystemmodel.sip
|
||||
%Include auto_generated/qgscredentialdialog.sip
|
||||
%Include auto_generated/qgscrsdefinitionwidget.sip
|
||||
%Include auto_generated/qgscurveeditorwidget.sip
|
||||
|
@ -235,7 +235,7 @@ bool QgsCoordinateReferenceSystemRegistry::updateUserCrs( long id, const QgsCoor
|
||||
|
||||
if ( res )
|
||||
{
|
||||
emit userCrsChanged( crs.d->mAuthId );
|
||||
emit userCrsChanged( QStringLiteral( "USER:%1" ).arg( id ) );
|
||||
emit crsDefinitionsChanged();
|
||||
}
|
||||
|
||||
@ -446,7 +446,7 @@ QList<QgsCrsDbRecord> QgsCoordinateReferenceSystemRegistry::crsDbRecords() const
|
||||
int result = database.open_v2( srsDatabaseFileName, SQLITE_OPEN_READONLY, nullptr );
|
||||
if ( result == SQLITE_OK )
|
||||
{
|
||||
const QString sql = QStringLiteral( "select description, srs_id, auth_name, auth_id, name, deprecated, srs_type from vw_srs" );
|
||||
const QString sql = QStringLiteral( "select description, srs_id, auth_name, auth_id, projection_acronym, deprecated, srs_type from tbl_srs" );
|
||||
sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
|
||||
if ( result == SQLITE_OK )
|
||||
{
|
||||
@ -457,7 +457,7 @@ QList<QgsCrsDbRecord> QgsCoordinateReferenceSystemRegistry::crsDbRecords() const
|
||||
record.srsId = preparedStatement.columnAsText( 1 );
|
||||
record.authName = preparedStatement.columnAsText( 2 );
|
||||
record.authId = preparedStatement.columnAsText( 3 );
|
||||
record.name = preparedStatement.columnAsText( 4 );
|
||||
record.projectionAcronym = preparedStatement.columnAsText( 4 );
|
||||
record.deprecated = preparedStatement.columnAsText( 5 ).toInt();
|
||||
record.type = qgsEnumKeyToValue( preparedStatement.columnAsText( 6 ), Qgis::CrsType::Unknown );
|
||||
mCrsDbRecords.append( record );
|
||||
|
@ -41,7 +41,7 @@ class QgsProjOperation;
|
||||
struct CORE_EXPORT QgsCrsDbRecord
|
||||
{
|
||||
QString description;
|
||||
QString name;
|
||||
QString projectionAcronym;
|
||||
QString srsId;
|
||||
QString authName;
|
||||
QString authId;
|
||||
|
@ -515,6 +515,7 @@ set(QGIS_GUI_SRCS
|
||||
qgsconfigureshortcutsdialog.cpp
|
||||
qgscoordinateboundspreviewmapwidget.cpp
|
||||
qgscoordinateoperationwidget.cpp
|
||||
qgscoordinatereferencesystemmodel.cpp
|
||||
qgscrsdefinitionwidget.cpp
|
||||
qgscredentialdialog.cpp
|
||||
qgscustomdrophandler.cpp
|
||||
@ -786,6 +787,7 @@ set(QGIS_GUI_HDRS
|
||||
qgsconfigureshortcutsdialog.h
|
||||
qgscoordinateboundspreviewmapwidget.h
|
||||
qgscoordinateoperationwidget.h
|
||||
qgscoordinatereferencesystemmodel.h
|
||||
qgscredentialdialog.h
|
||||
qgscrsdefinitionwidget.h
|
||||
qgscurveeditorwidget.h
|
||||
|
739
src/gui/qgscoordinatereferencesystemmodel.cpp
Normal file
739
src/gui/qgscoordinatereferencesystemmodel.cpp
Normal file
@ -0,0 +1,739 @@
|
||||
/***************************************************************************
|
||||
qgscoordinatereferencesystemmodel.h
|
||||
-------------------
|
||||
begin : July 2023
|
||||
copyright : (C) 2023 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgscoordinatereferencesystemmodel.h"
|
||||
#include "qgscoordinatereferencesystemutils.h"
|
||||
#include "qgsapplication.h"
|
||||
|
||||
#include <QFont>
|
||||
|
||||
QgsCoordinateReferenceSystemModel::QgsCoordinateReferenceSystemModel( QObject *parent )
|
||||
: QAbstractItemModel( parent )
|
||||
, mRootNode( std::make_unique< QgsCoordinateReferenceSystemModelGroupNode >( QString(), QIcon(), QString() ) )
|
||||
{
|
||||
mCrsDbRecords = QgsApplication::coordinateReferenceSystemRegistry()->crsDbRecords();
|
||||
|
||||
rebuild();
|
||||
|
||||
connect( QgsApplication::coordinateReferenceSystemRegistry(), &QgsCoordinateReferenceSystemRegistry::userCrsAdded, this, &QgsCoordinateReferenceSystemModel::userCrsAdded );
|
||||
connect( QgsApplication::coordinateReferenceSystemRegistry(), &QgsCoordinateReferenceSystemRegistry::userCrsRemoved, this, &QgsCoordinateReferenceSystemModel::userCrsRemoved );
|
||||
connect( QgsApplication::coordinateReferenceSystemRegistry(), &QgsCoordinateReferenceSystemRegistry::userCrsChanged, this, &QgsCoordinateReferenceSystemModel::userCrsChanged );
|
||||
}
|
||||
|
||||
Qt::ItemFlags QgsCoordinateReferenceSystemModel::flags( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
{
|
||||
return Qt::ItemFlags();
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *n = index2node( index );
|
||||
if ( !n )
|
||||
return Qt::ItemFlags();
|
||||
|
||||
switch ( n->nodeType() )
|
||||
{
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeGroup:
|
||||
return index.column() == 0 ? Qt::ItemIsEnabled : Qt::ItemFlags();
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeCrs:
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
BUILTIN_UNREACHABLE
|
||||
}
|
||||
|
||||
QVariant QgsCoordinateReferenceSystemModel::data( const QModelIndex &index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return QVariant();
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *n = index2node( index );
|
||||
if ( !n )
|
||||
return QVariant();
|
||||
|
||||
if ( role == RoleNodeType )
|
||||
return n->nodeType();
|
||||
|
||||
switch ( n->nodeType() )
|
||||
{
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeGroup:
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelGroupNode *groupNode = qgis::down_cast< QgsCoordinateReferenceSystemModelGroupNode * >( n );
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DecorationRole:
|
||||
switch ( index.column() )
|
||||
{
|
||||
case 0:
|
||||
return groupNode->icon();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
case Qt::ToolTipRole:
|
||||
switch ( index.column() )
|
||||
{
|
||||
case 0:
|
||||
return groupNode->name();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::FontRole:
|
||||
{
|
||||
QFont font;
|
||||
font.setItalic( true );
|
||||
if ( groupNode->parent() == mRootNode.get() )
|
||||
{
|
||||
font.setBold( true );
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
case RoleGroupId:
|
||||
return groupNode->id();
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
}
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeCrs:
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelCrsNode *crsNode = qgis::down_cast< QgsCoordinateReferenceSystemModelCrsNode * >( n );
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::ToolTipRole:
|
||||
switch ( index.column() )
|
||||
{
|
||||
case 0:
|
||||
return crsNode->record().description;
|
||||
|
||||
case 1:
|
||||
{
|
||||
if ( crsNode->record().authName == QLatin1String( "CUSTOM" ) )
|
||||
return QString();
|
||||
return QStringLiteral( "%1:%2" ).arg( crsNode->record().authName, crsNode->record().authId );
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RoleName:
|
||||
return crsNode->record().description;
|
||||
|
||||
case RoleAuthId:
|
||||
return QStringLiteral( "%1:%2" ).arg( crsNode->record().authName, crsNode->record().authId );
|
||||
|
||||
case RoleDeprecated:
|
||||
return crsNode->record().deprecated;
|
||||
|
||||
case RoleType:
|
||||
return QVariant::fromValue( crsNode->record().type );
|
||||
|
||||
case RoleWkt:
|
||||
return crsNode->wkt();
|
||||
|
||||
case RoleProj:
|
||||
return crsNode->proj();
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QgsCoordinateReferenceSystemModel::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
if ( orientation == Qt::Horizontal )
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
switch ( section )
|
||||
{
|
||||
case 0:
|
||||
return tr( "Coordinate Reference System" );
|
||||
case 1:
|
||||
return tr( "Authority ID" );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int QgsCoordinateReferenceSystemModel::rowCount( const QModelIndex &parent ) const
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelNode *n = index2node( parent );
|
||||
if ( !n )
|
||||
return 0;
|
||||
|
||||
return n->children().count();
|
||||
}
|
||||
|
||||
int QgsCoordinateReferenceSystemModel::columnCount( const QModelIndex & ) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
QModelIndex QgsCoordinateReferenceSystemModel::index( int row, int column, const QModelIndex &parent ) const
|
||||
{
|
||||
if ( !hasIndex( row, column, parent ) )
|
||||
return QModelIndex();
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *n = index2node( parent );
|
||||
if ( !n )
|
||||
return QModelIndex(); // have no children
|
||||
|
||||
return createIndex( row, column, n->children().at( row ) );
|
||||
}
|
||||
|
||||
QModelIndex QgsCoordinateReferenceSystemModel::parent( const QModelIndex &child ) const
|
||||
{
|
||||
if ( !child.isValid() )
|
||||
return QModelIndex();
|
||||
|
||||
if ( QgsCoordinateReferenceSystemModelNode *n = index2node( child ) )
|
||||
{
|
||||
return indexOfParentTreeNode( n->parent() ); // must not be null
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false ); // no other node types!
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModel::rebuild()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
mRootNode->deleteChildren();
|
||||
|
||||
for ( const QgsCrsDbRecord &record : std::as_const( mCrsDbRecords ) )
|
||||
{
|
||||
addRecord( record );
|
||||
}
|
||||
|
||||
const QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> userCrsList = QgsApplication::coordinateReferenceSystemRegistry()->userCrsList();
|
||||
for ( const QgsCoordinateReferenceSystemRegistry::UserCrsDetails &details : userCrsList )
|
||||
{
|
||||
QgsCrsDbRecord userRecord;
|
||||
userRecord.authName = QStringLiteral( "USER" );
|
||||
userRecord.authId = QString::number( details.id );
|
||||
userRecord.description = details.name;
|
||||
|
||||
addRecord( userRecord );
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModel::userCrsAdded( const QString &id )
|
||||
{
|
||||
const QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> userCrsList = QgsApplication::coordinateReferenceSystemRegistry()->userCrsList();
|
||||
for ( const QgsCoordinateReferenceSystemRegistry::UserCrsDetails &details : userCrsList )
|
||||
{
|
||||
if ( QStringLiteral( "USER:%1" ).arg( details.id ) == id )
|
||||
{
|
||||
QgsCrsDbRecord userRecord;
|
||||
userRecord.authName = QStringLiteral( "USER" );
|
||||
userRecord.authId = QString::number( details.id );
|
||||
userRecord.description = details.name;
|
||||
|
||||
QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( QStringLiteral( "USER" ) );
|
||||
if ( !group )
|
||||
{
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelGroupNode > newGroup = std::make_unique< QgsCoordinateReferenceSystemModelGroupNode >(
|
||||
tr( "User Defined Coordinate Systems" ),
|
||||
QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) ), QStringLiteral( "USER" ) );
|
||||
beginInsertRows( QModelIndex(), mRootNode->children().length(), mRootNode->children().length() );
|
||||
mRootNode->addChildNode( newGroup.get() );
|
||||
endInsertRows();
|
||||
group = newGroup.release();
|
||||
}
|
||||
|
||||
const QModelIndex parentGroupIndex = node2index( group );
|
||||
|
||||
beginInsertRows( parentGroupIndex, group->children().size(), group->children().size() );
|
||||
QgsCoordinateReferenceSystemModelCrsNode *crsNode = addRecord( userRecord );
|
||||
crsNode->setProj( details.proj );
|
||||
crsNode->setWkt( details.wkt );
|
||||
endInsertRows();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModel::userCrsRemoved( long id )
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( QStringLiteral( "USER" ) );
|
||||
if ( group )
|
||||
{
|
||||
for ( int row = 0; row < group->children().size(); ++row )
|
||||
{
|
||||
if ( QgsCoordinateReferenceSystemModelCrsNode *crsNode = dynamic_cast< QgsCoordinateReferenceSystemModelCrsNode * >( group->children().at( row ) ) )
|
||||
{
|
||||
if ( crsNode->record().authId == QString::number( id ) )
|
||||
{
|
||||
const QModelIndex parentIndex = node2index( group );
|
||||
beginRemoveRows( parentIndex, row, row );
|
||||
delete group->takeChild( crsNode );
|
||||
endRemoveRows();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModel::userCrsChanged( const QString &id )
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( QStringLiteral( "USER" ) );
|
||||
if ( group )
|
||||
{
|
||||
for ( int row = 0; row < group->children().size(); ++row )
|
||||
{
|
||||
if ( QgsCoordinateReferenceSystemModelCrsNode *crsNode = dynamic_cast< QgsCoordinateReferenceSystemModelCrsNode * >( group->children().at( row ) ) )
|
||||
{
|
||||
if ( QStringLiteral( "USER:%1" ).arg( crsNode->record().authId ) == id )
|
||||
{
|
||||
// treat a change as a remove + add operation
|
||||
const QModelIndex parentIndex = node2index( group );
|
||||
beginRemoveRows( parentIndex, row, row );
|
||||
delete group->takeChild( crsNode );
|
||||
endRemoveRows();
|
||||
|
||||
userCrsAdded( id );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModelCrsNode *QgsCoordinateReferenceSystemModel::addRecord( const QgsCrsDbRecord &record )
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelGroupNode *parentNode = mRootNode.get();
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelCrsNode > crsNode = std::make_unique< QgsCoordinateReferenceSystemModelCrsNode>( record );
|
||||
|
||||
QString groupName;
|
||||
QString groupId;
|
||||
QIcon groupIcon;
|
||||
if ( record.authName == QLatin1String( "USER" ) )
|
||||
{
|
||||
groupName = tr( "User Defined Coordinate Systems" );
|
||||
groupId = QStringLiteral( "USER" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) );
|
||||
}
|
||||
else if ( record.authName == QLatin1String( "CUSTOM" ) )
|
||||
{
|
||||
// the group is guaranteed to exist at this point
|
||||
groupId = QStringLiteral( "CUSTOM" );
|
||||
}
|
||||
else
|
||||
{
|
||||
groupId = qgsEnumValueToKey( record.type );
|
||||
switch ( record.type )
|
||||
{
|
||||
case Qgis::CrsType::Unknown:
|
||||
break;
|
||||
case Qgis::CrsType::Geodetic:
|
||||
groupName = tr( "Geodetic" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) );
|
||||
break;
|
||||
case Qgis::CrsType::Geocentric:
|
||||
groupName = tr( "Geocentric" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) );
|
||||
break;
|
||||
case Qgis::CrsType::Geographic2d:
|
||||
groupName = tr( "Geographic (2D)" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Geographic3d:
|
||||
groupName = tr( "Geographic (3D)" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mIconProjectionEnabled.svg" ) );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Vertical:
|
||||
groupName = tr( "Vertical" );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Projected:
|
||||
case Qgis::CrsType::DerivedProjected:
|
||||
groupName = tr( "Projected" );
|
||||
groupIcon = QgsApplication::getThemeIcon( QStringLiteral( "/transformed.svg" ) );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Compound:
|
||||
groupName = tr( "Compound" );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Temporal:
|
||||
groupName = tr( "Temporal" );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Engineering:
|
||||
groupName = tr( "Engineering" );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Bound:
|
||||
groupName = tr( "Bound" );
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Other:
|
||||
groupName = tr( "Other" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( QgsCoordinateReferenceSystemModelGroupNode *group = parentNode->getChildGroupNode( groupId ) )
|
||||
{
|
||||
parentNode = group;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelGroupNode > newGroup = std::make_unique< QgsCoordinateReferenceSystemModelGroupNode >( groupName, groupIcon, groupId );
|
||||
parentNode->addChildNode( newGroup.get() );
|
||||
parentNode = newGroup.release();
|
||||
}
|
||||
|
||||
if ( ( record.authName != QLatin1String( "USER" ) && record.authName != QLatin1String( "CUSTOM" ) ) && ( record.type == Qgis::CrsType::Projected || record.type == Qgis::CrsType::DerivedProjected ) )
|
||||
{
|
||||
QString projectionName = QgsCoordinateReferenceSystemUtils::translateProjection( record.projectionAcronym );
|
||||
if ( projectionName.isEmpty() )
|
||||
projectionName = tr( "Other" );
|
||||
|
||||
if ( QgsCoordinateReferenceSystemModelGroupNode *group = parentNode->getChildGroupNode( record.projectionAcronym ) )
|
||||
{
|
||||
parentNode = group;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelGroupNode > newGroup = std::make_unique< QgsCoordinateReferenceSystemModelGroupNode >( projectionName, QIcon(), record.projectionAcronym );
|
||||
parentNode->addChildNode( newGroup.get() );
|
||||
parentNode = newGroup.release();
|
||||
}
|
||||
}
|
||||
|
||||
parentNode->addChildNode( crsNode.get() );
|
||||
return crsNode.release();
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModel::addCustomCrs( const QgsCoordinateReferenceSystem &crs )
|
||||
{
|
||||
QgsCrsDbRecord userRecord;
|
||||
userRecord.authName = QStringLiteral( "CUSTOM" );
|
||||
userRecord.description = crs.description().isEmpty() ? tr( "Custom CRS" ) : crs.description();
|
||||
userRecord.type = crs.type();
|
||||
|
||||
QgsCoordinateReferenceSystemModelGroupNode *group = mRootNode->getChildGroupNode( QStringLiteral( "CUSTOM" ) );
|
||||
if ( !group )
|
||||
{
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelGroupNode > newGroup = std::make_unique< QgsCoordinateReferenceSystemModelGroupNode >(
|
||||
tr( "Custom Coordinate Systems" ),
|
||||
QgsApplication::getThemeIcon( QStringLiteral( "/user.svg" ) ), QStringLiteral( "CUSTOM" ) );
|
||||
beginInsertRows( QModelIndex(), mRootNode->children().length(), mRootNode->children().length() );
|
||||
mRootNode->addChildNode( newGroup.get() );
|
||||
endInsertRows();
|
||||
group = newGroup.release();
|
||||
}
|
||||
|
||||
const QModelIndex parentGroupIndex = node2index( group );
|
||||
|
||||
beginInsertRows( parentGroupIndex, group->children().size(), group->children().size() );
|
||||
QgsCoordinateReferenceSystemModelCrsNode *node = addRecord( userRecord );
|
||||
node->setWkt( crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) );
|
||||
node->setProj( crs.toProj() );
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *QgsCoordinateReferenceSystemModel::index2node( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return mRootNode.get();
|
||||
|
||||
return reinterpret_cast<QgsCoordinateReferenceSystemModelNode *>( index.internalPointer() );
|
||||
}
|
||||
|
||||
QModelIndex QgsCoordinateReferenceSystemModel::node2index( QgsCoordinateReferenceSystemModelNode *node ) const
|
||||
{
|
||||
if ( !node || !node->parent() )
|
||||
return QModelIndex(); // this is the only root item -> invalid index
|
||||
|
||||
QModelIndex parentIndex = node2index( node->parent() );
|
||||
|
||||
int row = node->parent()->children().indexOf( node );
|
||||
Q_ASSERT( row >= 0 );
|
||||
return index( row, 0, parentIndex );
|
||||
}
|
||||
|
||||
QModelIndex QgsCoordinateReferenceSystemModel::indexOfParentTreeNode( QgsCoordinateReferenceSystemModelNode *parentNode ) const
|
||||
{
|
||||
Q_ASSERT( parentNode );
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *grandParentNode = parentNode->parent();
|
||||
if ( !grandParentNode )
|
||||
return QModelIndex(); // root node -> invalid index
|
||||
|
||||
int row = grandParentNode->children().indexOf( parentNode );
|
||||
Q_ASSERT( row >= 0 );
|
||||
|
||||
return createIndex( row, 0, parentNode );
|
||||
}
|
||||
|
||||
///@cond PRIVATE
|
||||
QgsCoordinateReferenceSystemModelNode::~QgsCoordinateReferenceSystemModelNode() = default;
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *QgsCoordinateReferenceSystemModelNode::takeChild( QgsCoordinateReferenceSystemModelNode *node )
|
||||
{
|
||||
return mChildren.takeAt( mChildren.indexOf( node ) );
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModelNode::addChildNode( QgsCoordinateReferenceSystemModelNode *node )
|
||||
{
|
||||
if ( !node )
|
||||
return;
|
||||
|
||||
Q_ASSERT( !node->mParent );
|
||||
node->mParent = this;
|
||||
|
||||
mChildren.append( node );
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemModelNode::deleteChildren()
|
||||
{
|
||||
qDeleteAll( mChildren );
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModelGroupNode *QgsCoordinateReferenceSystemModelNode::getChildGroupNode( const QString &id )
|
||||
{
|
||||
for ( QgsCoordinateReferenceSystemModelNode *node : std::as_const( mChildren ) )
|
||||
{
|
||||
if ( node->nodeType() == NodeGroup )
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelGroupNode *groupNode = qgis::down_cast< QgsCoordinateReferenceSystemModelGroupNode * >( node );
|
||||
if ( groupNode && groupNode->id() == id )
|
||||
return groupNode;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModelGroupNode::QgsCoordinateReferenceSystemModelGroupNode( const QString &name, const QIcon &icon, const QString &id )
|
||||
: mId( id )
|
||||
, mName( name )
|
||||
, mIcon( icon )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModelCrsNode::QgsCoordinateReferenceSystemModelCrsNode( const QgsCrsDbRecord &record )
|
||||
: mRecord( record )
|
||||
{
|
||||
|
||||
}
|
||||
///@endcond
|
||||
|
||||
|
||||
//
|
||||
// QgsCoordinateReferenceSystemProxyModel
|
||||
//
|
||||
|
||||
QgsCoordinateReferenceSystemProxyModel::QgsCoordinateReferenceSystemProxyModel( QObject *parent )
|
||||
: QSortFilterProxyModel( parent )
|
||||
, mModel( new QgsCoordinateReferenceSystemModel( this ) )
|
||||
{
|
||||
setSourceModel( mModel );
|
||||
setDynamicSortFilter( true );
|
||||
setSortLocaleAware( true );
|
||||
setFilterCaseSensitivity( Qt::CaseInsensitive );
|
||||
setRecursiveFilteringEnabled( true );
|
||||
sort( 0 );
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystemModel *QgsCoordinateReferenceSystemProxyModel::coordinateReferenceSystemModel()
|
||||
{
|
||||
return mModel;
|
||||
}
|
||||
|
||||
const QgsCoordinateReferenceSystemModel *QgsCoordinateReferenceSystemProxyModel::coordinateReferenceSystemModel() const
|
||||
{
|
||||
return mModel;
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemProxyModel::setFilters( QgsCoordinateReferenceSystemProxyModel::Filters filters )
|
||||
{
|
||||
if ( mFilters == filters )
|
||||
return;
|
||||
|
||||
mFilters = filters;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemProxyModel::setFilterString( const QString &filter )
|
||||
{
|
||||
mFilterString = filter;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemProxyModel::setFilterAuthIds( const QStringList &filter )
|
||||
{
|
||||
if ( mFilterAuthIds == filter )
|
||||
return;
|
||||
|
||||
mFilterAuthIds.clear();
|
||||
mFilterAuthIds.reserve( filter.size() );
|
||||
for ( const QString &id : filter )
|
||||
{
|
||||
mFilterAuthIds.insert( id.toUpper() );
|
||||
}
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void QgsCoordinateReferenceSystemProxyModel::setFilterDeprecated( bool filter )
|
||||
{
|
||||
if ( mFilterDeprecated == filter )
|
||||
return;
|
||||
|
||||
mFilterDeprecated = filter;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool QgsCoordinateReferenceSystemProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
|
||||
{
|
||||
if ( mFilterString.trimmed().isEmpty() && !mFilters && !mFilterDeprecated && mFilterAuthIds.isEmpty() )
|
||||
return true;
|
||||
|
||||
const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
|
||||
const QgsCoordinateReferenceSystemModelNode::NodeType nodeType = static_cast< QgsCoordinateReferenceSystemModelNode::NodeType >( sourceModel()->data( sourceIndex, QgsCoordinateReferenceSystemModel::RoleNodeType ).toInt() );
|
||||
switch ( nodeType )
|
||||
{
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeGroup:
|
||||
return false;
|
||||
case QgsCoordinateReferenceSystemModelNode::NodeCrs:
|
||||
break;
|
||||
}
|
||||
|
||||
const bool deprecated = sourceModel()->data( sourceIndex, QgsCoordinateReferenceSystemModel::RoleDeprecated ).toBool();
|
||||
if ( mFilterDeprecated && deprecated )
|
||||
return false;
|
||||
|
||||
if ( mFilters )
|
||||
{
|
||||
const Qgis::CrsType type = sourceModel()->data( sourceIndex, QgsCoordinateReferenceSystemModel::RoleType ).value< Qgis::CrsType >();
|
||||
switch ( type )
|
||||
{
|
||||
case Qgis::CrsType::Unknown:
|
||||
case Qgis::CrsType::Other:
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Geodetic:
|
||||
case Qgis::CrsType::Geocentric:
|
||||
case Qgis::CrsType::Geographic2d:
|
||||
case Qgis::CrsType::Geographic3d:
|
||||
case Qgis::CrsType::Projected:
|
||||
case Qgis::CrsType::Temporal:
|
||||
case Qgis::CrsType::Engineering:
|
||||
case Qgis::CrsType::Bound:
|
||||
case Qgis::CrsType::DerivedProjected:
|
||||
if ( !mFilters.testFlag( Filter::FilterHorizontal ) )
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Vertical:
|
||||
if ( !mFilters.testFlag( Filter::FilterVertical ) )
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Qgis::CrsType::Compound:
|
||||
if ( !mFilters.testFlag( Filter::FilterCompound ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const QString authid = sourceModel()->data( sourceIndex, QgsCoordinateReferenceSystemModel::RoleAuthId ).toString();
|
||||
if ( !mFilterAuthIds.isEmpty() )
|
||||
{
|
||||
if ( !mFilterAuthIds.contains( authid.toUpper() ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !mFilterString.trimmed().isEmpty() )
|
||||
{
|
||||
const QString name = sourceModel()->data( sourceIndex, QgsCoordinateReferenceSystemModel::RoleName ).toString();
|
||||
if ( !( name.contains( mFilterString, Qt::CaseInsensitive )
|
||||
|| authid.contains( mFilterString, Qt::CaseInsensitive ) ) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsCoordinateReferenceSystemProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
|
||||
{
|
||||
QgsCoordinateReferenceSystemModelNode::NodeType leftType = static_cast< QgsCoordinateReferenceSystemModelNode::NodeType >( sourceModel()->data( left, QgsCoordinateReferenceSystemModel::RoleNodeType ).toInt() );
|
||||
QgsCoordinateReferenceSystemModelNode::NodeType rightType = static_cast< QgsCoordinateReferenceSystemModelNode::NodeType >( sourceModel()->data( right, QgsCoordinateReferenceSystemModel::RoleNodeType ).toInt() );
|
||||
|
||||
if ( leftType != rightType )
|
||||
{
|
||||
if ( leftType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
|
||||
return true;
|
||||
else if ( rightType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString leftStr = sourceModel()->data( left ).toString().toLower();
|
||||
const QString rightStr = sourceModel()->data( right ).toString().toLower();
|
||||
|
||||
if ( leftType == QgsCoordinateReferenceSystemModelNode::NodeGroup )
|
||||
{
|
||||
// both are groups -- ensure USER group comes last, and CUSTOM group comes first
|
||||
const QString leftGroupId = sourceModel()->data( left, QgsCoordinateReferenceSystemModel::RoleGroupId ).toString();
|
||||
const QString rightGroupId = sourceModel()->data( left, QgsCoordinateReferenceSystemModel::RoleGroupId ).toString();
|
||||
if ( leftGroupId == QLatin1String( "USER" ) )
|
||||
return false;
|
||||
if ( rightGroupId == QLatin1String( "USER" ) )
|
||||
return true;
|
||||
|
||||
if ( leftGroupId == QLatin1String( "CUSTOM" ) )
|
||||
return true;
|
||||
if ( rightGroupId == QLatin1String( "CUSTOM" ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// default sort is alphabetical order
|
||||
return QString::localeAwareCompare( leftStr, rightStr ) < 0;
|
||||
}
|
||||
|
||||
|
391
src/gui/qgscoordinatereferencesystemmodel.h
Normal file
391
src/gui/qgscoordinatereferencesystemmodel.h
Normal file
@ -0,0 +1,391 @@
|
||||
/***************************************************************************
|
||||
qgscoordinatereferencesystemmodel.h
|
||||
-------------------
|
||||
begin : July 2023
|
||||
copyright : (C) 2023 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSCOORDINATEREFERENCESYSTEMMODEL_H
|
||||
#define QGSCOORDINATEREFERENCESYSTEMMODEL_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_sip.h"
|
||||
#include "qgis.h"
|
||||
#include "qgscoordinatereferencesystemregistry.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QIcon>
|
||||
|
||||
class QgsCoordinateReferenceSystem;
|
||||
class QgsCoordinateReferenceSystemModelGroupNode;
|
||||
|
||||
///@cond PRIVATE
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* \brief Abstract base class for nodes contained within a QgsCoordinateReferenceSystemModel.
|
||||
* \warning Not part of stable API and may change in future QGIS releases.
|
||||
* \ingroup gui
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class GUI_EXPORT QgsCoordinateReferenceSystemModelNode
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Enumeration of possible model node types
|
||||
enum NodeType
|
||||
{
|
||||
NodeGroup, //!< Group node
|
||||
NodeCrs, //!< CRS node
|
||||
};
|
||||
|
||||
virtual ~QgsCoordinateReferenceSystemModelNode();
|
||||
|
||||
/**
|
||||
* Returns the node's type.
|
||||
*/
|
||||
virtual NodeType nodeType() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the node's parent. If the node's parent is NULLPTR, then the node is a root node.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModelNode *parent() { return mParent; }
|
||||
|
||||
/**
|
||||
* Returns a list of children belonging to the node.
|
||||
*/
|
||||
QList<QgsCoordinateReferenceSystemModelNode *> children() { return mChildren; }
|
||||
|
||||
/**
|
||||
* Returns a list of children belonging to the node.
|
||||
*/
|
||||
QList<QgsCoordinateReferenceSystemModelNode *> children() const { return mChildren; }
|
||||
|
||||
/**
|
||||
* Removes the specified \a node from this node's children, and gives
|
||||
* ownership back to the caller.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModelNode *takeChild( QgsCoordinateReferenceSystemModelNode *node );
|
||||
|
||||
/**
|
||||
* Adds a child \a node to this node, transferring ownership of the node
|
||||
* to this node.
|
||||
*/
|
||||
void addChildNode( QgsCoordinateReferenceSystemModelNode *node );
|
||||
|
||||
/**
|
||||
* Deletes all child nodes from this node.
|
||||
*/
|
||||
void deleteChildren();
|
||||
|
||||
/**
|
||||
* Tries to find a child node belonging to this node, which corresponds to
|
||||
* a group node with the given group \a id. Returns NULLPTR if no matching
|
||||
* child group node was found.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModelGroupNode *getChildGroupNode( const QString &id );
|
||||
|
||||
private:
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *mParent = nullptr;
|
||||
QList<QgsCoordinateReferenceSystemModelNode *> mChildren;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Coordinate reference system model node corresponding to a group
|
||||
* \ingroup gui
|
||||
* \warning Not available in Python bindings
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class GUI_EXPORT QgsCoordinateReferenceSystemModelGroupNode : public QgsCoordinateReferenceSystemModelNode
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsCoordinateReferenceSystemModelGroupNode.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModelGroupNode( const QString &name, const QIcon &icon, const QString &id );
|
||||
|
||||
/**
|
||||
* Returns the group's ID, which is non-translated.
|
||||
*/
|
||||
QString id() const { return mId; }
|
||||
|
||||
/**
|
||||
* Returns the group's name, which is translated and user-visible.
|
||||
*/
|
||||
QString name() const { return mName; }
|
||||
|
||||
/**
|
||||
* Returns the group's icon.
|
||||
*/
|
||||
QIcon icon() const { return mIcon; }
|
||||
|
||||
NodeType nodeType() const override { return NodeGroup; }
|
||||
|
||||
private:
|
||||
|
||||
QString mId;
|
||||
QString mName;
|
||||
QIcon mIcon;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Coordinate reference system model node corresponding to a CRS.
|
||||
* \ingroup gui
|
||||
* \warning Not available in Python bindings.
|
||||
* \since QGIS 3.44
|
||||
*/
|
||||
class GUI_EXPORT QgsCoordinateReferenceSystemModelCrsNode : public QgsCoordinateReferenceSystemModelNode
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsCoordinateReferenceSystemModelCrsNode, associated
|
||||
* with the specified \a record.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModelCrsNode( const QgsCrsDbRecord &record );
|
||||
|
||||
NodeType nodeType() const override { return NodeCrs; }
|
||||
|
||||
/**
|
||||
* Returns the record associated with this node.
|
||||
*/
|
||||
const QgsCrsDbRecord &record() const { return mRecord; }
|
||||
|
||||
/**
|
||||
* Sets the \a wkt representation of the CRS.
|
||||
*
|
||||
* This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
*
|
||||
* \see wkt()
|
||||
*/
|
||||
void setWkt( const QString &wkt ) { mWkt = wkt; }
|
||||
|
||||
/**
|
||||
* Returns the WKT representation of the CRS.
|
||||
*
|
||||
* This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
*
|
||||
* \see setWkt()
|
||||
*/
|
||||
QString wkt() const { return mWkt; }
|
||||
|
||||
/**
|
||||
* Sets the \a proj representation of the CRS.
|
||||
*
|
||||
* This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
*
|
||||
* \see proj()
|
||||
*/
|
||||
void setProj( const QString &proj ) { mProj = proj; }
|
||||
|
||||
/**
|
||||
* Returns the PROJ representation of the CRS.
|
||||
*
|
||||
* This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
*
|
||||
* \see setProj()
|
||||
*/
|
||||
QString proj() const { return mProj; }
|
||||
|
||||
private:
|
||||
|
||||
const QgsCrsDbRecord mRecord;
|
||||
QString mWkt;
|
||||
QString mProj;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
///@endcond
|
||||
|
||||
/**
|
||||
* \class QgsCoordinateReferenceSystemModel
|
||||
* \ingroup core
|
||||
* \brief A tree model for display of known coordinate reference systems.
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class GUI_EXPORT QgsCoordinateReferenceSystemModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! Custom roles used by the model
|
||||
enum Roles
|
||||
{
|
||||
RoleNodeType = Qt::UserRole, //!< Corresponds to the node's type
|
||||
RoleName = Qt::UserRole + 1, //!< The coordinate reference system name
|
||||
RoleAuthId = Qt::UserRole + 2, //!< The coordinate reference system authority name and id
|
||||
RoleDeprecated = Qt::UserRole + 3, //!< TRUE if the CRS is deprecated
|
||||
RoleType = Qt::UserRole + 4, //!< The coordinate reference system type
|
||||
RoleGroupId = Qt::UserRole + 5, //!< The node ID (for group nodes)
|
||||
RoleWkt = Qt::UserRole + 6, //!< The coordinate reference system's WKT representation. This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
RoleProj = Qt::UserRole + 7, //!< The coordinate reference system's PROJ representation. This is only used for non-standard CRS (i.e. those not present in the database).
|
||||
};
|
||||
|
||||
QgsCoordinateReferenceSystemModel( QObject *parent = nullptr );
|
||||
|
||||
Qt::ItemFlags flags( const QModelIndex &index ) const override;
|
||||
QVariant data( const QModelIndex &index, int role ) const override;
|
||||
QVariant headerData( int section, Qt::Orientation orientation, int role ) const override;
|
||||
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
|
||||
int columnCount( const QModelIndex & = QModelIndex() ) const override;
|
||||
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
|
||||
QModelIndex parent( const QModelIndex &index ) const override;
|
||||
|
||||
/**
|
||||
* Adds a custom \a crs to the model.
|
||||
*
|
||||
* This method can be used to add CRS which aren't present in either the standard PROJ SRS database or the
|
||||
* user's custom CRS database to the model.
|
||||
*/
|
||||
void addCustomCrs( const QgsCoordinateReferenceSystem &crs );
|
||||
|
||||
private slots:
|
||||
|
||||
void rebuild();
|
||||
void userCrsAdded( const QString &id );
|
||||
void userCrsRemoved( long id );
|
||||
void userCrsChanged( const QString &id );
|
||||
|
||||
private:
|
||||
|
||||
QgsCoordinateReferenceSystemModelCrsNode *addRecord( const QgsCrsDbRecord &record );
|
||||
|
||||
QgsCoordinateReferenceSystemModelNode *index2node( const QModelIndex &index ) const;
|
||||
QModelIndex node2index( QgsCoordinateReferenceSystemModelNode *node ) const;
|
||||
QModelIndex indexOfParentTreeNode( QgsCoordinateReferenceSystemModelNode *parentNode ) const;
|
||||
|
||||
|
||||
std::unique_ptr< QgsCoordinateReferenceSystemModelGroupNode > mRootNode;
|
||||
|
||||
QList< QgsCrsDbRecord > mCrsDbRecords;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief A sort/filter proxy model for coordinate reference systems.
|
||||
*
|
||||
* \ingroup gui
|
||||
* \since QGIS 3.34
|
||||
*/
|
||||
class GUI_EXPORT QgsCoordinateReferenceSystemProxyModel: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
//! Available filter flags for filtering the model
|
||||
enum Filter
|
||||
{
|
||||
FilterHorizontal = 1 << 1, //!< Include horizontal CRS (excludes compound CRS containing a horizontal component)
|
||||
FilterVertical = 1 << 2, //!< Include vertical CRS (excludes compound CRS containing a vertical component)
|
||||
FilterCompound = 1 << 3, //!< Include compound CRS
|
||||
};
|
||||
Q_DECLARE_FLAGS( Filters, Filter )
|
||||
Q_FLAG( Filters )
|
||||
|
||||
/**
|
||||
* Constructor for QgsCoordinateReferenceSystemProxyModel, with the given \a parent object.
|
||||
*/
|
||||
explicit QgsCoordinateReferenceSystemProxyModel( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
/**
|
||||
* Returns the underlying source model.
|
||||
*/
|
||||
QgsCoordinateReferenceSystemModel *coordinateReferenceSystemModel();
|
||||
|
||||
/**
|
||||
* Returns the underlying source model.
|
||||
* \note Not available in Python bindings
|
||||
*/
|
||||
const QgsCoordinateReferenceSystemModel *coordinateReferenceSystemModel() const SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Set \a filters that affect how CRS are filtered.
|
||||
* \see filters()
|
||||
*/
|
||||
void setFilters( QgsCoordinateReferenceSystemProxyModel::Filters filters );
|
||||
|
||||
/**
|
||||
* Returns any filters that affect how CRS are filtered.
|
||||
* \see setFilters()
|
||||
*/
|
||||
Filters filters() const { return mFilters; }
|
||||
|
||||
/**
|
||||
* Sets a \a filter string, such that only coordinate reference systems matching the
|
||||
* specified string will be shown.
|
||||
*
|
||||
* \see filterString()
|
||||
*/
|
||||
void setFilterString( const QString &filter );
|
||||
|
||||
/**
|
||||
* Returns the current filter string, if set.
|
||||
*
|
||||
* \see setFilterString()
|
||||
*/
|
||||
QString filterString() const { return mFilterString; }
|
||||
|
||||
/**
|
||||
* Sets a \a filter list of CRS auth ID strings, such that only coordinate reference systems matching the
|
||||
* specified auth IDs will be shown.
|
||||
*
|
||||
* \see filterAuthIds()
|
||||
*/
|
||||
void setFilterAuthIds( const QStringList &filter );
|
||||
|
||||
/**
|
||||
* Returns the current filter list of auth ID strings, if set.
|
||||
*
|
||||
* \see setFilterString()
|
||||
*/
|
||||
QStringList filterAuthIds() const { return mFilterAuthIds; }
|
||||
|
||||
/**
|
||||
* Sets whether deprecated CRS should be filtered from the results.
|
||||
*
|
||||
* \see filterDeprecated()
|
||||
*/
|
||||
void setFilterDeprecated( bool filter );
|
||||
|
||||
/**
|
||||
* Returns whether deprecated CRS will be filtered from the results.
|
||||
*
|
||||
* \see setFilterDeprecated()
|
||||
*/
|
||||
bool filterDeprecated() const { return mFilterDeprecated; }
|
||||
|
||||
bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override;
|
||||
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
|
||||
|
||||
private:
|
||||
|
||||
QgsCoordinateReferenceSystemModel *mModel = nullptr;
|
||||
QString mFilterString;
|
||||
QStringList mFilterAuthIds;
|
||||
bool mFilterDeprecated = false;
|
||||
Filters mFilters = Filters();
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSCOORDINATEREFERENCESYSTEMMODEL_H
|
@ -63,6 +63,7 @@ ADD_PYTHON_TEST(PyQgsCoordinateFormatter test_qgscoordinateformatter.py)
|
||||
ADD_PYTHON_TEST(PyQgsCoordinateOperationWidget test_qgscoordinateoperationwidget.py)
|
||||
ADD_PYTHON_TEST(PyQgsConditionalFormatWidgets test_qgsconditionalformatwidgets.py)
|
||||
ADD_PYTHON_TEST(PyQgsCoordinateReferenceSystem test_qgscoordinatereferencesystem.py)
|
||||
ADD_PYTHON_TEST(PyQgsCoordinateReferenceSystemModel test_qgscoordinatereferencesystemmodel.py)
|
||||
ADD_PYTHON_TEST(PyQgsCoordinateReferenceSystemUtils test_qgscoordinatereferencesystemutils.py)
|
||||
ADD_PYTHON_TEST(PyQgsConditionalStyle test_qgsconditionalstyle.py)
|
||||
ADD_PYTHON_TEST(PyQgsConnectionRegistry test_qgsconnectionregistry.py)
|
||||
|
548
tests/src/python/test_qgscoordinatereferencesystemmodel.py
Normal file
548
tests/src/python/test_qgscoordinatereferencesystemmodel.py
Normal file
@ -0,0 +1,548 @@
|
||||
"""QGIS Unit tests for QgsCoordinateReferenceSystemModel.
|
||||
|
||||
.. note:: This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
"""
|
||||
__author__ = '(C) 2022 by Nyall Dawson'
|
||||
__date__ = '12/07/2023'
|
||||
__copyright__ = 'Copyright 2023, The QGIS Project'
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
from qgis.PyQt.QtCore import (
|
||||
Qt,
|
||||
QModelIndex
|
||||
)
|
||||
from qgis.core import (
|
||||
Qgis,
|
||||
QgsApplication,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsCoordinateReferenceSystemUtils,
|
||||
)
|
||||
from qgis.gui import (
|
||||
QgsCoordinateReferenceSystemModel,
|
||||
QgsCoordinateReferenceSystemProxyModel
|
||||
)
|
||||
|
||||
import unittest
|
||||
from qgis.testing import start_app, QgisTestCase
|
||||
|
||||
start_app()
|
||||
|
||||
|
||||
class TestQgsCoordinateReferenceSystemModel(QgisTestCase):
|
||||
|
||||
def test_model(self):
|
||||
model = QgsCoordinateReferenceSystemModel()
|
||||
# top level items -- we expect to find Projected, Geographic (2D), Geographic (3D),
|
||||
# Compound, Vertical amongst others
|
||||
self.assertGreaterEqual(model.rowCount(QModelIndex()), 5)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('Projected', top_level_items)
|
||||
self.assertIn('Geographic (2D)', top_level_items)
|
||||
self.assertIn('Geographic (3D)', top_level_items)
|
||||
self.assertIn('Compound', top_level_items)
|
||||
self.assertIn('Vertical', top_level_items)
|
||||
|
||||
# projection methods should not be at top level
|
||||
self.assertNotIn('Cassini', top_level_items)
|
||||
|
||||
# user and custom groups should not be created until required
|
||||
self.assertNotIn("User Defined Coordinate Systems", top_level_items)
|
||||
self.assertNotIn("Custom Coordinate Systems", top_level_items)
|
||||
|
||||
# check group ids
|
||||
top_level_item_group_ids = [
|
||||
model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.RoleGroupId) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('Projected', top_level_item_group_ids)
|
||||
self.assertIn('Geographic2d', top_level_item_group_ids)
|
||||
self.assertIn('Geographic3d', top_level_item_group_ids)
|
||||
self.assertIn('Compound', top_level_item_group_ids)
|
||||
self.assertIn('Vertical', top_level_item_group_ids)
|
||||
|
||||
# find WGS84 in Geographic2d group
|
||||
geographic_2d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic2d'
|
||||
][0]
|
||||
|
||||
# for proj 9, there's > 1300 crs in this group
|
||||
self.assertGreaterEqual(model.rowCount(geographic_2d_index), 1000)
|
||||
|
||||
wgs84_index = [
|
||||
model.index(row, 0, geographic_2d_index)
|
||||
for row in range(model.rowCount(geographic_2d_index))
|
||||
if model.data(model.index(row, 0, geographic_2d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4326'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(wgs84_index, Qt.DisplayRole), 'WGS 84')
|
||||
self.assertEqual(model.data(model.index(wgs84_index.row(), 1, wgs84_index.parent()), Qt.DisplayRole), 'EPSG:4326')
|
||||
self.assertEqual(model.data(wgs84_index, QgsCoordinateReferenceSystemModel.RoleName), 'WGS 84')
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
# check that same result is returned by authIdToIndex
|
||||
self.assertEqual(model.authIdToIndex('EPSG:4326'), wgs84_index)
|
||||
|
||||
# find EPSG:4329 in Geographic3d group (also tests a deprecated CRS)
|
||||
geographic_3d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic3d'
|
||||
][0]
|
||||
|
||||
# for proj 9, there's > 200 crs in this group
|
||||
self.assertGreaterEqual(model.rowCount(geographic_3d_index), 200)
|
||||
|
||||
epsg_4329_index = [
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4329'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(epsg_4329_index, Qt.DisplayRole), 'WGS 84 (3D)')
|
||||
self.assertEqual(
|
||||
model.data(model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()),
|
||||
Qt.DisplayRole), 'EPSG:4329')
|
||||
self.assertEqual(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'WGS 84 (3D)')
|
||||
self.assertTrue(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
# check that same result is returned by authIdToIndex
|
||||
self.assertEqual(model.authIdToIndex('EPSG:4329'), epsg_4329_index)
|
||||
|
||||
# find a vertical crs
|
||||
vertical_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Vertical'
|
||||
][0]
|
||||
|
||||
# for proj 9, there's > 400 crs in this group
|
||||
self.assertGreaterEqual(model.rowCount(vertical_index), 400)
|
||||
|
||||
ahd_index = [
|
||||
model.index(row, 0, vertical_index)
|
||||
for row in range(model.rowCount(vertical_index))
|
||||
if model.data(model.index(row, 0, vertical_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:5711'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(ahd_index, Qt.DisplayRole), 'AHD height')
|
||||
self.assertEqual(
|
||||
model.data(model.index(ahd_index.row(), 1, ahd_index.parent()),
|
||||
Qt.DisplayRole), 'EPSG:5711')
|
||||
self.assertEqual(model.data(ahd_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'AHD height')
|
||||
self.assertFalse(model.data(ahd_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(ahd_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(ahd_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
# check that same result is returned by authIdToIndex
|
||||
self.assertEqual(model.authIdToIndex('EPSG:5711'), ahd_index)
|
||||
|
||||
# check projected group
|
||||
projected_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Projected'
|
||||
][0]
|
||||
# for proj 9, there's > 50 projection methods in this group
|
||||
self.assertGreaterEqual(model.rowCount(projected_index), 50)
|
||||
|
||||
# find Albers equal area group
|
||||
aea_group_index = [
|
||||
model.index(row, 0, projected_index)
|
||||
for row in range(model.rowCount(projected_index))
|
||||
if model.data(model.index(row, 0, projected_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'aea'
|
||||
][0]
|
||||
# for proj 9, there's > 100 crs in this group
|
||||
self.assertGreaterEqual(model.rowCount(aea_group_index), 100)
|
||||
|
||||
# find epsg:3577 in this group
|
||||
epsg_3577_index = [
|
||||
model.index(row, 0, aea_group_index)
|
||||
for row in range(model.rowCount(aea_group_index))
|
||||
if model.data(model.index(row, 0, aea_group_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:3577'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(epsg_3577_index, Qt.DisplayRole), 'GDA94 / Australian Albers')
|
||||
self.assertEqual(
|
||||
model.data(model.index(epsg_3577_index.row(), 1, epsg_3577_index.parent()),
|
||||
Qt.DisplayRole), 'EPSG:3577')
|
||||
self.assertEqual(model.data(epsg_3577_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'GDA94 / Australian Albers')
|
||||
self.assertFalse(model.data(epsg_3577_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(epsg_3577_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(epsg_3577_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
# check that same result is returned by authIdToIndex
|
||||
self.assertEqual(model.authIdToIndex('EPSG:3577'), epsg_3577_index)
|
||||
|
||||
# now add a custom crs and ensure it appears in the model
|
||||
prev_top_level_count = model.rowCount(QModelIndex())
|
||||
registry = QgsApplication.coordinateReferenceSystemRegistry()
|
||||
crs = QgsCoordinateReferenceSystem.fromProj("+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
res = registry.addUserCrs(crs, 'my custom crs')
|
||||
self.assertEqual(res, 100000)
|
||||
|
||||
self.assertEqual(model.rowCount(QModelIndex()), prev_top_level_count + 1)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('User Defined Coordinate Systems', top_level_items)
|
||||
self.assertNotIn("Custom Coordinate Systems", top_level_items)
|
||||
|
||||
# check group ids
|
||||
top_level_item_group_ids = [
|
||||
model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.RoleGroupId) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('USER', top_level_item_group_ids)
|
||||
|
||||
# find user crs
|
||||
user_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'USER'
|
||||
][0]
|
||||
self.assertEqual(model.rowCount(user_index), 1)
|
||||
|
||||
user_crs_index = model.index(0, 0, user_index)
|
||||
# test model roles
|
||||
self.assertEqual(model.data(user_crs_index, Qt.DisplayRole), 'my custom crs')
|
||||
self.assertEqual(
|
||||
model.data(model.index(user_crs_index.row(), 1, user_crs_index.parent()),
|
||||
Qt.DisplayRole), 'USER:100000')
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'my custom crs')
|
||||
self.assertFalse(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt)[:8], 'PROJCRS[')
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj), "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
|
||||
# check that same result is returned by authIdToIndex
|
||||
self.assertEqual(model.authIdToIndex('USER:100000'), user_crs_index)
|
||||
|
||||
# modify user crs
|
||||
crs = QgsCoordinateReferenceSystem.fromProj("+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
self.assertTrue(registry.updateUserCrs(100000, crs, 'my custom crs rev 2'))
|
||||
user_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'USER'
|
||||
][0]
|
||||
self.assertEqual(model.rowCount(user_index), 1)
|
||||
|
||||
user_crs_index = model.index(0, 0, user_index)
|
||||
# test model roles
|
||||
self.assertEqual(model.data(user_crs_index, Qt.DisplayRole), 'my custom crs rev 2')
|
||||
self.assertEqual(
|
||||
model.data(model.index(user_crs_index.row(), 1, user_crs_index.parent()),
|
||||
Qt.DisplayRole), 'USER:100000')
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'my custom crs rev 2')
|
||||
self.assertFalse(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt)[:8], 'PROJCRS[')
|
||||
self.assertEqual(model.data(user_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj), "+proj=aea +lat_1=21 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
|
||||
# remove
|
||||
registry.removeUserCrs(100000)
|
||||
self.assertEqual(model.rowCount(user_index), 0)
|
||||
|
||||
# add a non-standard crs (does not correspond to any db entry)
|
||||
prev_top_level_count = model.rowCount(QModelIndex())
|
||||
crs = QgsCoordinateReferenceSystem.fromProj(
|
||||
"+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
model.addCustomCrs(crs)
|
||||
|
||||
self.assertEqual(model.rowCount(QModelIndex()), prev_top_level_count + 1)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn("Custom Coordinate Systems", top_level_items)
|
||||
|
||||
# check group ids
|
||||
top_level_item_group_ids = [
|
||||
model.data(model.index(row, 0, QModelIndex()), QgsCoordinateReferenceSystemModel.RoleGroupId) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('CUSTOM', top_level_item_group_ids)
|
||||
custom_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'CUSTOM'
|
||||
][0]
|
||||
self.assertEqual(model.rowCount(custom_index), 1)
|
||||
|
||||
custom_crs_index = model.index(0, 0, custom_index)
|
||||
# test model roles
|
||||
self.assertEqual(model.data(custom_crs_index, Qt.DisplayRole), 'Custom CRS')
|
||||
self.assertFalse(
|
||||
model.data(model.index(custom_crs_index.row(), 1, custom_crs_index.parent()),
|
||||
Qt.DisplayRole))
|
||||
self.assertEqual(model.data(custom_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName), 'Custom CRS')
|
||||
self.assertFalse(model.data(custom_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertEqual(model.data(custom_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt)[:8], 'PROJCRS[')
|
||||
self.assertEqual(model.data(custom_crs_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj), "+proj=aea +lat_1=1.5 +lat_2=-23 +lat_0=4 +lon_0=29 +x_0=10 +y_0=3 +datum=WGS84 +units=m +no_defs")
|
||||
|
||||
def test_proxy_model(self):
|
||||
model = QgsCoordinateReferenceSystemProxyModel()
|
||||
# top level items -- we expect to find Projected, Geographic (2D), Geographic (3D),
|
||||
# Compound, Vertical amongst others
|
||||
self.assertGreaterEqual(model.rowCount(QModelIndex()), 5)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('Projected', top_level_items)
|
||||
self.assertIn('Geographic (2D)', top_level_items)
|
||||
self.assertIn('Geographic (3D)', top_level_items)
|
||||
self.assertIn('Compound', top_level_items)
|
||||
self.assertIn('Vertical', top_level_items)
|
||||
|
||||
# filter by type
|
||||
model.setFilters(QgsCoordinateReferenceSystemProxyModel.FilterHorizontal)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for
|
||||
row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertIn('Projected', top_level_items)
|
||||
self.assertIn('Geographic (2D)', top_level_items)
|
||||
self.assertIn('Geographic (3D)', top_level_items)
|
||||
self.assertNotIn('Compound', top_level_items)
|
||||
self.assertNotIn('Vertical', top_level_items)
|
||||
|
||||
model.setFilters(QgsCoordinateReferenceSystemProxyModel.FilterVertical)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for
|
||||
row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertNotIn('Projected', top_level_items)
|
||||
self.assertNotIn('Geographic (2D)', top_level_items)
|
||||
self.assertNotIn('Geographic (3D)', top_level_items)
|
||||
self.assertNotIn('Compound', top_level_items)
|
||||
self.assertIn('Vertical', top_level_items)
|
||||
|
||||
model.setFilters(QgsCoordinateReferenceSystemProxyModel.FilterCompound)
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for
|
||||
row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertNotIn('Projected', top_level_items)
|
||||
self.assertNotIn('Geographic (2D)', top_level_items)
|
||||
self.assertNotIn('Geographic (3D)', top_level_items)
|
||||
self.assertIn('Compound', top_level_items)
|
||||
self.assertNotIn('Vertical', top_level_items)
|
||||
|
||||
model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters(QgsCoordinateReferenceSystemProxyModel.FilterCompound
|
||||
| QgsCoordinateReferenceSystemProxyModel.FilterVertical))
|
||||
top_level_items = [
|
||||
model.data(model.index(row, 0, QModelIndex()), Qt.DisplayRole) for
|
||||
row in range(model.rowCount(QModelIndex()))
|
||||
]
|
||||
self.assertNotIn('Projected', top_level_items)
|
||||
self.assertNotIn('Geographic (2D)', top_level_items)
|
||||
self.assertNotIn('Geographic (3D)', top_level_items)
|
||||
self.assertIn('Compound', top_level_items)
|
||||
self.assertIn('Vertical', top_level_items)
|
||||
|
||||
model.setFilters(QgsCoordinateReferenceSystemProxyModel.Filters())
|
||||
|
||||
# find WGS84 in Geographic2d group
|
||||
geographic_2d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic2d'
|
||||
][0]
|
||||
|
||||
wgs84_index = [
|
||||
model.index(row, 0, geographic_2d_index)
|
||||
for row in range(model.rowCount(geographic_2d_index))
|
||||
if model.data(model.index(row, 0, geographic_2d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4326'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(wgs84_index, Qt.DisplayRole), 'WGS 84')
|
||||
self.assertEqual(model.data(model.index(wgs84_index.row(), 1, wgs84_index.parent()), Qt.DisplayRole), 'EPSG:4326')
|
||||
self.assertEqual(model.data(wgs84_index, QgsCoordinateReferenceSystemModel.RoleName), 'WGS 84')
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(wgs84_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
# find EPSG:4329 in Geographic3d group (also tests a deprecated CRS)
|
||||
geographic_3d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic3d'
|
||||
][0]
|
||||
|
||||
epsg_4329_index = [
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4329'
|
||||
][0]
|
||||
# test model roles
|
||||
self.assertEqual(model.data(epsg_4329_index, Qt.DisplayRole), 'WGS 84 (3D)')
|
||||
self.assertEqual(
|
||||
model.data(model.index(epsg_4329_index.row(), 1, epsg_4329_index.parent()),
|
||||
Qt.DisplayRole), 'EPSG:4329')
|
||||
self.assertEqual(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleName),
|
||||
'WGS 84 (3D)')
|
||||
self.assertTrue(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleDeprecated))
|
||||
# the proj and wkt roles are only available for non-standard CRS
|
||||
self.assertFalse(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleWkt))
|
||||
self.assertFalse(model.data(epsg_4329_index,
|
||||
QgsCoordinateReferenceSystemModel.RoleProj))
|
||||
|
||||
model.setFilterDeprecated(True)
|
||||
geographic_3d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic3d'
|
||||
][0]
|
||||
self.assertFalse([
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4329'
|
||||
])
|
||||
model.setFilterDeprecated(False)
|
||||
geographic_3d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic3d'
|
||||
][0]
|
||||
epsg_4329_index = [
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4329'
|
||||
][0]
|
||||
self.assertTrue(epsg_4329_index.isValid())
|
||||
|
||||
# filter by string
|
||||
model.setFilterString('GDA94')
|
||||
geographic_3d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic3d'
|
||||
][0]
|
||||
self.assertFalse([
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4329'
|
||||
])
|
||||
epsg_4939_index = [
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4939'
|
||||
][0]
|
||||
self.assertTrue(epsg_4939_index.isValid())
|
||||
epsg_4347_index = [
|
||||
model.index(row, 0, geographic_3d_index)
|
||||
for row in range(model.rowCount(geographic_3d_index))
|
||||
if model.data(model.index(row, 0, geographic_3d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4347'
|
||||
][0]
|
||||
self.assertTrue(epsg_4347_index.isValid())
|
||||
|
||||
model.setFilterString('')
|
||||
|
||||
# set filtered list of crs to show
|
||||
model.setFilterAuthIds({'epsg:4289', 'EPSG:4196'})
|
||||
geographic_2d_index = [
|
||||
model.index(row, 0, QModelIndex())
|
||||
for row in range(model.rowCount(QModelIndex()))
|
||||
if model.data(model.index(row, 0, QModelIndex()),
|
||||
QgsCoordinateReferenceSystemModel.RoleGroupId) == 'Geographic2d'
|
||||
][0]
|
||||
self.assertFalse([
|
||||
model.index(row, 0, geographic_2d_index)
|
||||
for row in range(model.rowCount(geographic_2d_index))
|
||||
if model.data(model.index(row, 0, geographic_2d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4169'
|
||||
])
|
||||
epsg_4289_index = [
|
||||
model.index(row, 0, geographic_2d_index)
|
||||
for row in range(model.rowCount(geographic_2d_index))
|
||||
if model.data(model.index(row, 0, geographic_2d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4289'
|
||||
][0]
|
||||
self.assertTrue(epsg_4289_index.isValid())
|
||||
epsg_4196_index = [
|
||||
model.index(row, 0, geographic_2d_index)
|
||||
for row in range(model.rowCount(geographic_2d_index))
|
||||
if model.data(model.index(row, 0, geographic_2d_index),
|
||||
QgsCoordinateReferenceSystemModel.RoleAuthId) == 'EPSG:4196'
|
||||
][0]
|
||||
self.assertTrue(epsg_4196_index.isValid())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user