Skip to content

Commit fbc12a8

Browse files
committed
Allow showing 'not set' in QgsProjectionSelectionWidget
1 parent 08231b8 commit fbc12a8

File tree

5 files changed

+254
-6
lines changed

5 files changed

+254
-6
lines changed

python/gui/qgsprojectionselectionwidget.sip

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ class QgsProjectionSelectionWidget : QWidget
2020
ProjectCrs, /*!< current project CRS (if OTF reprojection enabled) */
2121
CurrentCrs, /*!< current user selected CRS */
2222
DefaultCrs, /*!< global default QGIS CRS */
23-
RecentCrs /*!< recently used CRS */
23+
RecentCrs, //!< Recently used CRS
24+
CrsNotSet, //!< Not set (hidden by default)
2425
};
2526

2627
explicit QgsProjectionSelectionWidget( QWidget *parent /TransferThis/ = 0 );
@@ -39,15 +40,37 @@ class QgsProjectionSelectionWidget : QWidget
3940
/** Sets whether a predefined CRS option should be shown in the widget.
4041
* @param option CRS option to show/hide
4142
* @param visible whether the option should be shown
43+
* @see optionVisible()
4244
*/
4345
void setOptionVisible( const CrsOption option, const bool visible );
4446

47+
48+
/**
49+
* Returns whether the specified CRS option is visible in the widget.
50+
* @note added in QGIS 3.0
51+
* @see setOptionVisible()
52+
*/
53+
bool optionVisible( CrsOption option ) const;
54+
55+
/**
56+
* Sets the text to show for the not set option. Note that this option is not shown
57+
* by default and must be set visible by calling setOptionVisible().
58+
* @note added in QGIS 3.0
59+
*/
60+
void setNotSetText( const QString& text );
61+
4562
signals:
4663

4764
/** Emitted when the selected CRS is changed
4865
*/
4966
void crsChanged( const QgsCoordinateReferenceSystem& );
5067

68+
/**
69+
* Emitted when the not set option is selected.
70+
* @note added in QGIS 3.0
71+
*/
72+
void cleared();
73+
5174
public slots:
5275

