QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
qgsscalecombobox.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsscalecombobox.h
3 ------------------------
4 begin : January 7, 2012
5 copyright : (C) 2012 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
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
18#include "qgis.h"
19#include "qgslogger.h"
20#include "qgsscalecombobox.h"
21#include "qgssettings.h"
22
23#include <QAbstractItemView>
24#include <QLocale>
25#include <QLineEdit>
26
28 : QComboBox( parent )
29{
31
32 setEditable( true );
33 setInsertPolicy( QComboBox::NoInsert );
34 setCompleter( nullptr );
35 connect( this, qOverload< int >( &QComboBox::activated ), this, &QgsScaleComboBox::fixupScale );
36 connect( lineEdit(), &QLineEdit::editingFinished, this, &QgsScaleComboBox::fixupScale );
37 fixupScale();
38}
39
40void QgsScaleComboBox::updateScales( const QStringList &scales )
41{
42 QStringList myScalesList;
43 const QString oldScale = currentText();
44
45 if ( scales.isEmpty() )
46 {
47 const QgsSettings settings;
48 const QString myScales = settings.value( QStringLiteral( "Map/scales" ), Qgis::defaultProjectScales() ).toString();
49 if ( !myScales.isEmpty() )
50 {
51 myScalesList = myScales.split( ',' );
52 }
53 }
54 else
55 {
56 QStringList::const_iterator scaleIt = scales.constBegin();
57 for ( ; scaleIt != scales.constEnd(); ++scaleIt )
58 {
59 myScalesList.append( *scaleIt );
60 }
61 }
62
63 for ( int i = 0; i < myScalesList.size(); ++i )
64 {
65 const QStringList parts = myScalesList[ i ] .split( ':' );
66 if ( parts.size() < 2 )
67 continue;
68
69 bool ok = false;
70 const double denominator = QLocale().toDouble( parts[1], &ok );
71 if ( ok )
72 {
73 myScalesList[ i ] = toString( denominator );
74 }
75 }
76
77 blockSignals( true );
78 clear();
79 addItems( myScalesList );
80 setScaleString( oldScale );
81 blockSignals( false );
82}
83
85{
86 QComboBox::showPopup();
87
88 if ( !currentText().contains( ':' ) )
89 {
90 return;
91 }
92 QStringList parts = currentText().split( ':' );
93 bool ok;
94 int idx = 0;
95 int min = 999999;
96 const long currScale = parts.at( 1 ).toLong( &ok );
97 long nextScale, delta;
98 for ( int i = 0; i < count(); i++ )
99 {
100 parts = itemText( i ).split( ':' );
101 nextScale = parts.at( 1 ).toLong( &ok );
102 delta = std::labs( currScale - nextScale );
103 if ( delta < min )
104 {
105 min = delta;
106 idx = i;
107 }
108 }
109
110 blockSignals( true );
111 view()->setCurrentIndex( model()->index( idx, 0 ) );
112 blockSignals( false );
113 view()->setMinimumWidth( view()->sizeHintForColumn( 0 ) );
114}
115
117{
118 return toString( mScale );
119}
120
121bool QgsScaleComboBox::setScaleString( const QString &string )
122{
123 const double oldScale = mScale;
124 if ( mAllowNull && string.trimmed().isEmpty() )
125 {
126 mScale = std::numeric_limits< double >::quiet_NaN();
127 setEditText( toString( mScale ) );
128 clearFocus();
129 if ( !std::isnan( oldScale ) )
130 {
131 emit scaleChanged( mScale );
132 }
133 return true;
134 }
135
136 bool ok;
137 double newScale = toDouble( string, &ok );
138 if ( newScale > mMinScale && newScale != 0 && mMinScale != 0 )
139 {
140 newScale = mMinScale;
141 }
142 if ( ! ok )
143 {
144 return false;
145 }
146 else
147 {
148 mScale = newScale;
149 setEditText( toString( mScale ) );
150 clearFocus();
151 if ( mScale != oldScale )
152 {
153 emit scaleChanged( mScale );
154 }
155 return true;
156 }
157}
158
160{
161 return mScale;
162}
163
165{
166 return std::isnan( mScale );
167}
168
169void QgsScaleComboBox::setScale( double scale )
170{
172}
173
174void QgsScaleComboBox::fixupScale()
175{
176 if ( mAllowNull && currentText().trimmed().isEmpty() )
177 {
178 setScale( std::numeric_limits< double >::quiet_NaN() );
179 return;
180 }
181
182 const QStringList txtList = currentText().split( ':' );
183 const bool userSetScale = txtList.size() != 2;
184
185 bool ok;
186 double newScale = toDouble( currentText(), &ok );
187
188 // Valid string representation
189 if ( ok )
190 {
191 // if a user types scale = 2345, we transform to 1:2345
192 if ( userSetScale && newScale < 1.0 && !qgsDoubleNear( newScale, 0.0 ) )
193 {
194 newScale = 1 / newScale;
195 }
196 setScale( newScale );
197 }
198 else
199 {
200 setScale( mScale );
201 }
202}
203
204QString QgsScaleComboBox::toString( double scale )
205{
206 if ( std::isnan( scale ) )
207 {
208 return QString();
209 }
210 if ( scale == 0 )
211 {
212 return QStringLiteral( "0" );
213 }
214 else if ( scale <= 1 )
215 {
216 return QStringLiteral( "%1:1" ).arg( QLocale().toString( static_cast< int >( std::round( 1.0 / scale ) ) ) );
217 }
218 else
219 {
220 return QStringLiteral( "1:%1" ).arg( QLocale().toString( static_cast< float >( std::round( scale ) ), 'f', 0 ) );
221 }
222}
223
224double QgsScaleComboBox::toDouble( const QString &scaleString, bool *returnOk )
225{
226 bool ok = false;
227 QString scaleTxt( scaleString );
228
229 const double denominator = qgsPermissiveToDouble( scaleTxt, ok );
230 double scale = !qgsDoubleNear( denominator, 0.0 ) ? 1.0 / denominator : 0.0;
231 if ( ok )
232 {
233 // Create a text version and set that text and rescan
234 // Idea is to get the same rounding.
235 scaleTxt = toString( scale );
236 }
237 else
238 {
239 // It is now either X:Y or not valid
240 QStringList txtList = scaleTxt.split( ':' );
241 if ( 2 == txtList.size() )
242 {
243 bool okX = false;
244 bool okY = false;
245 const int x = qgsPermissiveToInt( txtList[ 0 ], okX );
246 const int y = qgsPermissiveToInt( txtList[ 1 ], okY );
247 if ( okX && okY && x != 0 )
248 {
249 // Scale is fraction of x and y
250 scale = static_cast< double >( y ) / static_cast< double >( x );
251 ok = true;
252 }
253 }
254 }
255
256 // Set up optional return flag
257 if ( returnOk )
258 {
259 *returnOk = ok;
260 }
261 return scale;
262}
263
264void QgsScaleComboBox::setAllowNull( bool allowNull )
265{
266 mAllowNull = allowNull;
267 lineEdit()->setClearButtonEnabled( allowNull );
268 updateScales();
269}
270
272{
273 return mAllowNull;
274}
275
277{
278 mMinScale = scale;
279 if ( mScale > mMinScale && mScale != 0 && mMinScale != 0 )
280 {
281 setScale( mMinScale );
282 }
283}
284
286{
287 if ( allowNull() )
288 setScale( std::numeric_limits< double >::quiet_NaN() );
289}
static QString defaultProjectScales()
A string with default project scales.
Definition qgis.cpp:271
static QString toString(double scale)
Helper function to convert a scale double to scale string.
void updateScales(const QStringList &scales=QStringList())
Sets the list of predefined scales to show in the combobox.
QString scaleString() const
Returns the selected scale as a string, e.g.
bool setScaleString(const QString &string)
Set the selected scale from a string, e.g.
void setAllowNull(bool allowNull)
Sets whether the scale combobox can be set to a NULL value.
QgsScaleComboBox(QWidget *parent=nullptr)
Constructor for QgsScaleComboBox.
bool isNull() const
Returns true if the combo box is currently set to a "null" value.
bool allowNull() const
Returns true if the combobox can be set to a NULL value.
static double toDouble(const QString &string, bool *ok=nullptr)
Helper function to convert a scale string to double.
void setScale(double scale)
Set the selected scale from a double.
void showPopup() override
void setNull()
Sets the combo box to the null value.
void setMinScale(double scale)
Set the minimum allowed scale.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
This class is a composition of two QSettings instances:
Definition qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
Definition qgis.cpp:71
int qgsPermissiveToInt(QString string, bool &ok)
Converts a string to an integer in a permissive way, e.g., allowing for incorrect numbers of digits b...
Definition qgis.cpp:78
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:2527