QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsdatumtransformdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdatumtransformdialog.cpp
3  ---------------------------
4  begin : November 2013
5  copyright : (C) 2013 by Marco Hugentobler
6  email : marco.hugentobler at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgscoordinatetransform.h"
21 #include "qgslogger.h"
22 #include "qgssettings.h"
23 #include "qgsproject.h"
24 #include "qgsguiutils.h"
25 #include "qgsgui.h"
26 #include "qgshelp.h"
27 
28 #include <QDir>
29 #include <QPushButton>
30 
31 #if PROJ_VERSION_MAJOR>=6
32 #include "qgsprojutils.h"
33 #include <proj.h>
34 #endif
35 
36 bool QgsDatumTransformDialog::run( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, QWidget *parent, QgsMapCanvas *mapCanvas, const QString &windowTitle )
37 {
38  if ( sourceCrs == destinationCrs )
39  return true;
40 
42  if ( context.hasTransform( sourceCrs, destinationCrs ) )
43  {
44  return true;
45  }
46 
47  QgsDatumTransformDialog dlg( sourceCrs, destinationCrs, false, true, false, qMakePair( -1, -1 ), parent, Qt::WindowFlags(), QString(), mapCanvas );
48  if ( !windowTitle.isEmpty() )
49  dlg.setWindowTitle( windowTitle );
50 
51  if ( dlg.shouldAskUserForSelection() )
52  {
53  if ( dlg.exec() )
54  {
55  const TransformInfo dt = dlg.selectedDatumTransform();
62  return true;
63  }
64  else
65  {
66  return false;
67  }
68  }
69  else
70  {
71  dlg.applyDefaultTransform();
72  return true;
73  }
74 }
75 
77  const QgsCoordinateReferenceSystem &dCrs, const bool allowCrsChanges, const bool showMakeDefault, const bool forceChoice,
78  QPair<int, int> selectedDatumTransforms,
79  QWidget *parent,
80  Qt::WindowFlags f, const QString &selectedProj, QgsMapCanvas *mapCanvas, bool allowFallback )
81  : QDialog( parent, f )
82  , mPreviousCursorOverride( qgis::make_unique< QgsTemporaryCursorRestoreOverride >() ) // this dialog is often shown while cursor overrides are in place, so temporarily remove them
83 {
84  setupUi( this );
85 
86  QgsCoordinateReferenceSystem sourceCrs = sCrs;
87  QgsCoordinateReferenceSystem destinationCrs = dCrs;
88 
90 
91  if ( !showMakeDefault )
92  mCoordinateOperationsWidget->setShowMakeDefault( false );
93 
94  if ( forceChoice )
95  {
96  mButtonBox->removeButton( mButtonBox->button( QDialogButtonBox::Cancel ) );
97  setWindowFlags( windowFlags() | Qt::CustomizeWindowHint );
98  setWindowFlags( windowFlags() & ~Qt::WindowCloseButtonHint );
99  }
100 
101 #if PROJ_VERSION_MAJOR>=6
102  if ( !sourceCrs.isValid() )
103  sourceCrs = QgsProject::instance()->crs();
104  if ( !sourceCrs.isValid() )
105  sourceCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );
106  if ( !destinationCrs.isValid() )
107  destinationCrs = QgsProject::instance()->crs();
108  if ( !destinationCrs.isValid() )
109  destinationCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );
110 
111  mSourceProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
112  mDestinationProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
113 #endif
114 
115  mSourceProjectionSelectionWidget->setCrs( sourceCrs );
116  mDestinationProjectionSelectionWidget->setCrs( destinationCrs );
117  if ( !allowCrsChanges )
118  {
119  mCrsStackedWidget->setCurrentIndex( 1 );
120  mSourceProjectionSelectionWidget->setEnabled( false );
121  mDestinationProjectionSelectionWidget->setEnabled( false );
122  mSourceCrsLabel->setText( QgsProjectionSelectionWidget::crsOptionText( sourceCrs ) );
123  mDestCrsLabel->setText( QgsProjectionSelectionWidget::crsOptionText( destinationCrs ) );
124  }
125 
126  mCoordinateOperationsWidget->setMapCanvas( mapCanvas );
127 
128  connect( mSourceProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, &QgsDatumTransformDialog::setSourceCrs );
129  connect( mDestinationProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, &QgsDatumTransformDialog::setDestinationCrs );
130 
131  mCoordinateOperationsWidget->setSourceCrs( sourceCrs );
132  mCoordinateOperationsWidget->setDestinationCrs( destinationCrs );
133 
134  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, [ = ]
135  {
136  QgsHelp::openHelp( QStringLiteral( "working_with_projections/working_with_projections.html" ) );
137  } );
138 
139  connect( mCoordinateOperationsWidget, &QgsCoordinateOperationWidget::operationChanged, this, &QgsDatumTransformDialog::operationChanged );
141  deets.proj = selectedProj;
142  deets.sourceTransformId = selectedDatumTransforms.first;
143  deets.destinationTransformId = selectedDatumTransforms.second;
144  deets.allowFallback = allowFallback;
145  mCoordinateOperationsWidget->setSelectedOperation( deets );
146 
147  connect( mCoordinateOperationsWidget, &QgsCoordinateOperationWidget::operationDoubleClicked, this, [ = ]
148  {
149 
150 #if PROJ_VERSION_MAJOR>=6
151  if ( mCoordinateOperationsWidget->sourceCrs().isValid() && mCoordinateOperationsWidget->destinationCrs().isValid()
152  && mCoordinateOperationsWidget->selectedOperation().isAvailable )
153  accept();
154 #else
155  if ( mCoordinateOperationsWidget->sourceCrs().isValid() && mCoordinateOperationsWidget->destinationCrs().isValid() && mCoordinateOperationsWidget->hasSelection() )
156  accept();
157 #endif
158  } );
159 }
160 
161 void QgsDatumTransformDialog::setOKButtonEnabled()
162 {
163 #if PROJ_VERSION_MAJOR>=6
164  mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mCoordinateOperationsWidget->sourceCrs().isValid() && mCoordinateOperationsWidget->destinationCrs().isValid()
165  && mCoordinateOperationsWidget->selectedOperation().isAvailable );
166 #else
167  mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( mCoordinateOperationsWidget->sourceCrs().isValid() && mCoordinateOperationsWidget->destinationCrs().isValid() && mCoordinateOperationsWidget->hasSelection() );
168 #endif
169 }
170 
172 {
173  if ( mCoordinateOperationsWidget->makeDefaultSelected() && mCoordinateOperationsWidget->hasSelection() )
174  {
175  QgsSettings settings;
176  settings.beginGroup( QStringLiteral( "/Projections" ) );
177 
179 
180  QString srcAuthId = dt.sourceCrs.authid();
181  QString destAuthId = dt.destinationCrs.authid();
182  int sourceDatumTransform = dt.sourceTransformId;
183  QString sourceDatumProj;
185  if ( sourceDatumTransform >= 0 )
186  sourceDatumProj = QgsDatumTransform::datumTransformToProj( sourceDatumTransform );
187  int destinationDatumTransform = dt.destinationTransformId;
188  QString destinationDatumProj;
189  if ( destinationDatumTransform >= 0 )
190  destinationDatumProj = QgsDatumTransform::datumTransformToProj( destinationDatumTransform );
192  settings.setValue( srcAuthId + QStringLiteral( "//" ) + destAuthId + QStringLiteral( "_srcTransform" ), sourceDatumProj );
193  settings.setValue( srcAuthId + QStringLiteral( "//" ) + destAuthId + QStringLiteral( "_destTransform" ), destinationDatumProj );
194  settings.setValue( srcAuthId + QStringLiteral( "//" ) + destAuthId + QStringLiteral( "_coordinateOp" ), dt.proj );
195  settings.setValue( srcAuthId + QStringLiteral( "//" ) + destAuthId + QStringLiteral( "_allowFallback" ), dt.allowFallback );
196  }
197  QDialog::accept();
198 }
199 
201 {
202  if ( !mButtonBox->button( QDialogButtonBox::Cancel ) )
203  return; // users HAVE to make a choice, no click on the dialog "x" to avoid this!
204 
205  QDialog::reject();
206 }
207 
208 bool QgsDatumTransformDialog::shouldAskUserForSelection() const
209 {
210  if ( mCoordinateOperationsWidget->availableOperations().count() > 1 )
211  {
212  return QgsSettings().value( QStringLiteral( "/projections/promptWhenMultipleTransformsExist" ), false, QgsSettings::App ).toBool();
213  }
214  // TODO: show if transform grids are required, but missing
215  return false;
216 }
217 
218 QgsDatumTransformDialog::TransformInfo QgsDatumTransformDialog::defaultDatumTransform() const
219 {
220  TransformInfo preferred;
221  preferred.sourceCrs = mCoordinateOperationsWidget->sourceCrs();
222  preferred.destinationCrs = mCoordinateOperationsWidget->destinationCrs();
223  QgsCoordinateOperationWidget::OperationDetails defaultOp = mCoordinateOperationsWidget->defaultOperation();
224  preferred.sourceTransformId = defaultOp.sourceTransformId;
225  preferred.destinationTransformId = defaultOp.destinationTransformId;
226  preferred.proj = defaultOp.proj;
227  return preferred;
228 }
229 
230 void QgsDatumTransformDialog::applyDefaultTransform()
231 {
232  if ( mCoordinateOperationsWidget->availableOperations().count() > 0 )
233  {
235  const TransformInfo dt = defaultDatumTransform();
237  context.addSourceDestinationDatumTransform( dt.sourceCrs, dt.destinationCrs, dt.sourceTransformId, dt.destinationTransformId );
239 
240 #if PROJ_VERSION_MAJOR>=6
241  // on proj 6 builds, removing a coordinate operation falls back to default
242  context.removeCoordinateOperation( dt.sourceCrs, dt.destinationCrs );
243 #else
244  context.addCoordinateOperation( dt.sourceCrs, dt.destinationCrs, dt.proj );
245 #endif
247  }
248 }
249 
251 {
252  QgsCoordinateOperationWidget::OperationDetails selected = mCoordinateOperationsWidget->selectedOperation();
253  TransformInfo sdt;
254  sdt.sourceCrs = mCoordinateOperationsWidget->sourceCrs();
255  sdt.destinationCrs = mCoordinateOperationsWidget->destinationCrs();
256  sdt.sourceTransformId = selected.sourceTransformId;
258  sdt.proj = selected.proj;
259  sdt.allowFallback = selected.allowFallback;
260  return sdt;
261 }
262 
263 bool QgsDatumTransformDialog::gridShiftTransformation( const QString &itemText ) const
264 {
265  return !itemText.isEmpty() && !itemText.contains( QLatin1String( "towgs84" ), Qt::CaseInsensitive );
266 }
267 
268 void QgsDatumTransformDialog::operationChanged()
269 {
270  setOKButtonEnabled();
271 }
272 
273 void QgsDatumTransformDialog::setSourceCrs( const QgsCoordinateReferenceSystem &sourceCrs )
274 {
275  mCoordinateOperationsWidget->setSourceCrs( sourceCrs );
276  setOKButtonEnabled();
277 }
278 
279 void QgsDatumTransformDialog::setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs )
280 {
281  mCoordinateOperationsWidget->setDestinationCrs( destinationCrs );
282  setOKButtonEnabled();
283 }
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:58
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsDatumTransformDialog::TransformInfo::proj
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.
Definition: qgsdatumtransformdialog.h:55
QgsCoordinateTransformContext::removeCoordinateOperation
void removeCoordinateOperation(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs)
Removes the coordinate operation for the specified sourceCrs and destinationCrs.
Definition: qgscoordinatetransformcontext.cpp:148
QgsSettings::App
@ App
Definition: qgssettings.h:75
QgsDatumTransformDialog::TransformInfo
Dialog transformation entry info.
Definition: qgsdatumtransformdialog.h:41
qgsgui.h
QgsCoordinateOperationWidget::OperationDetails
Coordinate operation details.
Definition: qgscoordinateoperationwidget.h:40
QgsDatumTransformDialog::reject
void reject() override
Definition: qgsdatumtransformdialog.cpp:200
QgsProjectionSelectionWidget::crsChanged
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
QgsDatumTransformDialog::accept
void accept() override
Definition: qgsdatumtransformdialog.cpp:171
QgsCoordinateOperationWidget::OperationDetails::allowFallback
bool allowFallback
true if fallback transforms can be used
Definition: qgscoordinateoperationwidget.h:54
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:85
QgsDatumTransformDialog
Definition: qgsdatumtransformdialog.h:35
QgsProject::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:101
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsDatumTransformDialog::TransformInfo::destinationCrs
QgsCoordinateReferenceSystem destinationCrs
Destination coordinate reference system.
Definition: qgsdatumtransformdialog.h:49
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsDatumTransformDialog::TransformInfo::destinationTransformId
int destinationTransformId
Destination transform ID.
Definition: qgsdatumtransformdialog.h:52
QgsDatumTransformDialog::selectedDatumTransform
TransformInfo selectedDatumTransform()
Returns the source and destination transforms, each being a pair of QgsCoordinateReferenceSystems and...
Definition: qgsdatumtransformdialog.cpp:250
QgsDatumTransformDialog::QgsDatumTransformDialog
QgsDatumTransformDialog(const QgsCoordinateReferenceSystem &sourceCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), bool allowCrsChanges=false, bool showMakeDefault=true, bool forceChoice=true, QPair< int, int > selectedDatumTransforms=qMakePair(-1, -1), QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags(), const QString &selectedProj=QString(), QgsMapCanvas *mapCanvas=nullptr, bool allowFallback=true)
Constructor for QgsDatumTransformDialog.
Definition: qgsdatumtransformdialog.cpp:76
qgsprojectionselectiondialog.h
QgsCoordinateTransformContext::addCoordinateOperation
bool addCoordinateOperation(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QString &coordinateOperationProjString, bool allowFallback=true)
Adds a new coordinateOperationProjString to use when projecting coordinates from the specified source...
Definition: qgscoordinatetransformcontext.cpp:123
QgsGui::enableAutoGeometryRestore
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:139
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:797
QgsCoordinateOperationWidget::OperationDetails::proj
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.
Definition: qgscoordinateoperationwidget.h:48
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1321
QgsDatumTransformDialog::TransformInfo::sourceCrs
QgsCoordinateReferenceSystem sourceCrs
Source coordinate reference system.
Definition: qgsdatumtransformdialog.h:43
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:924
qgscoordinatetransform.h
QgsDatumTransformDialog::TransformInfo::allowFallback
bool allowFallback
true if fallback transforms can be used
Definition: qgsdatumtransformdialog.h:58
QgsCoordinateTransformContext::addSourceDestinationDatumTransform
Q_DECL_DEPRECATED bool addSourceDestinationDatumTransform(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, int sourceTransformId, int destinationTransformId)
Adds a new sourceTransform and destinationTransform to use when projecting coordinates from the speci...
Definition: qgscoordinatetransformcontext.cpp:106
QgsCoordinateOperationWidget::operationDoubleClicked
void operationDoubleClicked()
Emitted when an operation is double-clicked in the widget.
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsProjectionSelectionWidget::CrsNotSet
@ CrsNotSet
Not set (hidden by default)
Definition: qgsprojectionselectionwidget.h:53
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:206
QgsCoordinateOperationWidget::OperationDetails::destinationTransformId
int destinationTransformId
Destination transform ID.
Definition: qgscoordinateoperationwidget.h:45
QgsDatumTransformDialog::run
static bool run(const QgsCoordinateReferenceSystem &sourceCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr, const QString &windowTitle=QString())
Runs the dialog (if required) prompting for the desired transform to use from sourceCrs to destinatio...
Definition: qgsdatumtransformdialog.cpp:36
QgsSettings::beginGroup
void beginGroup(const QString &prefix, QgsSettings::Section section=QgsSettings::NoSection)
Appends prefix to the current group.
Definition: qgssettings.cpp:87
QgsCoordinateOperationWidget::OperationDetails::sourceTransformId
int sourceTransformId
Source transform ID.
Definition: qgscoordinateoperationwidget.h:42
QgsHelp::openHelp
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
qgsprojutils.h
QgsProjectionSelectionWidget::crsOptionText
static QString crsOptionText(const QgsCoordinateReferenceSystem &crs)
Returns display text for the specified crs.
Definition: qgsprojectionselectionwidget.cpp:379
qgssettings.h
qgsdatumtransformdialog.h
QgsTemporaryCursorRestoreOverride
Temporarily removes all cursor overrides for the QApplication for the lifetime of the object.
Definition: qgsguiutils.h:254
qgslogger.h
qgsguiutils.h
QgsCoordinateTransformContext::hasTransform
bool hasTransform(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination) const
Returns true if the context has a valid coordinate operation to use when transforming from the specif...
Definition: qgscoordinatetransformcontext.cpp:157
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:796
QgsDatumTransformDialog::TransformInfo::sourceTransformId
int sourceTransformId
Source transform ID.
Definition: qgsdatumtransformdialog.h:46
QgsProject::crs
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:100
qgshelp.h
QgsDatumTransform::datumTransformToProj
static Q_DECL_DEPRECATED QString datumTransformToProj(int datumTransformId)
Returns a proj string representing the specified datumTransformId datum transform ID.
Definition: qgsdatumtransform.cpp:162
QgsProject::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the project's coordinate transform context, which stores various information regarding which dat...
Definition: qgsproject.cpp:764
qgsproject.h
QgsCoordinateOperationWidget::operationChanged
void operationChanged()
Emitted when the operation selected in the dialog is changed.