5376
/** Sets the current CRS for the widget

src/gui/qgsprojectionselectionwidget.cpp

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ QgsCoordinateReferenceSystem QgsProjectionSelectionWidget::crs() const
8888
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromSrsId( srsid );
8989
return crs;
9090
}
91+
case QgsProjectionSelectionWidget::CrsNotSet:
92+
return QgsCoordinateReferenceSystem();
9193
}
9294
return mCrs;
9395
}
@@ -117,18 +119,55 @@ void QgsProjectionSelectionWidget::setOptionVisible( const QgsProjectionSelectio
117119
return;
118120
}
119121
case QgsProjectionSelectionWidget::CurrentCrs:
122+
{
123+
addCurrentCrsOption();
124+
return;
125+
}
120126
case QgsProjectionSelectionWidget::RecentCrs:
121-
//current/recently used CRS option cannot be readded
127+
//recently used CRS option cannot be readded
128+
return;
129+
case QgsProjectionSelectionWidget::CrsNotSet:
130+
{
131+
addNotSetOption();
132+
133+
if ( optionVisible( CurrentCrs ) && !mCrs.isValid() )
134+
{
135+
// hide invalid option if not set option is shown
136+
setOptionVisible( CurrentCrs, false );
137+
}
138+
122139
return;
140+
}
123141
}
124142
}
125143
else if ( !visible && optionIndex >= 0 )
126144
{
127145
//remove CRS option
128146
mCrsComboBox->removeItem( optionIndex );
147+
148+
if ( option == CrsNotSet )
149+
{
150+
setOptionVisible( CurrentCrs, true );
151+
}
152+
}
153+
}
154+
155+
void QgsProjectionSelectionWidget::setNotSetText( const QString& text )
156+
{
157+
mNotSetText = text;
158+
int optionIndex = mCrsComboBox->findData( CrsNotSet );
159+
if ( optionIndex >= 0 )
160+
{
161+
mCrsComboBox->setItemText( optionIndex, mNotSetText );
129162
}
130163
}
131164

165+
bool QgsProjectionSelectionWidget::optionVisible( QgsProjectionSelectionWidget::CrsOption option ) const
166+
{
167+
int optionIndex = mCrsComboBox->findData( option );
168+
return optionIndex >= 0;
169+
}
170+
132171
void QgsProjectionSelectionWidget::selectCrs()
133172
{
134173
//find out crs id of current proj4 string
@@ -152,6 +191,13 @@ void QgsProjectionSelectionWidget::selectCrs()
152191
}
153192
}
154193

194+
void QgsProjectionSelectionWidget::addNotSetOption()
195+
{
196+
mCrsComboBox->insertItem( 0, mNotSetText, QgsProjectionSelectionWidget::CrsNotSet );
197+
if ( !mCrs.isValid() )
198+
whileBlocking( mCrsComboBox )->setCurrentIndex( 0 );
199+
}
200+
155201
void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
156202
{
157203
switch (( CrsOption )mCrsComboBox->itemData( idx ).toInt() )
@@ -175,23 +221,38 @@ void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
175221
emit crsChanged( crs );
176222
return;
177223
}
224+
case QgsProjectionSelectionWidget::CrsNotSet:
225+
emit cleared();
226+
return;
178227
}
179228
}
180229

181230
void QgsProjectionSelectionWidget::setCrs( const QgsCoordinateReferenceSystem& crs )
182231
{
183232
if ( crs.isValid() )
184233
{
234+
if ( !optionVisible( QgsProjectionSelectionWidget::CurrentCrs ) )
235+
setOptionVisible( QgsProjectionSelectionWidget::CurrentCrs, true );
185236
mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
186-
tr( "Selected CRS (%1, %2)" ).arg( crs.authid(), crs.description() ) );
237+
currentCrsOptionText( crs ) );
187238
mCrsComboBox->blockSignals( true );
188239
mCrsComboBox->setCurrentIndex( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ) );
189240
mCrsComboBox->blockSignals( false );
190241
}
191242
else
192243
{
193-
mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
194-
tr( "invalid projection" ) );
244+
int crsNotSetIndex = mCrsComboBox->findData( QgsProjectionSelectionWidget::CrsNotSet );
245+
if ( crsNotSetIndex >= 0 )
246+
{
247+
mCrsComboBox->blockSignals( true );
248+
mCrsComboBox->setCurrentIndex( crsNotSetIndex );
249+
mCrsComboBox->blockSignals( false );
250+
}
251+
else
252+
{
253+
mCrsComboBox->setItemText( mCrsComboBox->findData( QgsProjectionSelectionWidget::CurrentCrs ),
254+
currentCrsOptionText( crs ) );
255+
}
195256
}
196257
mCrs = crs;
197258
}
@@ -233,6 +294,21 @@ void QgsProjectionSelectionWidget::addDefaultCrsOption()
233294
mCrsComboBox->addItem( tr( "Default CRS (%1 - %2)" ).arg( mDefaultCrs.authid(), mDefaultCrs.description() ), QgsProjectionSelectionWidget::DefaultCrs );
234295
}
235296

297+
void QgsProjectionSelectionWidget::addCurrentCrsOption()
298+
{
299+
int index = optionVisible( CrsNotSet ) ? 1 : 0;
300+
mCrsComboBox->insertItem( index, currentCrsOptionText( mCrs ), QgsProjectionSelectionWidget::CurrentCrs );
301+
302+
}
303+
304+
QString QgsProjectionSelectionWidget::currentCrsOptionText( const QgsCoordinateReferenceSystem& crs ) const
305+
{
306+
if ( crs.isValid() )
307+
return tr( "Selected CRS (%1, %2)" ).arg( crs.authid(), crs.description() );
308+
else
309+
return tr( "invalid projection" );
310+
}
311+
236312
void QgsProjectionSelectionWidget::addRecentCrs()
237313
{
238314
QStringList recentProjections = QgsCoordinateReferenceSystem::recentProjections();

src/gui/qgsprojectionselectionwidget.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class GUI_EXPORT QgsProjectionSelectionWidget : public QWidget
4545
ProjectCrs, //!< Current project CRS (if OTF reprojection enabled)
4646
CurrentCrs, //!< Current user selected CRS
4747
DefaultCrs, //!< Global default QGIS CRS
48-
RecentCrs //!< Recently used CRS
48+
RecentCrs, //!< Recently used CRS
49+
CrsNotSet, //!< Not set (hidden by default)
4950
};
5051

5152
explicit QgsProjectionSelectionWidget( QWidget *parent = nullptr );
@@ -64,15 +65,36 @@ class GUI_EXPORT QgsProjectionSelectionWidget : public QWidget
6465
/** Sets whether a predefined CRS option should be shown in the widget.
6566
* @param option CRS option to show/hide
6667
* @param visible whether the option should be shown
68+
* @see optionVisible()
6769
*/
6870
void setOptionVisible( const CrsOption option, const bool visible );
6971

