19#include "moc_qgsprojectionselectionwidget.cpp"
29#ifdef ENABLE_MODELTEST
35StandardCoordinateReferenceSystemsModel::StandardCoordinateReferenceSystemsModel( QObject *parent )
36 : QAbstractItemModel( parent )
39#ifdef ENABLE_MODELTEST
40 new ModelTest(
this,
this );
48 mCurrentCrs.updateDefinition();
49 mLayerCrs.updateDefinition();
50 mProjectCrs.updateDefinition();
51 mDefaultCrs.updateDefinition();
55Qt::ItemFlags StandardCoordinateReferenceSystemsModel::flags(
const QModelIndex &index )
const
57 if ( !index.isValid() )
59 return Qt::ItemFlags();
62 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
65QVariant StandardCoordinateReferenceSystemsModel::data(
const QModelIndex &index,
int role )
const
98 return static_cast< int >( option );
107int StandardCoordinateReferenceSystemsModel::rowCount(
const QModelIndex &parent )
const
109 if ( parent.isValid() )
115int StandardCoordinateReferenceSystemsModel::columnCount(
const QModelIndex & )
const
120QModelIndex StandardCoordinateReferenceSystemsModel::index(
int row,
int column,
const QModelIndex &parent )
const
122 if ( row < 0 || row >= rowCount() || column != 0 || parent.isValid() )
123 return QModelIndex();
125 return createIndex( row, column );
128QModelIndex StandardCoordinateReferenceSystemsModel::parent(
const QModelIndex & )
const
130 return QModelIndex();
135 if ( !index.isValid() )
159 if ( !index.isValid() )
162 const int row = index.row();
189 return QModelIndex();
207 return index( row, 0, QModelIndex() );
214 emit dataChanged( index, index );
221 emit dataChanged( index, index );
224void StandardCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
228 emit dataChanged( index, index );
235CombinedCoordinateReferenceSystemsModel::CombinedCoordinateReferenceSystemsModel( QObject *parent )
236 : QConcatenateTablesProxyModel( parent )
237 , mStandardModel( new StandardCoordinateReferenceSystemsModel( this ) )
240 addSourceModel( mStandardModel );
241 addSourceModel( mRecentModel );
244void CombinedCoordinateReferenceSystemsModel::setNotSetText(
const QString &text )
246 mStandardModel->setNotSetText( text );
249QString CombinedCoordinateReferenceSystemsModel::notSetText()
const
251 return mStandardModel->notSetText();
256 return mStandardModel->currentCrs();
262CombinedCoordinateReferenceSystemsProxyModel::CombinedCoordinateReferenceSystemsProxyModel( QObject *parent )
263 : QSortFilterProxyModel( parent )
264 , mModel( new CombinedCoordinateReferenceSystemsModel( this ) )
270 setSourceModel( mModel );
271 setDynamicSortFilter(
true );
274bool CombinedCoordinateReferenceSystemsProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex &sourceParent )
const
276 const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
279 if ( !mFilteredCrs.isEmpty() && !mFilteredCrs.contains(
crs ) )
312 const QVariant optionInt = mModel->data( sourceIndex, StandardCoordinateReferenceSystemsModel::RoleOption );
313 if ( optionInt.isValid() )
315 if ( optionInt.toInt() > 0 )
318 if ( !mVisibleOptions.testFlag( option ) )
357 const QModelIndexList standardItemIndex = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption,
static_cast< int >( standardOption ) );
358 if ( standardItemIndex.empty() )
361 const QgsCoordinateReferenceSystem standardItemCrs = mModel->data( standardItemIndex.at( 0 ), StandardCoordinateReferenceSystemsModel::RoleCrs ).value< QgsCoordinateReferenceSystem >();
362 if ( standardItemCrs ==
crs && filterAcceptsRow( standardItemIndex.at( 0 ).row(), QModelIndex() ) )
372 mModel->standardModel()->setLayerCrs(
crs );
378 mModel->standardModel()->setCurrentCrs(
crs );
393void CombinedCoordinateReferenceSystemsProxyModel::setFilteredCrs(
const QList<QgsCoordinateReferenceSystem> &crses )
395 mFilteredCrs = crses;
401 mVisibleOptions.setFlag( option, enabled );
411 , mDialogTitle( tr(
"Coordinate Reference System Selector" ) )
414 mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
416 mModel =
new CombinedCoordinateReferenceSystemsProxyModel(
this );
418 mCrsComboBox->setModel( mModel );
420 const int labelMargin =
static_cast< int >( std::round( mCrsComboBox->fontMetrics().horizontalAdvance(
'X' ) ) );
421 QHBoxLayout *layout =
new QHBoxLayout();
422 layout->setContentsMargins( 0, 0, 0, 0 );
423 layout->setSpacing( 0 );
426 layout->addWidget( mCrsComboBox, 1 );
431 mWarningLabelContainer =
new QWidget();
432 QHBoxLayout *warningLayout =
new QHBoxLayout();
433 warningLayout->setContentsMargins( 0, 0, 0, 0 );
434 mWarningLabel =
new QLabel();
436 const int size =
static_cast< int >( std::max( 24.0, mCrsComboBox->minimumSize().height() * 0.5 ) );
437 mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
438 warningLayout->insertSpacing( 0, labelMargin / 2 );
439 warningLayout->insertWidget( 1, mWarningLabel );
440 mWarningLabelContainer->setLayout( warningLayout );
441 layout->addWidget( mWarningLabelContainer );
442 mWarningLabelContainer->hide();
444 layout->addSpacing( labelMargin / 2 );
446 mButton =
new QToolButton(
this );
448 mButton->setToolTip( tr(
"Select CRS" ) );
449 layout->addWidget( mButton );
451 setFocusPolicy( Qt::StrongFocus );
452 setFocusProxy( mButton );
453 setAcceptDrops(
true );
456 connect( mCrsComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsProjectionSelectionWidget::comboIndexChanged );
461 const int idx = mCrsComboBox->currentIndex();
462 if ( idx >= 0 && idx < mModel->rowCount() )
463 return mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleCrs ).value<
QgsCoordinateReferenceSystem >();
477 mModel->setOption( option, visible );
494 if ( !mModel->combinedModel()->currentCrs().isValid() )
508 mModel->combinedModel()->setNotSetText( text );
518 const QModelIndexList matches = mModel->match( mModel->index( 0, 0 ), StandardCoordinateReferenceSystemsModel::Role::RoleOption,
static_cast< int >( option ) );
519 return !matches.empty();
525 const QList< QgsCoordinateReferenceSystem > filteredCrses = mModel->filteredCrs();
527 QSet< QString > ogcFilter;
528 ogcFilter.reserve( filteredCrses.size( ) );
537 if ( !ogcFilter.isEmpty() )
538 mActivePanel->setOgcWmsCrsFilter( ogcFilter );
539 if ( !mMessage.isEmpty() )
540 mActivePanel->setMessage( mMessage );
541 mActivePanel->setCrs(
crs() );
543 if ( !mModel->combinedModel()->notSetText().isEmpty() )
544 mActivePanel->setNotSetText( mModel->combinedModel()->notSetText() );
546 mActivePanel->setPanelTitle( mDialogTitle );
550 mActivePanel->setShowNoCrs(
true );
555 if ( mIgnorePanelSignals )
558 if ( !mActivePanel->hasValidSelection() )
561 mCrsComboBox->blockSignals(
true );
563 mCrsComboBox->blockSignals(
false );
566 mIgnorePanelSignals++;
568 mIgnorePanelSignals--;
577 if ( !mMessage.isEmpty() )
579 if ( !ogcFilter.isEmpty() )
582 dlg.setWindowTitle( mDialogTitle );
584 if ( !mModel->combinedModel()->notSetText().isEmpty() )
595 mCrsComboBox->blockSignals(
true );
597 mCrsComboBox->blockSignals(
false );
604 QApplication::restoreOverrideCursor();
611 if ( !( event->possibleActions() & Qt::CopyAction ) )
617 if ( mapLayerFromMimeData( event->mimeData() ) )
620 event->setDropAction( Qt::CopyAction );
647 if ( !( event->possibleActions() & Qt::CopyAction ) )
653 if (
QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
656 setFocus( Qt::MouseFocusReason );
657 event->setDropAction( Qt::CopyAction );
660 if ( layer->crs().isValid() )
673 return mSourceEnsemble;
678 mDialogTitle = title;
688 mModel->setFilteredCrs( crses );
693 return mModel->filters();
700 mActivePanel->setFilters(
filters );
705 if ( mSourceEnsemble == ensemble )
708 mSourceEnsemble = ensemble;
714 return mShowAccuracyWarnings;
719 mShowAccuracyWarnings = show;
720 if ( !mShowAccuracyWarnings )
721 mWarningLabelContainer->hide();
726void QgsProjectionSelectionWidget::comboIndexChanged(
int idx )
728 if ( idx >= 0 && idx < mModel->rowCount() )
731 const QVariant optionData = mModel->data( mModel->index( idx, 0 ), StandardCoordinateReferenceSystemsModel::RoleOption );
748void QgsProjectionSelectionWidget::updateWarning()
750 if ( !mShowAccuracyWarnings )
752 if ( mWarningLabelContainer->isVisible() )
753 mWarningLabelContainer->hide();
759 const double crsAccuracyWarningThreshold =
QgsSettings().
value( QStringLiteral(
"/projections/crsAccuracyWarningThreshold" ), 0.0,
QgsSettings::App ).toDouble();
762 if ( !ensemble.
isValid() || ensemble.
name() == mSourceEnsemble || ( ensemble.
accuracy() > 0 && ensemble.
accuracy() < crsAccuracyWarningThreshold ) )
764 mWarningLabelContainer->hide();
768 mWarningLabelContainer->show();
770 QString warning = QStringLiteral(
"<p>" );
773 if ( !ensemble.
code().isEmpty() )
774 id = QStringLiteral(
"<i>%1</i> (%2:%3)" ).arg( ensemble.
name(), ensemble.
authority(), ensemble.
code() );
776 id = QStringLiteral(
"<i>%</i>”" ).arg( ensemble.
name() );
780 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() );
784 warning = tr(
"The selected CRS is based on %1, which has a limited accuracy." ).arg(
id );
786 warning += QStringLiteral(
"</p><p>" ) + tr(
"Use an alternative CRS if accurate positioning is required." ) + QStringLiteral(
"</p>" );
788 const QList< QgsDatumEnsembleMember > members = ensemble.
members();
789 if ( !members.isEmpty() )
791 warning += QStringLiteral(
"<p>" ) + tr(
"%1 consists of the datums:" ).arg( ensemble.
name() ) + QStringLiteral(
"</p><ul>" );
795 if ( !member.code().isEmpty() )
796 id = QStringLiteral(
"%1 (%2:%3)" ).arg( member.name(), member.authority(), member.code() );
799 warning += QStringLiteral(
"<li>%1</li>" ).arg(
id );
802 warning += QLatin1String(
"</ul>" );
805 mWarningLabel->setToolTip( warning );
810 mWarningLabelContainer->hide();
817 mModel->setCurrentCrs(
crs );
822 mCrsComboBox->blockSignals(
true );
824 mCrsComboBox->blockSignals(
false );
829 if ( crsNotSetIndex >= 0 )
831 mCrsComboBox->blockSignals(
true );
832 mCrsComboBox->setCurrentIndex( crsNotSetIndex );
833 mCrsComboBox->blockSignals(
false );
836 if ( mActivePanel && !mIgnorePanelSignals )
838 mIgnorePanelSignals++;
839 mActivePanel->setCrs(
crs );
840 mIgnorePanelSignals--;
842 if ( prevCrs !=
crs )
851 mModel->setLayerCrs(
crs );
859 return tr(
"invalid projection" );
862void QgsProjectionSelectionWidget::updateTooltip()
868 setToolTip( QString() );
872QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData(
const QMimeData *data )
const
@ 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.
@ 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.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString userFriendlyIdentifier(Qgis::CrsIdentifierType type=Qgis::CrsIdentifierType::MediumString) const
Returns a user friendly identifier for the CRS.
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the CRS.
Qgis::CrsType type() const
Returns the type of the CRS.
Contains information about a member of a datum ensemble.
Contains information about a datum ensemble.
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.
void setHighlighted(bool highlighted)
Sets whether the combo box is currently highlighted.
bool isHighlighted() const
Returns true if the combo box is currently highlighted.
Base class for all map layer types.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Custom exception class which is raised when an operation is not supported.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
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.
This class is a composition of two QSettings instances:
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.
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
const QgsCoordinateReferenceSystem & crs