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();
63Qt::ItemFlags StandardCoordinateReferenceSystemsModel::flags(
const QModelIndex &index )
const
65 if ( !index.isValid() )
67 return Qt::ItemFlags();
70 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
73QVariant StandardCoordinateReferenceSystemsModel::data(
const QModelIndex &index,
int role )
const
87 return tr(
"Project CRS: %1" ).arg( mProjectCrs.userFriendlyIdentifier() );
89 return tr(
"Default CRS: %1" ).arg( mDefaultCrs.userFriendlyIdentifier() );
91 return tr(
"Layer CRS: %1" ).arg( mLayerCrs.userFriendlyIdentifier() );
106 return static_cast<int>( option );
115int StandardCoordinateReferenceSystemsModel::rowCount(
const QModelIndex &parent )
const
117 if ( parent.isValid() )
123int StandardCoordinateReferenceSystemsModel::columnCount(
const QModelIndex & )
const
128QModelIndex StandardCoordinateReferenceSystemsModel::index(
int row,
int column,
const QModelIndex &parent )
const
130 if ( row < 0 || row >= rowCount() || column != 0 || parent.isValid() )
131 return QModelIndex();
133 return createIndex( row, column );
136QModelIndex StandardCoordinateReferenceSystemsModel::parent(
const QModelIndex & )
const
138 return QModelIndex();
143 if ( !index.isValid() )
167 if ( !index.isValid() )
170 const int row = index.row();
197 return QModelIndex();
215 return index( row, 0, QModelIndex() );
222 emit dataChanged( index, index );
229 emit dataChanged( index, index );
232void StandardCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
236 emit dataChanged( index, index );
243CombinedCoordinateReferenceSystemsModel::CombinedCoordinateReferenceSystemsModel( QObject *parent )
244 : QConcatenateTablesProxyModel( parent )
245 , mStandardModel( new StandardCoordinateReferenceSystemsModel( this ) )
248 addSourceModel( mStandardModel );
249 addSourceModel( mRecentModel );
252void CombinedCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
254 mStandardModel->setNotSetText( text );
257QString CombinedCoordinateReferenceSystemsModel::notSetText()
const
259 return mStandardModel->notSetText();
264 return mStandardModel->currentCrs();
270CombinedCoordinateReferenceSystemsProxyModel::CombinedCoordinateReferenceSystemsProxyModel( QObject *parent )
271 : QSortFilterProxyModel( parent )
272 , mModel( new CombinedCoordinateReferenceSystemsModel( this ) )
278 setSourceModel( mModel );
279 setDynamicSortFilter(
true );
282bool CombinedCoordinateReferenceSystemsProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex &sourceParent )
const
284 const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
287 if ( !mFilteredCrs.isEmpty() && !mFilteredCrs.contains( crs ) )
290 switch ( crs.
type() )
320 const QVariant optionInt = mModel->data( sourceIndex, StandardCoordinateReferenceSystemsModel::RoleOption );
321 if ( optionInt.isValid() )
323 if ( optionInt.toInt() > 0 )
326 if ( !mVisibleOptions.testFlag( option ) )
365 const QModelIndexList standardItemIndex = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption,
static_cast<int>( standardOption ) );
366 if ( standardItemIndex.empty() )
370 if ( standardItemCrs == crs && filterAcceptsRow( standardItemIndex.at( 0 ).row(), QModelIndex() ) )
380 mModel->standardModel()->setLayerCrs( crs );
386 mModel->standardModel()->setCurrentCrs( crs );
401void CombinedCoordinateReferenceSystemsProxyModel::setFilteredCrs(
const QList<QgsCoordinateReferenceSystem> &crses )
403 mFilteredCrs = crses;
409 mVisibleOptions.setFlag( option, enabled );
418 , mDialogTitle( tr(
"Coordinate Reference System Selector" ) )
421 mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
423 mModel =
new CombinedCoordinateReferenceSystemsProxyModel(
this );
425 mCrsComboBox->setModel( mModel );
427 const int labelMargin =
static_cast<int>( std::round( mCrsComboBox->fontMetrics().horizontalAdvance(
'X' ) ) );
428 QHBoxLayout *layout =
new QHBoxLayout();
429 layout->setContentsMargins( 0, 0, 0, 0 );
430 layout->setSpacing( 0 );
433 layout->addWidget( mCrsComboBox, 1 );
438 mWarningLabelContainer =
new QWidget();
439 QHBoxLayout *warningLayout =
new QHBoxLayout();
440 warningLayout->setContentsMargins( 0, 0, 0, 0 );
441 mWarningLabel =
new QLabel();
443 const int size =
static_cast<int>( std::max( 24.0, mCrsComboBox->minimumSize().height() * 0.5 ) );
444 mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
445 warningLayout->insertSpacing( 0, labelMargin / 2 );
446 warningLayout->insertWidget( 1, mWarningLabel );
447 mWarningLabelContainer->setLayout( warningLayout );
448 layout->addWidget( mWarningLabelContainer );
449 mWarningLabelContainer->hide();
451 layout->addSpacing( labelMargin / 2 );
453 mButton =
new QToolButton(
this );
455 mButton->setToolTip( tr(
"Select CRS" ) );
456 layout->addWidget( mButton );
458 setFocusPolicy( Qt::StrongFocus );
459 setFocusProxy( mButton );
460 setAcceptDrops(
true );
463 connect( mCrsComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsProjectionSelectionWidget::comboIndexChanged );
468 const int idx = mCrsComboBox->currentIndex();
469 if ( idx >= 0 && idx < mModel->rowCount() )
484 mModel->setOption( option, visible );
501 if ( !mModel->combinedModel()->currentCrs().isValid() )
515 mModel->combinedModel()->setNotSetText( text );
525 const QModelIndexList matches = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::Role::RoleOption,
static_cast<int>( option ) );
526 return !matches.empty();
532 const QList<QgsCoordinateReferenceSystem> filteredCrses = mModel->filteredCrs();
534 QSet<QString> ogcFilter;
535 ogcFilter.reserve( filteredCrses.size() );
538 ogcFilter <<
crs.authid();
544 if ( !ogcFilter.isEmpty() )
545 mActivePanel->setOgcWmsCrsFilter( ogcFilter );
546 if ( !mMessage.isEmpty() )
547 mActivePanel->setMessage( mMessage );
548 mActivePanel->setCrs(
crs() );
550 if ( !mModel->combinedModel()->notSetText().isEmpty() )
551 mActivePanel->setNotSetText( mModel->combinedModel()->notSetText() );
553 mActivePanel->setPanelTitle( mDialogTitle );
557 mActivePanel->setShowNoCrs(
true );
561 if ( mIgnorePanelSignals )
564 if ( !mActivePanel->hasValidSelection() )
567 mCrsComboBox->blockSignals(
true );
569 mCrsComboBox->blockSignals(
false );
572 mIgnorePanelSignals++;
574 mIgnorePanelSignals--;
583 if ( !mMessage.isEmpty() )
585 if ( !ogcFilter.isEmpty() )
588 dlg.setWindowTitle( mDialogTitle );
590 if ( !mModel->combinedModel()->notSetText().isEmpty() )
601 mCrsComboBox->blockSignals(
true );
603 mCrsComboBox->blockSignals(
false );
610 QApplication::restoreOverrideCursor();
617 if ( !( event->possibleActions() & Qt::CopyAction ) )
623 if ( mapLayerFromMimeData( event->mimeData() ) )
626 event->setDropAction( Qt::CopyAction );
628 mCrsComboBox->setHighlighted(
true );
639 if ( mCrsComboBox->isHighlighted() )
642 mCrsComboBox->setHighlighted(
false );
653 if ( !( event->possibleActions() & Qt::CopyAction ) )
659 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
662 setFocus( Qt::MouseFocusReason );
663 event->setDropAction( Qt::CopyAction );
666 if ( layer->crs().isValid() )
673 mCrsComboBox->setHighlighted(
false );
679 return mSourceEnsemble;
684 mDialogTitle = title;
694 mModel->setFilteredCrs( crses );
699 return mModel->filters();
706 mActivePanel->setFilters(
filters );
711 if ( mSourceEnsemble == ensemble )
714 mSourceEnsemble = ensemble;
720 return mShowAccuracyWarnings;
725 mShowAccuracyWarnings = show;
726 if ( !mShowAccuracyWarnings )
727 mWarningLabelContainer->hide();
732void QgsProjectionSelectionWidget::comboIndexChanged(
int idx )
734 if ( idx >= 0 && idx < mModel->rowCount() )
737 const QVariant optionData = mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption );
747 emit
crsChanged( QgsCoordinateReferenceSystem() );
754void QgsProjectionSelectionWidget::updateWarning()
756 if ( !mShowAccuracyWarnings )
758 if ( mWarningLabelContainer->isVisible() )
759 mWarningLabelContainer->hide();
765 const double crsAccuracyWarningThreshold = QgsSettings().value( u
"/projections/crsAccuracyWarningThreshold"_s, 0.0,
QgsSettings::App ).toDouble();
768 if ( !ensemble.
isValid() || ensemble.
name() == mSourceEnsemble || ( ensemble.
accuracy() > 0 && ensemble.
accuracy() < crsAccuracyWarningThreshold ) )
770 mWarningLabelContainer->hide();
774 mWarningLabelContainer->show();
776 QString warning = u
"<p>"_s;
779 if ( !ensemble.
code().isEmpty() )
780 id = u
"<i>%1</i> (%2:%3)"_s.arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
782 id = u
"<i>%1</i>”"_s.arg( ensemble.
name() );
786 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() );
790 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy." ).arg(
id );
792 warning += u
"</p><p>"_s + tr(
"Use an alternative CRS if accurate positioning is required." ) + u
"</p>"_s;
794 const QList<QgsDatumEnsembleMember> members = ensemble.
members();
795 if ( !members.isEmpty() )
797 warning += u
"<p>"_s + tr(
"%1 consists of the datums:" ).arg( ensemble.
name() ) + u
"</p><ul>"_s;
799 for (
const QgsDatumEnsembleMember &member : members )
801 if ( !member.code().isEmpty() )
802 id = u
"%1 (%2:%3)"_s.arg( member.name(), member.authority(), member.code() );
805 warning += u
"<li>%1</li>"_s.arg(
id );
808 warning +=
"</ul>"_L1;
811 mWarningLabel->setToolTip( warning );
814 catch ( QgsNotSupportedException & )
816 mWarningLabelContainer->hide();
823 mModel->setCurrentCrs(
crs );
828 mCrsComboBox->blockSignals(
true );
830 mCrsComboBox->blockSignals(
false );
835 if ( crsNotSetIndex >= 0 )
837 mCrsComboBox->blockSignals(
true );
838 mCrsComboBox->setCurrentIndex( crsNotSetIndex );
839 mCrsComboBox->blockSignals(
false );
842 if ( mActivePanel && !mIgnorePanelSignals )
844 mIgnorePanelSignals++;
845 mActivePanel->setCrs(
crs );
846 mIgnorePanelSignals--;
848 if ( prevCrs !=
crs )
857 mModel->setLayerCrs(
crs );
863 return crs.userFriendlyIdentifier();
865 return tr(
"invalid projection" );
868void QgsProjectionSelectionWidget::updateTooltip()
874 setToolTip( QString() );
878QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData(
const QMimeData *data )
const
881 for (
const QgsMimeDataUtils::Uri &u : uriList )
884 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.