30#include "moc_qgsprojectionselectionwidget.cpp"
32using namespace Qt::StringLiterals;
34#ifdef ENABLE_MODELTEST
40StandardCoordinateReferenceSystemsModel::StandardCoordinateReferenceSystemsModel( QObject *parent )
41 : QAbstractItemModel( parent )
44#ifdef ENABLE_MODELTEST
45 new ModelTest(
this,
this );
52 mCurrentCrs.updateDefinition();
53 mLayerCrs.updateDefinition();
54 mProjectCrs.updateDefinition();
55 mDefaultCrs.updateDefinition();
61Qt::ItemFlags StandardCoordinateReferenceSystemsModel::flags(
const QModelIndex &index )
const
63 if ( !index.isValid() )
65 return Qt::ItemFlags();
68 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
71QVariant StandardCoordinateReferenceSystemsModel::data(
const QModelIndex &index,
int role )
const
85 return tr(
"Project CRS: %1" ).arg( mProjectCrs.userFriendlyIdentifier() );
87 return tr(
"Default CRS: %1" ).arg( mDefaultCrs.userFriendlyIdentifier() );
89 return tr(
"Layer CRS: %1" ).arg( mLayerCrs.userFriendlyIdentifier() );
104 return static_cast<int>( option );
113int StandardCoordinateReferenceSystemsModel::rowCount(
const QModelIndex &parent )
const
115 if ( parent.isValid() )
121int StandardCoordinateReferenceSystemsModel::columnCount(
const QModelIndex & )
const
126QModelIndex StandardCoordinateReferenceSystemsModel::index(
int row,
int column,
const QModelIndex &parent )
const
128 if ( row < 0 || row >= rowCount() || column != 0 || parent.isValid() )
129 return QModelIndex();
131 return createIndex( row, column );
134QModelIndex StandardCoordinateReferenceSystemsModel::parent(
const QModelIndex & )
const
136 return QModelIndex();
141 if ( !index.isValid() )
165 if ( !index.isValid() )
168 const int row = index.row();
195 return QModelIndex();
213 return index( row, 0, QModelIndex() );
220 emit dataChanged( index, index );
227 emit dataChanged( index, index );
230void StandardCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
234 emit dataChanged( index, index );
241CombinedCoordinateReferenceSystemsModel::CombinedCoordinateReferenceSystemsModel( QObject *parent )
242 : QConcatenateTablesProxyModel( parent )
243 , mStandardModel( new StandardCoordinateReferenceSystemsModel( this ) )
246 addSourceModel( mStandardModel );
247 addSourceModel( mRecentModel );
250void CombinedCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
252 mStandardModel->setNotSetText( text );
255QString CombinedCoordinateReferenceSystemsModel::notSetText()
const
257 return mStandardModel->notSetText();
262 return mStandardModel->currentCrs();
268CombinedCoordinateReferenceSystemsProxyModel::CombinedCoordinateReferenceSystemsProxyModel( QObject *parent )
269 : QSortFilterProxyModel( parent )
270 , mModel( new CombinedCoordinateReferenceSystemsModel( this ) )
276 setSourceModel( mModel );
277 setDynamicSortFilter(
true );
280bool CombinedCoordinateReferenceSystemsProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex &sourceParent )
const
282 const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
285 if ( !mFilteredCrs.isEmpty() && !mFilteredCrs.contains( crs ) )
288 switch ( crs.
type() )
328 const QVariant optionInt = mModel->data( sourceIndex, StandardCoordinateReferenceSystemsModel::RoleOption );
329 if ( optionInt.isValid() )
331 if ( optionInt.toInt() > 0 )
334 if ( !mVisibleOptions.testFlag( option ) )
374 const QModelIndexList standardItemIndex = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption,
static_cast<int>( standardOption ) );
375 if ( standardItemIndex.empty() )
379 if ( standardItemCrs == crs && filterAcceptsRow( standardItemIndex.at( 0 ).row(), QModelIndex() ) )
389 mModel->standardModel()->setLayerCrs( crs );
395 mModel->standardModel()->setCurrentCrs( crs );
410void CombinedCoordinateReferenceSystemsProxyModel::setFilteredCrs(
const QList<QgsCoordinateReferenceSystem> &crses )
412 mFilteredCrs = crses;
418 mVisibleOptions.setFlag( option, enabled );
427 , mDialogTitle( tr(
"Coordinate Reference System Selector" ) )
430 mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
432 mModel =
new CombinedCoordinateReferenceSystemsProxyModel(
this );
434 mCrsComboBox->setModel( mModel );
436 const int labelMargin =
static_cast<int>( std::round( mCrsComboBox->fontMetrics().horizontalAdvance(
'X' ) ) );
437 QHBoxLayout *layout =
new QHBoxLayout();
438 layout->setContentsMargins( 0, 0, 0, 0 );
439 layout->setSpacing( 0 );
442 layout->addWidget( mCrsComboBox, 1 );
447 mWarningLabelContainer =
new QWidget();
448 QHBoxLayout *warningLayout =
new QHBoxLayout();
449 warningLayout->setContentsMargins( 0, 0, 0, 0 );
450 mWarningLabel =
new QLabel();
452 const int size =
static_cast<int>( std::max( 24.0, mCrsComboBox->minimumSize().height() * 0.5 ) );
453 mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
454 warningLayout->insertSpacing( 0, labelMargin / 2 );
455 warningLayout->insertWidget( 1, mWarningLabel );
456 mWarningLabelContainer->setLayout( warningLayout );
457 layout->addWidget( mWarningLabelContainer );
458 mWarningLabelContainer->hide();
460 layout->addSpacing( labelMargin / 2 );
462 mButton =
new QToolButton(
this );
464 mButton->setToolTip( tr(
"Select CRS" ) );
465 layout->addWidget( mButton );
467 setFocusPolicy( Qt::StrongFocus );
468 setFocusProxy( mButton );
469 setAcceptDrops(
true );
472 connect( mCrsComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsProjectionSelectionWidget::comboIndexChanged );
477 const int idx = mCrsComboBox->currentIndex();
478 if ( idx >= 0 && idx < mModel->rowCount() )
493 mModel->setOption( option, visible );
510 if ( !mModel->combinedModel()->currentCrs().isValid() )
524 mModel->combinedModel()->setNotSetText( text );
534 const QModelIndexList matches = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::Role::RoleOption,
static_cast<int>( option ) );
535 return !matches.empty();
540 mAllowTopocentricCrs = allow;
546 const QList<QgsCoordinateReferenceSystem> filteredCrses = mModel->filteredCrs();
548 QSet<QString> ogcFilter;
549 ogcFilter.reserve( filteredCrses.size() );
552 ogcFilter <<
crs.authid();
558 if ( !ogcFilter.isEmpty() )
559 mActivePanel->setOgcWmsCrsFilter( ogcFilter );
560 if ( !mMessage.isEmpty() )
561 mActivePanel->setMessage( mMessage );
562 mActivePanel->setCrs(
crs() );
564 if ( !mModel->combinedModel()->notSetText().isEmpty() )
565 mActivePanel->setNotSetText( mModel->combinedModel()->notSetText() );
567 mActivePanel->setPanelTitle( mDialogTitle );
569 if ( !mAllowTopocentricCrs )
570 mActivePanel->setAllowTopocentricCrs(
false );
574 mActivePanel->setShowNoCrs(
true );
578 if ( mIgnorePanelSignals )
581 if ( !mActivePanel->hasValidSelection() )
584 mCrsComboBox->blockSignals(
true );
586 mCrsComboBox->blockSignals(
false );
589 mIgnorePanelSignals++;
591 mIgnorePanelSignals--;
600 if ( !mMessage.isEmpty() )
602 if ( !ogcFilter.isEmpty() )
605 dlg.setWindowTitle( mDialogTitle );
607 if ( !mAllowTopocentricCrs )
610 if ( !mModel->combinedModel()->notSetText().isEmpty() )
621 mCrsComboBox->blockSignals(
true );
623 mCrsComboBox->blockSignals(
false );
630 QApplication::restoreOverrideCursor();
637 if ( !( event->possibleActions() & Qt::CopyAction ) )
643 if ( mapLayerFromMimeData( event->mimeData() ) )
646 event->setDropAction( Qt::CopyAction );
648 mCrsComboBox->setHighlighted(
true );
659 if ( mCrsComboBox->isHighlighted() )
662 mCrsComboBox->setHighlighted(
false );
673 if ( !( event->possibleActions() & Qt::CopyAction ) )
679 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
682 setFocus( Qt::MouseFocusReason );
683 event->setDropAction( Qt::CopyAction );
686 if ( layer->crs().isValid() )
693 mCrsComboBox->setHighlighted(
false );
699 return mSourceEnsemble;
704 mDialogTitle = title;
714 mModel->setFilteredCrs( crses );
719 return mModel->filters();
726 mActivePanel->setFilters(
filters );
731 if ( mSourceEnsemble == ensemble )
734 mSourceEnsemble = ensemble;
740 return mShowAccuracyWarnings;
745 mShowAccuracyWarnings = show;
746 if ( !mShowAccuracyWarnings )
747 mWarningLabelContainer->hide();
752void QgsProjectionSelectionWidget::comboIndexChanged(
int idx )
754 if ( idx >= 0 && idx < mModel->rowCount() )
757 const QVariant optionData = mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption );
767 emit
crsChanged( QgsCoordinateReferenceSystem() );
774void QgsProjectionSelectionWidget::updateWarning()
776 if ( !mShowAccuracyWarnings )
778 if ( mWarningLabelContainer->isVisible() )
779 mWarningLabelContainer->hide();
785 const double crsAccuracyWarningThreshold = QgsSettings().value( u
"/projections/crsAccuracyWarningThreshold"_s, 0.0,
QgsSettings::App ).toDouble();
788 if ( !ensemble.
isValid() || ensemble.
name() == mSourceEnsemble || ( ensemble.
accuracy() > 0 && ensemble.
accuracy() < crsAccuracyWarningThreshold ) )
790 mWarningLabelContainer->hide();
794 mWarningLabelContainer->show();
796 QString warning = u
"<p>"_s;
799 if ( !ensemble.
code().isEmpty() )
800 id = u
"<i>%1</i> (%2:%3)"_s.arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
802 id = u
"<i>%1</i>”"_s.arg( ensemble.
name() );
806 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy of <b>at best %2 meters</b>." ).arg(
id ).arg( ensemble.
accuracy() );
810 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy." ).arg(
id );
812 warning += u
"</p><p>"_s + tr(
"Use an alternative CRS if accurate positioning is required." ) + u
"</p>"_s;
814 const QList<QgsDatumEnsembleMember> members = ensemble.
members();
815 if ( !members.isEmpty() )
817 warning += u
"<p>"_s + tr(
"%1 consists of the datums:" ).arg( ensemble.
name() ) + u
"</p><ul>"_s;
819 for (
const QgsDatumEnsembleMember &member : members )
821 if ( !member.code().isEmpty() )
822 id = u
"%1 (%2:%3)"_s.arg( member.name(), member.authority(), member.code() );
825 warning += u
"<li>%1</li>"_s.arg(
id );
828 warning +=
"</ul>"_L1;
831 mWarningLabel->setToolTip( warning );
834 catch ( QgsNotSupportedException & )
836 mWarningLabelContainer->hide();
843 mModel->setCurrentCrs(
crs );
848 mCrsComboBox->blockSignals(
true );
850 mCrsComboBox->blockSignals(
false );
855 if ( crsNotSetIndex >= 0 )
857 mCrsComboBox->blockSignals(
true );
858 mCrsComboBox->setCurrentIndex( crsNotSetIndex );
859 mCrsComboBox->blockSignals(
false );
862 if ( mActivePanel && !mIgnorePanelSignals )
864 mIgnorePanelSignals++;
865 mActivePanel->setCrs(
crs );
866 mIgnorePanelSignals--;
868 if ( prevCrs !=
crs )
877 mModel->setLayerCrs(
crs );
883 return crs.userFriendlyIdentifier();
885 return tr(
"invalid projection" );
888void QgsProjectionSelectionWidget::updateTooltip()
894 setToolTip( QString() );
898QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData(
const QMimeData *data )
const
901 for (
const QgsMimeDataUtils::Uri &u : uriList )
904 if ( QgsMapLayer *layer = u.mapLayer() )
@ 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.
static QString geographicCrsAuthId()
Geographic coordinate system auth:id string for a default geographic CRS (EPSG:4326).
@ 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...
@ FilterVertical
Include vertical CRS (excludes compound CRS containing a vertical component).
@ FilterTopocentricCompatible
Include all CRS types compatible with topocentric CRS (all except projected CRS).
@ FilterCompound
Include compound CRS.
@ FilterHorizontal
Include horizontal CRS (excludes compound CRS containing a horizontal component).
void userCrsChanged(const QString &id)
Emitted whenever an existing user CRS definition is changed.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the CRS.
Qgis::CrsType type() const
Returns the type of the CRS.
QString code() const
Identification code, e.g.
QString authority() const
Authority name, e.g.
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
QList< QgsDatumEnsembleMember > members() const
Contains a list of members of the ensemble.
QString name() const
Display name of datum ensemble.
double accuracy() const
Positional accuracy (in meters).
A QComboBox subclass with the ability to "highlight" the edges of the widget.
Base class for all map layer types.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static QgsProject * instance()
Returns the QgsProject singleton instance.
void crsChanged()
Emitted when the crs() of the project has changed.
QgsCoordinateReferenceSystem crs
A generic dialog to prompt the user for a Coordinate Reference System.
void setShowNoProjection(bool show)
Sets whether a "no/invalid" projection option should be shown.
void setNotSetText(const QString &text, const QString &description=QString())
Sets the text to show for the not set option.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the initial crs to show within the dialog.
void setMessage(const QString &message)
Sets a message to show in the dialog.
QgsCoordinateReferenceSystem crs() const
Returns the CRS currently selected in the widget.
void setRequireValidSelection()
Sets the dialog to require a valid selection only, preventing users from accepting the dialog if no s...
void setOgcWmsCrsFilter(const QSet< QString > &crsFilter)
filters this dialog by the given CRSs
void setAllowTopocentricCrs(bool allow)
Sets whether the topocentric CRS type option is shown in the dialog.
A sort/filter proxy model for recent coordinate reference systems.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define BUILTIN_UNREACHABLE
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.