72+
/**
73+
* Returns whether the specified CRS option is visible in the widget.
74+
* @note added in QGIS 3.0
75+
* @see setOptionVisible()
76+
*/
77+
bool optionVisible( CrsOption option ) const;
78+
79+
/**
80+
* Sets the text to show for the not set option. Note that this option is not shown
81+
* by default and must be set visible by calling setOptionVisible().
82+
* @note added in QGIS 3.0
83+
*/
84+
void setNotSetText( const QString& text );
85+
7086
signals:
7187

7288
/** Emitted when the selected CRS is changed
7389
*/
7490
void crsChanged( const QgsCoordinateReferenceSystem& );
7591

92+
/**
93+
* Emitted when the not set option is selected.
94+
* @note added in QGIS 3.0
95+
*/
96+
void cleared();
97+
7698
public slots:
7799

78100
/** Sets the current CRS for the widget
@@ -99,9 +121,13 @@ class GUI_EXPORT QgsProjectionSelectionWidget : public QWidget
99121
QComboBox* mCrsComboBox;
100122
QToolButton* mButton;
101123
QgsGenericProjectionSelector* mDialog;
124+
QString mNotSetText;
102125

126+
void addNotSetOption();
103127
void addProjectCrsOption();
104128
void addDefaultCrsOption();
129+
void addCurrentCrsOption();
130+
QString currentCrsOptionText( const QgsCoordinateReferenceSystem& crs ) const;
105131
void addRecentCrs();
106132
bool crsIsShown( const long srsid ) const;
107133

tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ ADD_PYTHON_TEST(PyQgsPanelWidgetStack test_qgspanelwidgetstack.py)
7474
ADD_PYTHON_TEST(PyQgsPoint test_qgspoint.py)
7575
ADD_PYTHON_TEST(PyQgsPointClusterRenderer test_qgspointclusterrenderer.py)
7676
ADD_PYTHON_TEST(PyQgsPointDisplacementRenderer test_qgspointdisplacementrenderer.py)
77+
ADD_PYTHON_TEST(PyQgsProjectionSelectionWidget test_qgsprojectionselectionwidget.py)
7778
ADD_PYTHON_TEST(PyQgsRangeWidgets test_qgsrangewidgets.py)
7879
ADD_PYTHON_TEST(PyQgsRasterFileWriter test_qgsrasterfilewriter.py)
7980
ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsProjectionSelectionWidget.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Nyall Dawson'
10+
__date__ = '12/11/2016'
11+
__copyright__ = 'Copyright 2016, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
from qgis.gui import QgsProjectionSelectionWidget
18+
from qgis.core import QgsCoordinateReferenceSystem, QgsProject
19+
from qgis.testing import start_app, unittest
20+
from qgis.PyQt.QtGui import QColor
21+
start_app()
22+
23+
24+
class TestQgsProjectionSelectionWidget(unittest.TestCase):
25+
26+
def testShowingHiding(self):
27+
""" test showing and hiding options """
28+
w = QgsProjectionSelectionWidget()
29+
30+
# layer crs
31+
w.setOptionVisible(QgsProjectionSelectionWidget.LayerCrs, False)
32+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.LayerCrs))
33+
w.setOptionVisible(QgsProjectionSelectionWidget.LayerCrs, True)
34+
# should still be hidden, because layer crs not set
35+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.LayerCrs))
36+
w.setLayerCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
37+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.LayerCrs))
38+
w.setOptionVisible(QgsProjectionSelectionWidget.LayerCrs, False)
39+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.LayerCrs))
40+
41+
# project crs
42+
w.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, False)
43+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.ProjectCrs))
44+
w.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, True)
45+
# should still be hidden, because project crs was not set
46+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.ProjectCrs))
47+
QgsProject.instance().setCrs(QgsCoordinateReferenceSystem('EPSG:3113'))
48+
w = QgsProjectionSelectionWidget()
49+
w.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, True)
50+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.ProjectCrs))
51+
# should still be hidden, because otf reprojection not active
52+
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectionsEnabled", 1)
53+
w = QgsProjectionSelectionWidget()
54+
w.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, True)
55+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.ProjectCrs))
56+
w.setOptionVisible(QgsProjectionSelectionWidget.ProjectCrs, False)
57+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.ProjectCrs))
58+
59+
# default crs
60+
w.setOptionVisible(QgsProjectionSelectionWidget.DefaultCrs, False)
61+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.DefaultCrs))
62+
w.setOptionVisible(QgsProjectionSelectionWidget.DefaultCrs, True)
63+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.DefaultCrs))
64+
65+
# current crs
66+
w = QgsProjectionSelectionWidget()
67+
w.setOptionVisible(QgsProjectionSelectionWidget.CurrentCrs, False)
68+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
69+
w.setOptionVisible(QgsProjectionSelectionWidget.CurrentCrs, True)
70+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
71+
72+
w = QgsProjectionSelectionWidget()
73+
w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
74+
w.setOptionVisible(QgsProjectionSelectionWidget.CurrentCrs, False)
75+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
76+
w.setOptionVisible(QgsProjectionSelectionWidget.CurrentCrs, True)
77+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
78+
79+
# not set
80+
w = QgsProjectionSelectionWidget()
81+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, False)
82+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
83+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)
84+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
85+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, False)
86+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
87+
88+
def testShowingNotSetOption(self):
89+
""" test showing the not set option """
90+
91+
w = QgsProjectionSelectionWidget()
92+
# start with an invalid CRS
93+
w.setCrs(QgsCoordinateReferenceSystem())
94+
# add the not-set option
95+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)
96+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
97+
# current crs (which would show "invalid") should be hidden
98+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
99+
# hide not-set option
100+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, False)
101+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
102+
# and now current crs option ('invalid') should be reshown
103+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
104+
105+
# repeat with a slightly different workflow
106+
w = QgsProjectionSelectionWidget()
107+
# start with an invalid CRS
108+
w.setCrs(QgsCoordinateReferenceSystem())
109+
# add the not-set option
110+
w.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True)
111+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
112+
# current crs (which would show "invalid") should be hidden
113+
self.assertFalse(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
114+
# now set a current crs
115+
w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
116+
# both current and not set options should be shown
117+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CurrentCrs))
118+
self.assertTrue(w.optionVisible(QgsProjectionSelectionWidget.CrsNotSet))
119+
120+
121+
if __name__ == '__main__':
122+
unittest.main()

0 commit comments

Comments
 (0)