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() )
318 const QVariant optionInt = mModel->data( sourceIndex, StandardCoordinateReferenceSystemsModel::RoleOption );
319 if ( optionInt.isValid() )
321 if ( optionInt.toInt() > 0 )
324 if ( !mVisibleOptions.testFlag( option ) )
361 const QModelIndexList standardItemIndex = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption,
static_cast<int>( standardOption ) );
362 if ( standardItemIndex.empty() )
366 if ( standardItemCrs == crs && filterAcceptsRow( standardItemIndex.at( 0 ).row(), QModelIndex() ) )
376 mModel->standardModel()->setLayerCrs( crs );
382 mModel->standardModel()->setCurrentCrs( crs );
397void CombinedCoordinateReferenceSystemsProxyModel::setFilteredCrs(
const QList<QgsCoordinateReferenceSystem> &crses )
399 mFilteredCrs = crses;
405 mVisibleOptions.setFlag( option, enabled );
414 , mDialogTitle( tr(
"Coordinate Reference System Selector" ) )
417 mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
419 mModel =
new CombinedCoordinateReferenceSystemsProxyModel(
this );
421 mCrsComboBox->setModel( mModel );
423 const int labelMargin =
static_cast<int>( std::round( mCrsComboBox->fontMetrics().horizontalAdvance(
'X' ) ) );
424 QHBoxLayout *layout =
new QHBoxLayout();
425 layout->setContentsMargins( 0, 0, 0, 0 );
426 layout->setSpacing( 0 );
429 layout->addWidget( mCrsComboBox, 1 );
434 mWarningLabelContainer =
new QWidget();
435 QHBoxLayout *warningLayout =
new QHBoxLayout();
436 warningLayout->setContentsMargins( 0, 0, 0, 0 );
437 mWarningLabel =
new QLabel();
439 const int size =
static_cast<int>( std::max( 24.0, mCrsComboBox->minimumSize().height() * 0.5 ) );
440 mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
441 warningLayout->insertSpacing( 0, labelMargin / 2 );
442 warningLayout->insertWidget( 1, mWarningLabel );
443 mWarningLabelContainer->setLayout( warningLayout );
444 layout->addWidget( mWarningLabelContainer );
445 mWarningLabelContainer->hide();
447 layout->addSpacing( labelMargin / 2 );
449 mButton =
new QToolButton(
this );
451 mButton->setToolTip( tr(
"Select CRS" ) );
452 layout->addWidget( mButton );
454 setFocusPolicy( Qt::StrongFocus );
455 setFocusProxy( mButton );
456 setAcceptDrops(
true );
459 connect( mCrsComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsProjectionSelectionWidget::comboIndexChanged );
464 const int idx = mCrsComboBox->currentIndex();
465 if ( idx >= 0 && idx < mModel->rowCount() )
480 mModel->setOption( option, visible );
497 if ( !mModel->combinedModel()->currentCrs().isValid() )
511 mModel->combinedModel()->setNotSetText( text );
521 const QModelIndexList matches = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::Role::RoleOption,
static_cast<int>( option ) );
522 return !matches.empty();
528 const QList<QgsCoordinateReferenceSystem> filteredCrses = mModel->filteredCrs();
530 QSet<QString> ogcFilter;
531 ogcFilter.reserve( filteredCrses.size() );
534 ogcFilter <<
crs.authid();
540 if ( !ogcFilter.isEmpty() )
541 mActivePanel->setOgcWmsCrsFilter( ogcFilter );
542 if ( !mMessage.isEmpty() )
543 mActivePanel->setMessage( mMessage );
544 mActivePanel->setCrs(
crs() );
546 if ( !mModel->combinedModel()->notSetText().isEmpty() )
547 mActivePanel->setNotSetText( mModel->combinedModel()->notSetText() );
549 mActivePanel->setPanelTitle( mDialogTitle );
553 mActivePanel->setShowNoCrs(
true );
557 if ( mIgnorePanelSignals )
560 if ( !mActivePanel->hasValidSelection() )
563 mCrsComboBox->blockSignals(
true );
565 mCrsComboBox->blockSignals(
false );
568 mIgnorePanelSignals++;
570 mIgnorePanelSignals--;
579 if ( !mMessage.isEmpty() )
581 if ( !ogcFilter.isEmpty() )
584 dlg.setWindowTitle( mDialogTitle );
586 if ( !mModel->combinedModel()->notSetText().isEmpty() )
597 mCrsComboBox->blockSignals(
true );
599 mCrsComboBox->blockSignals(
false );
606 QApplication::restoreOverrideCursor();
613 if ( !( event->possibleActions() & Qt::CopyAction ) )
619 if ( mapLayerFromMimeData( event->mimeData() ) )
622 event->setDropAction( Qt::CopyAction );
624 mCrsComboBox->setHighlighted(
true );
635 if ( mCrsComboBox->isHighlighted() )
638 mCrsComboBox->setHighlighted(
false );
649 if ( !( event->possibleActions() & Qt::CopyAction ) )
655 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
658 setFocus( Qt::MouseFocusReason );
659 event->setDropAction( Qt::CopyAction );
662 if ( layer->crs().isValid() )
669 mCrsComboBox->setHighlighted(
false );
675 return mSourceEnsemble;
680 mDialogTitle = title;
690 mModel->setFilteredCrs( crses );
695 return mModel->filters();
702 mActivePanel->setFilters(
filters );
707 if ( mSourceEnsemble == ensemble )
710 mSourceEnsemble = ensemble;
716 return mShowAccuracyWarnings;
721 mShowAccuracyWarnings = show;
722 if ( !mShowAccuracyWarnings )
723 mWarningLabelContainer->hide();
728void QgsProjectionSelectionWidget::comboIndexChanged(
int idx )
730 if ( idx >= 0 && idx < mModel->rowCount() )
733 const QVariant optionData = mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption );
743 emit
crsChanged( QgsCoordinateReferenceSystem() );
750void QgsProjectionSelectionWidget::updateWarning()
752 if ( !mShowAccuracyWarnings )
754 if ( mWarningLabelContainer->isVisible() )
755 mWarningLabelContainer->hide();
761 const double crsAccuracyWarningThreshold = QgsSettings().value( u
"/projections/crsAccuracyWarningThreshold"_s, 0.0,
QgsSettings::App ).toDouble();
764 if ( !ensemble.
isValid() || ensemble.
name() == mSourceEnsemble || ( ensemble.
accuracy() > 0 && ensemble.
accuracy() < crsAccuracyWarningThreshold ) )
766 mWarningLabelContainer->hide();
770 mWarningLabelContainer->show();
772 QString warning = u
"<p>"_s;
775 if ( !ensemble.
code().isEmpty() )
776 id = u
"<i>%1</i> (%2:%3)"_s.arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
778 id = u
"<i>%1</i>”"_s.arg( ensemble.
name() );
782 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() );
786 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy." ).arg(
id );
788 warning += u
"</p><p>"_s + tr(
"Use an alternative CRS if accurate positioning is required." ) + u
"</p>"_s;
790 const QList<QgsDatumEnsembleMember> members = ensemble.
members();
791 if ( !members.isEmpty() )
793 warning += u
"<p>"_s + tr(
"%1 consists of the datums:" ).arg( ensemble.
name() ) + u
"</p><ul>"_s;
795 for (
const QgsDatumEnsembleMember &member : members )
797 if ( !member.code().isEmpty() )
798 id = u
"%1 (%2:%3)"_s.arg( member.name(), member.authority(), member.code() );
801 warning += u
"<li>%1</li>"_s.arg(
id );
804 warning +=
"</ul>"_L1;
807 mWarningLabel->setToolTip( warning );
810 catch ( QgsNotSupportedException & )
812 mWarningLabelContainer->hide();
819 mModel->setCurrentCrs(
crs );
824 mCrsComboBox->blockSignals(
true );
826 mCrsComboBox->blockSignals(
false );
831 if ( crsNotSetIndex >= 0 )
833 mCrsComboBox->blockSignals(
true );
834 mCrsComboBox->setCurrentIndex( crsNotSetIndex );
835 mCrsComboBox->blockSignals(
false );
838 if ( mActivePanel && !mIgnorePanelSignals )
840 mIgnorePanelSignals++;
841 mActivePanel->setCrs(
crs );
842 mIgnorePanelSignals--;
844 if ( prevCrs !=
crs )
853 mModel->setLayerCrs(
crs );
859 return crs.userFriendlyIdentifier();
861 return tr(
"invalid projection" );
864void QgsProjectionSelectionWidget::updateTooltip()
870 setToolTip( QString() );
874QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData(
const QMimeData *data )
const
877 for (
const QgsMimeDataUtils::Uri &u : uriList )
880 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).
@ 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
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.