QGIS API Documentation 4.3.0-Master (bf28115e945)
Loading...
Searching...
No Matches
qgsprojectionselectiondialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgenericprojectionselector.cpp
3 Set user defined CRS using projection selector widget
4 -------------------
5 begin : May 28, 2004
6 copyright : (C) 2004 by Gary E.Sherman
7 email : sherman at mrcc.com
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
19
20#include "qgsapplication.h"
22#include "qgsdoublespinbox.h"
23#include "qgsgui.h"
24#include "qgshelp.h"
26#include "qgsrectangle.h"
27#include "qgssettings.h"
28
29#include <QApplication>
30#include <QDialogButtonBox>
31#include <QPushButton>
32#include <QString>
33
34#include "moc_qgsprojectionselectiondialog.cpp"
35
36using namespace Qt::StringLiterals;
37
38//
39// QgsCrsSelectionWidget
40//
42 : QgsPanelWidget( parent )
43{
44 setupUi( this );
45
46 projectionSelector->setFilters( filters );
47
48 //we will show this only when a message is set
49 textEdit->hide();
50
51 mNotSetText = tr( "No CRS (or unknown)" );
52 mLabelNoCrs->setText( tr( "Use this option to treat all coordinates as Cartesian coordinates in an unknown reference system." ) );
53
54 mComboCrsType->addItem( tr( "Predefined CRS" ), static_cast<int>( CrsType::Predefined ) );
55 mComboCrsType->addItem( tr( "Custom CRS" ), static_cast<int>( CrsType::Custom ) );
56 mComboCrsType->addItem( tr( "Topocentric CRS" ), static_cast<int>( CrsType::Topocentric ) );
57
58 mTopocentricBaseSelector->setFilters( QgsCoordinateReferenceSystemProxyModel::FilterTopocentricCompatible );
59 mTopocentricBaseSelector->setAllowTopocentricCrs( false );
60
61 mStackedWidget->setCurrentWidget( mPageDatabase );
62 mComboCrsType->setCurrentIndex( mComboCrsType->findData( static_cast<int>( CrsType::Predefined ) ) );
63
64 connect( mComboCrsType, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
65 if ( !mComboCrsType->currentData().isValid() )
66 mStackedWidget->setCurrentWidget( mPageNoCrs );
67 else
68 {
69 switch ( static_cast<CrsType>( mComboCrsType->currentData().toInt() ) )
70 {
71 case QgsCrsSelectionWidget::CrsType::Predefined:
72 mStackedWidget->setCurrentWidget( mPageDatabase );
73 break;
74 case QgsCrsSelectionWidget::CrsType::Custom:
75 mStackedWidget->setCurrentWidget( mPageCustom );
76 break;
77 case QgsCrsSelectionWidget::CrsType::Topocentric:
78 mStackedWidget->setCurrentWidget( mPageTopocentric );
79 if ( !mBlockSignals )
80 {
81 const QgsRectangle b = mTopocentricBaseSelector->crs().bounds();
82 if ( !b.isNull() )
83 {
84 mSpinBoxTopoLat->setClearValue( ( b.yMinimum() + b.yMaximum() ) / 2.0 );
85 mSpinBoxTopoLon->setClearValue( ( b.xMinimum() + b.xMaximum() ) / 2.0 );
86 mSpinBoxTopoLat->clear();
87 mSpinBoxTopoLon->clear();
88 }
89 }
90 break;
91 }
92 }
93
94 if ( !mBlockSignals )
95 {
96 emit crsChanged();
98 }
99 } );
100
101 connect( projectionSelector, &QgsProjectionSelectionTreeWidget::projectionDoubleClicked, this, [this] { emit crsDoubleClicked( projectionSelector->crs() ); } );
102
103 connect( mCrsDefinitionWidget, &QgsCrsDefinitionWidget::crsChanged, this, [this]() {
104 if ( !mBlockSignals )
105 {
106 emit crsChanged();
108 }
109 } );
110
111 connect( projectionSelector, &QgsProjectionSelectionTreeWidget::crsSelected, this, [this]() {
112 if ( !mBlockSignals )
113 {
114 mDeferredInvalidCrsSet = false;
115 emit crsChanged();
117 }
118 } );
119
120 connect( projectionSelector, &QgsProjectionSelectionTreeWidget::hasValidSelectionChanged, this, [this]() {
121 if ( !mBlockSignals )
122 {
123 emit crsChanged();
125 }
126 } );
127
128 connect( mTopocentricBaseSelector, &QgsProjectionSelectionWidget::crsChanged, this, [this]( const QgsCoordinateReferenceSystem &newBase ) {
129 const QgsRectangle b = newBase.bounds();
130 if ( !b.isNull() )
131 {
132 mSpinBoxTopoLat->setClearValue( ( b.yMinimum() + b.yMaximum() ) / 2.0 );
133 mSpinBoxTopoLon->setClearValue( ( b.xMinimum() + b.xMaximum() ) / 2.0 );
134 }
135 if ( !mBlockSignals )
136 {
137 mBlockSignals++;
138 mSpinBoxTopoLat->clear();
139 mSpinBoxTopoLon->clear();
140 mBlockSignals--;
141 emit crsChanged();
143 }
144 } );
145
146 connect( mSpinBoxTopoLat, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, [this]( double ) {
147 if ( !mBlockSignals )
148 emit crsChanged();
149 } );
150
151 connect( mSpinBoxTopoLon, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, [this]( double ) {
152 if ( !mBlockSignals )
153 emit crsChanged();
154 } );
155
156 const QgsSettings settings;
157 mSplitter->restoreState( settings.value( u"Windows/ProjectionSelectorDialog/splitterState"_s ).toByteArray() );
158}
159
161{
162 QgsSettings settings;
163 settings.setValue( u"Windows/ProjectionSelectorDialog/splitterState"_s, mSplitter->saveState() );
164}
165
166void QgsCrsSelectionWidget::setMessage( const QString &message )
167{
168 textEdit->setHtml( u"<head><style>%1</style></head><body>%2</body>"_s.arg( QgsApplication::reportStyleSheet(), message ) );
169 textEdit->show();
170}
171
173{
174 if ( mShowNoCrsOption == show )
175 return;
176
177 mBlockSignals++;
178 mShowNoCrsOption = show;
179 if ( mShowNoCrsOption )
180 {
181 mComboCrsType->insertItem( 0, mNotSetText );
182 }
183 else
184 {
185 mComboCrsType->removeItem( 0 );
186 }
187
188 if ( show && mDeferredInvalidCrsSet )
189 {
190 mComboCrsType->setCurrentIndex( 0 );
191 }
192
193 mBlockSignals--;
194
195 if ( mDeferredInvalidCrsSet )
196 emit crsChanged();
197
198 mDeferredInvalidCrsSet = false;
199
201}
202
204{
205 return mShowNoCrsOption;
206}
207
208void QgsCrsSelectionWidget::setNotSetText( const QString &text, const QString &description )
209{
210 mNotSetText = text;
211
212 if ( mShowNoCrsOption )
213 {
214 mComboCrsType->setItemText( 0, mNotSetText );
215 }
216
217 mLabelNoCrs->setText( description.isEmpty() ? text : description );
218}
219
221{
222 if ( !mComboCrsType->currentData().isValid() )
223 return true;
224 else if ( mDeferredInvalidCrsSet )
225 return false;
226 else
227 {
228 switch ( static_cast<CrsType>( mComboCrsType->currentData().toInt() ) )
229 {
230 case QgsCrsSelectionWidget::CrsType::Predefined:
231 return projectionSelector->hasValidSelection();
232 case QgsCrsSelectionWidget::CrsType::Custom:
233 return mCrsDefinitionWidget->crs().isValid();
234 case QgsCrsSelectionWidget::CrsType::Topocentric:
235 {
236 const QgsCoordinateReferenceSystem baseCrs = mTopocentricBaseSelector->crs();
237 return baseCrs.isValid();
238 }
239 }
241 }
242}
243
245{
246 return projectionSelector->filters();
247}
248
253
255{
256 if ( allow == mAllowTopocentricCrs )
257 return;
258 mAllowTopocentricCrs = allow;
259
260 const int idx = mComboCrsType->findData( static_cast<int>( CrsType::Topocentric ) );
261 if ( !allow && idx >= 0 )
262 mComboCrsType->removeItem( idx );
263 else if ( allow && idx < 0 )
264 mComboCrsType->addItem( tr( "Topocentric CRS" ), static_cast<int>( CrsType::Topocentric ) );
265}
266
268{
269 if ( !mComboCrsType->currentData().isValid() )
271 else
272 {
273 switch ( static_cast<CrsType>( mComboCrsType->currentData().toInt() ) )
274 {
275 case QgsCrsSelectionWidget::CrsType::Predefined:
276 return projectionSelector->crs();
277 case QgsCrsSelectionWidget::CrsType::Custom:
278 return mCrsDefinitionWidget->crs();
279 case QgsCrsSelectionWidget::CrsType::Topocentric:
280 {
281 const QgsCoordinateReferenceSystem base = mTopocentricBaseSelector->crs();
282 return base.toTopocentricCrs( mSpinBoxTopoLat->value(), mSpinBoxTopoLon->value() );
283 }
284 }
286 }
287}
288
290{
291 mBlockSignals++;
292 if ( !crs.isValid() )
293 {
294 if ( mShowNoCrsOption )
295 mComboCrsType->setCurrentIndex( 0 );
296 else
297 mDeferredInvalidCrsSet = true;
298 }
299 else
300 {
301 double topoLat = 0.0, topoLon = 0.0;
302 if ( crs.topocentricOrigin( topoLat, topoLon ) )
303 {
304 const QgsCoordinateReferenceSystem baseCrs = crs.topocentricBaseCrs();
305 mTopocentricBaseSelector->setCrs( baseCrs );
306
307 const QgsRectangle b = baseCrs.bounds();
308 if ( !b.isNull() )
309 {
310 mSpinBoxTopoLat->setClearValue( ( b.yMinimum() + b.yMaximum() ) / 2.0 );
311 mSpinBoxTopoLon->setClearValue( ( b.xMinimum() + b.xMaximum() ) / 2.0 );
312 }
313 mSpinBoxTopoLat->clear();
314 mSpinBoxTopoLon->clear();
315 mComboCrsType->setCurrentIndex( mComboCrsType->findData( static_cast<int>( CrsType::Topocentric ) ) );
316 mStackedWidget->setCurrentWidget( mPageTopocentric );
317 }
318 else if ( crs.authid().isEmpty() )
319 {
320 projectionSelector->setCrs( crs );
321 mCrsDefinitionWidget->setCrs( crs );
322 mComboCrsType->setCurrentIndex( mComboCrsType->findData( static_cast<int>( CrsType::Custom ) ) );
323 mStackedWidget->setCurrentWidget( mPageCustom );
324 }
325 else
326 {
327 projectionSelector->setCrs( crs );
328 mCrsDefinitionWidget->setCrs( crs );
329 mComboCrsType->setCurrentIndex( mComboCrsType->findData( static_cast<int>( CrsType::Predefined ) ) );
330 mStackedWidget->setCurrentWidget( mPageDatabase );
331 }
332 }
333 mBlockSignals--;
334
335 emit crsChanged();
337}
338
339void QgsCrsSelectionWidget::setOgcWmsCrsFilter( const QSet<QString> &crsFilter )
340{
341 projectionSelector->setOgcWmsCrsFilter( crsFilter );
342}
343
345{
346 projectionSelector->setPreviewRect( rect );
347}
348
349
350//
351// QgsProjectionSelectionDialog
352//
353
355 : QDialog( parent, fl )
356{
357 QVBoxLayout *vlayout = new QVBoxLayout();
358
359 mCrsWidget = new QgsCrsSelectionWidget( nullptr, filters );
360 vlayout->addWidget( mCrsWidget, 1 );
361
362 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
363 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsProjectionSelectionDialog::accept );
364 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsProjectionSelectionDialog::reject );
365 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsProjectionSelectionDialog::showHelp );
366
367 vlayout->addWidget( mButtonBox );
368
369 setLayout( vlayout );
370
372
373 //apply selected projection upon double-click on item
374 connect( mCrsWidget, &QgsCrsSelectionWidget::crsDoubleClicked, this, &QgsProjectionSelectionDialog::accept );
375}
376
377void QgsProjectionSelectionDialog::setMessage( const QString &message )
378{
379 mCrsWidget->setMessage( message );
380}
381
383{
385 tr( "This layer appears to have no projection specification." )
386 + ' '
387 + tr(
388 "By default, this layer will now have its projection set to that of the project, "
389 "but you may override this by selecting a different projection below."
390 )
391 );
392}
393
395{
396 mCrsWidget->setShowNoCrs( show );
397}
398
400{
401 return mCrsWidget->showNoCrs();
402}
403
404void QgsProjectionSelectionDialog::setNotSetText( const QString &text, const QString &description )
405{
406 mCrsWidget->setNotSetText( text, description );
407}
408
410{
411 mRequireValidSelection = true;
412 mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
413
414 connect( mCrsWidget, &QgsCrsSelectionWidget::hasValidSelectionChanged, this, [this]( bool isValid ) { mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid ); } );
415}
416
418{
419 return mCrsWidget->hasValidSelection();
420}
421
426
431
433{
434 mCrsWidget->setAllowTopocentricCrs( allow );
435}
436
438{
439 return mCrsWidget->crs();
440}
441
443{
444 mCrsWidget->setCrs( crs );
445
446 if ( mRequireValidSelection )
447 mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( hasValidSelection() );
448}
449
450void QgsProjectionSelectionDialog::setOgcWmsCrsFilter( const QSet<QString> &crsFilter )
451{
452 mCrsWidget->setOgcWmsCrsFilter( crsFilter );
453}
454
455void QgsProjectionSelectionDialog::showHelp()
456{
457 QgsHelp::openHelp( u"working_with_projections/working_with_projections.html"_s );
458}
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
@ FilterTopocentricCompatible
Include all CRS types compatible with topocentric CRS (all except projected CRS).
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
QgsCoordinateReferenceSystem toTopocentricCrs(double latitude, double longitude) const
Constructs a topocentric CRS derived from this CRS with origin at latitude, longitude in decimal degr...
void crsChanged()
Emitted when the CRS defined in the widget is changed.
A generic widget allowing users to pick a Coordinate Reference System (or define their own).
bool showNoCrs() const
Returns whether the "no/invalid" CRS option is shown.
QgsCoordinateReferenceSystem crs() const
Returns the CRS currently selected in the widget.
void setAllowTopocentricCrs(bool allow)
Sets whether the topocentric CRS type option is shown in the widget's CRS type combobox.
void hasValidSelectionChanged(bool isValid)
Emitted when the widget has a valid selection or not.
QgsCrsSelectionWidget(QWidget *parent=nullptr, QgsCoordinateReferenceSystemProxyModel::Filters filters=QgsCoordinateReferenceSystemProxyModel::FilterHorizontal|QgsCoordinateReferenceSystemProxyModel::FilterCompound)
Constructor for QgsCrsSelectionWidget, with the specified parent widget.
QgsCoordinateReferenceSystemProxyModel::Filters filters() const
Returns the filters set on the available CRS.
void setFilters(QgsCoordinateReferenceSystemProxyModel::Filters filters)
Sets filters for the available CRS.
void crsDoubleClicked(const QgsCoordinateReferenceSystem &crs)
Emitted when a CRS entry in the widget is double-clicked.
void setShowNoCrs(bool show)
Sets whether a "no/invalid" CRS option should be shown.
void crsChanged()
Emitted when the CRS defined in the widget is changed.
void setMessage(const QString &message)
Sets a message to show in the dialog.
bool hasValidSelection() const
Returns true if the widget has a valid CRS defined.
void setNotSetText(const QString &text, const QString &description=QString())
Sets the text to show for the not set option.
void setOgcWmsCrsFilter(const QSet< QString > &crsFilter)
filters this dialog by the given CRSs
void setPreviewRect(const QgsRectangle &rect)
Sets the visible area to use when showing a preview of the CRS in the widget.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the crs to show within the widget.
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:224
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
void showNoCrsForLayerMessage()
When called, the dialog will show a default "layer has no CRS set" message above the projection selec...
void setShowNoProjection(bool show)
Sets whether a "no/invalid" projection option should be shown.
bool showNoProjection() const
Returns whether the "no/invalid" projection option is shown.
QgsCoordinateReferenceSystemProxyModel::Filters filters() const
Returns the filters set on the available CRS.
bool hasValidSelection() const
Returns true if the dialog has a valid CRS defined.
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.
QgsProjectionSelectionDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags, QgsCoordinateReferenceSystemProxyModel::Filters filters=QgsCoordinateReferenceSystemProxyModel::FilterHorizontal|QgsCoordinateReferenceSystemProxyModel::FilterCompound)
Constructor for QgsProjectionSelectionDialog.
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
void setFilters(QgsCoordinateReferenceSystemProxyModel::Filters filters)
Sets filters for the available CRS.
void setAllowTopocentricCrs(bool allow)
Sets whether the topocentric CRS type option is shown in the dialog.
void crsSelected()
Emitted when a projection is selected in the widget.
void projectionDoubleClicked()
Emitted when a projection is double clicked in the list.
void hasValidSelectionChanged(bool isValid)
Emitted when the selection in the tree is changed from a valid selection to an invalid selection,...
void crsChanged(const QgsCoordinateReferenceSystem &crs)
Emitted when the selected CRS is changed.
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
Stores settings for use within QGIS.
Definition qgssettings.h:68
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define BUILTIN_UNREACHABLE
Definition qgis.h:8015