29#include "moc_qgsprojectionselectionwidget.cpp"
31#ifdef ENABLE_MODELTEST
37StandardCoordinateReferenceSystemsModel::StandardCoordinateReferenceSystemsModel( QObject *parent )
38 : QAbstractItemModel( parent )
41#ifdef ENABLE_MODELTEST
42 new ModelTest(
this,
this );
49 mCurrentCrs.updateDefinition();
50 mLayerCrs.updateDefinition();
51 mProjectCrs.updateDefinition();
52 mDefaultCrs.updateDefinition();
60Qt::ItemFlags StandardCoordinateReferenceSystemsModel::flags(
const QModelIndex &index )
const
62 if ( !index.isValid() )
64 return Qt::ItemFlags();
67 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
70QVariant StandardCoordinateReferenceSystemsModel::data(
const QModelIndex &index,
int role )
const
84 return tr(
"Project CRS: %1" ).arg( mProjectCrs.userFriendlyIdentifier() );
86 return tr(
"Default CRS: %1" ).arg( mDefaultCrs.userFriendlyIdentifier() );
88 return tr(
"Layer CRS: %1" ).arg( mLayerCrs.userFriendlyIdentifier() );
103 return static_cast<int>( option );
112int StandardCoordinateReferenceSystemsModel::rowCount(
const QModelIndex &parent )
const
114 if ( parent.isValid() )
120int StandardCoordinateReferenceSystemsModel::columnCount(
const QModelIndex & )
const
125QModelIndex StandardCoordinateReferenceSystemsModel::index(
int row,
int column,
const QModelIndex &parent )
const
127 if ( row < 0 || row >= rowCount() || column != 0 || parent.isValid() )
128 return QModelIndex();
130 return createIndex( row, column );
133QModelIndex StandardCoordinateReferenceSystemsModel::parent(
const QModelIndex & )
const
135 return QModelIndex();
140 if ( !index.isValid() )
164 if ( !index.isValid() )
167 const int row = index.row();
194 return QModelIndex();
212 return index( row, 0, QModelIndex() );
219 emit dataChanged( index, index );
226 emit dataChanged( index, index );
229void StandardCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
233 emit dataChanged( index, index );
240CombinedCoordinateReferenceSystemsModel::CombinedCoordinateReferenceSystemsModel( QObject *parent )
241 : QConcatenateTablesProxyModel( parent )
242 , mStandardModel( new StandardCoordinateReferenceSystemsModel( this ) )
245 addSourceModel( mStandardModel );
246 addSourceModel( mRecentModel );
249void CombinedCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
251 mStandardModel->setNotSetText( text );
254QString CombinedCoordinateReferenceSystemsModel::notSetText()
const
256 return mStandardModel->notSetText();
261 return mStandardModel->currentCrs();
267CombinedCoordinateReferenceSystemsProxyModel::CombinedCoordinateReferenceSystemsProxyModel( QObject *parent )
268 : QSortFilterProxyModel( parent )
269 , mModel( new CombinedCoordinateReferenceSystemsModel( this ) )
275 setSourceModel( mModel );
276 setDynamicSortFilter(
true );
279bool CombinedCoordinateReferenceSystemsProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex &sourceParent )
const
281 const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
284 if ( !mFilteredCrs.isEmpty() && !mFilteredCrs.contains( crs ) )
287 switch ( crs.
type() )
317 const QVariant optionInt = mModel->data( sourceIndex, StandardCoordinateReferenceSystemsModel::RoleOption );
318 if ( optionInt.isValid() )
320 if ( optionInt.toInt() > 0 )
323 if ( !mVisibleOptions.testFlag( option ) )
362 const QModelIndexList standardItemIndex = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption,
static_cast<int>( standardOption ) );
363 if ( standardItemIndex.empty() )
367 if ( standardItemCrs == crs && filterAcceptsRow( standardItemIndex.at( 0 ).row(), QModelIndex() ) )
377 mModel->standardModel()->setLayerCrs( crs );
383 mModel->standardModel()->setCurrentCrs( crs );
398void CombinedCoordinateReferenceSystemsProxyModel::setFilteredCrs(
const QList<QgsCoordinateReferenceSystem> &crses )
400 mFilteredCrs = crses;
406 mVisibleOptions.setFlag( option, enabled );
415 , mDialogTitle( tr(
"Coordinate Reference System Selector" ) )
418 mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
420 mModel =
new CombinedCoordinateReferenceSystemsProxyModel(
this );
422 mCrsComboBox->setModel( mModel );
424 const int labelMargin =
static_cast<int>( std::round( mCrsComboBox->fontMetrics().horizontalAdvance(
'X' ) ) );
425 QHBoxLayout *layout =
new QHBoxLayout();
426 layout->setContentsMargins( 0, 0, 0, 0 );
427 layout->setSpacing( 0 );
430 layout->addWidget( mCrsComboBox, 1 );
435 mWarningLabelContainer =
new QWidget();
436 QHBoxLayout *warningLayout =
new QHBoxLayout();
437 warningLayout->setContentsMargins( 0, 0, 0, 0 );
438 mWarningLabel =
new QLabel();
440 const int size =
static_cast<int>( std::max( 24.0, mCrsComboBox->minimumSize().height() * 0.5 ) );
441 mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
442 warningLayout->insertSpacing( 0, labelMargin / 2 );
443 warningLayout->insertWidget( 1, mWarningLabel );
444 mWarningLabelContainer->setLayout( warningLayout );
445 layout->addWidget( mWarningLabelContainer );
446 mWarningLabelContainer->hide();
448 layout->addSpacing( labelMargin / 2 );
450 mButton =
new QToolButton(
this );
452 mButton->setToolTip( tr(
"Select CRS" ) );
453 layout->addWidget( mButton );
455 setFocusPolicy( Qt::StrongFocus );
456 setFocusProxy( mButton );
457 setAcceptDrops(
true );
460 connect( mCrsComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsProjectionSelectionWidget::comboIndexChanged );
465 const int idx = mCrsComboBox->currentIndex();
466 if ( idx >= 0 && idx < mModel->rowCount() )
481 mModel->setOption( option, visible );
498 if ( !mModel->combinedModel()->currentCrs().isValid() )
512 mModel->combinedModel()->setNotSetText( text );
522 const QModelIndexList matches = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::Role::RoleOption,
static_cast<int>( option ) );
523 return !matches.empty();
529 const QList<QgsCoordinateReferenceSystem> filteredCrses = mModel->filteredCrs();
531 QSet<QString> ogcFilter;
532 ogcFilter.reserve( filteredCrses.size() );
535 ogcFilter <<
crs.authid();
541 if ( !ogcFilter.isEmpty() )
542 mActivePanel->setOgcWmsCrsFilter( ogcFilter );
543 if ( !mMessage.isEmpty() )
544 mActivePanel->setMessage( mMessage );
545 mActivePanel->setCrs(
crs() );
547 if ( !mModel->combinedModel()->notSetText().isEmpty() )
548 mActivePanel->setNotSetText( mModel->combinedModel()->notSetText() );
550 mActivePanel->setPanelTitle( mDialogTitle );
554 mActivePanel->setShowNoCrs(
true );
558 if ( mIgnorePanelSignals )
561 if ( !mActivePanel->hasValidSelection() )
564 mCrsComboBox->blockSignals(
true );
566 mCrsComboBox->blockSignals(
false );
569 mIgnorePanelSignals++;
571 mIgnorePanelSignals--;
580 if ( !mMessage.isEmpty() )
582 if ( !ogcFilter.isEmpty() )
585 dlg.setWindowTitle( mDialogTitle );
587 if ( !mModel->combinedModel()->notSetText().isEmpty() )
598 mCrsComboBox->blockSignals(
true );
600 mCrsComboBox->blockSignals(
false );
607 QApplication::restoreOverrideCursor();
614 if ( !( event->possibleActions() & Qt::CopyAction ) )
620 if ( mapLayerFromMimeData( event->mimeData() ) )
623 event->setDropAction( Qt::CopyAction );
625 mCrsComboBox->setHighlighted(
true );
636 if ( mCrsComboBox->isHighlighted() )
639 mCrsComboBox->setHighlighted(
false );
650 if ( !( event->possibleActions() & Qt::CopyAction ) )
656 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
659 setFocus( Qt::MouseFocusReason );
660 event->setDropAction( Qt::CopyAction );
663 if ( layer->crs().isValid() )
670 mCrsComboBox->setHighlighted(
false );
676 return mSourceEnsemble;
681 mDialogTitle = title;
691 mModel->setFilteredCrs( crses );
696 return mModel->filters();
703 mActivePanel->setFilters(
filters );
708 if ( mSourceEnsemble == ensemble )
711 mSourceEnsemble = ensemble;
717 return mShowAccuracyWarnings;
722 mShowAccuracyWarnings = show;
723 if ( !mShowAccuracyWarnings )
724 mWarningLabelContainer->hide();
729void QgsProjectionSelectionWidget::comboIndexChanged(
int idx )
731 if ( idx >= 0 && idx < mModel->rowCount() )
734 const QVariant optionData = mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption );
744 emit
crsChanged( QgsCoordinateReferenceSystem() );
751void QgsProjectionSelectionWidget::updateWarning()
753 if ( !mShowAccuracyWarnings )
755 if ( mWarningLabelContainer->isVisible() )
756 mWarningLabelContainer->hide();
762 const double crsAccuracyWarningThreshold = QgsSettings().value( QStringLiteral(
"/projections/crsAccuracyWarningThreshold" ), 0.0,
QgsSettings::App ).toDouble();
765 if ( !ensemble.
isValid() || ensemble.
name() == mSourceEnsemble || ( ensemble.
accuracy() > 0 && ensemble.
accuracy() < crsAccuracyWarningThreshold ) )
767 mWarningLabelContainer->hide();
771 mWarningLabelContainer->show();
773 QString warning = QStringLiteral(
"<p>" );
776 if ( !ensemble.
code().isEmpty() )
777 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
779 id = QStringLiteral(
"<i>%1</i>”" ).arg( ensemble.
name() );
783 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() );
787 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy." ).arg(
id );
789 warning += QStringLiteral(
"</p><p>" ) + tr(
"Use an alternative CRS if accurate positioning is required." ) + QStringLiteral(
"</p>" );
791 const QList<QgsDatumEnsembleMember> members = ensemble.
members();
792 if ( !members.isEmpty() )
794 warning += QStringLiteral(
"<p>" ) + tr(
"%1 consists of the datums:" ).arg( ensemble.
name() ) + QStringLiteral(
"</p><ul>" );
796 for (
const QgsDatumEnsembleMember &member : members )
798 if ( !member.code().isEmpty() )
799 id = QStringLiteral(
"%1 (%2:%3)" ).arg( member.name(), member.authority(), member.code() );
802 warning += QStringLiteral(
"<li>%1</li>" ).arg(
id );
805 warning += QLatin1String(
"</ul>" );
808 mWarningLabel->setToolTip( warning );
811 catch ( QgsNotSupportedException & )
813 mWarningLabelContainer->hide();
820 mModel->setCurrentCrs(
crs );
825 mCrsComboBox->blockSignals(
true );
827 mCrsComboBox->blockSignals(
false );
832 if ( crsNotSetIndex >= 0 )
834 mCrsComboBox->blockSignals(
true );
835 mCrsComboBox->setCurrentIndex( crsNotSetIndex );
836 mCrsComboBox->blockSignals(
false );
839 if ( mActivePanel && !mIgnorePanelSignals )
841 mIgnorePanelSignals++;
842 mActivePanel->setCrs(
crs );
843 mIgnorePanelSignals--;
845 if ( prevCrs !=
crs )
854 mModel->setLayerCrs(
crs );
860 return crs.userFriendlyIdentifier();
862 return tr(
"invalid projection" );
865void QgsProjectionSelectionWidget::updateTooltip()
871 setToolTip( QString() );
875QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData(
const QMimeData *data )
const
878 for (
const QgsMimeDataUtils::Uri &u : uriList )
881 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.