QGIS API Documentation  2.99.0-Master (d55fa22)
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  , mScale( 1.0 )
30  , mMinScale( 0.0 )
31 {
32  updateScales();
33 
34  setEditable( true );
35  setInsertPolicy( QComboBox::NoInsert );
36  setCompleter( nullptr );
37  connect( this, static_cast<void ( QComboBox::* )( const QString & )>( &QComboBox::activated ), this, &QgsScaleComboBox::fixupScale );
38  connect( lineEdit(), &QLineEdit::editingFinished, this, &QgsScaleComboBox::fixupScale );
39  fixupScale();
40 }
41 
42 void QgsScaleComboBox::updateScales( const QStringList &scales )
43 {
44  QStringList myScalesList;
45  QString oldScale = currentText();
46 
47  if ( scales.isEmpty() )
48  {
49  QgsSettings settings;
50  QString myScales = settings.value( QStringLiteral( "Map/scales" ), PROJECT_SCALES ).toString();
51  if ( !myScales.isEmpty() )
52  {
53  myScalesList = myScales.split( ',' );
54  }
55  }
56  else
57  {
58  QStringList::const_iterator scaleIt = scales.constBegin();
59  for ( ; scaleIt != scales.constEnd(); ++scaleIt )
60  {
61  myScalesList.append( *scaleIt );
62  }
63  }
64 
65  QStringList parts;
66  double denominator;
67  bool ok;
68  for ( int i = 0; i < myScalesList.size(); ++i )
69  {
70  parts = myScalesList[ i ] .split( ':' );
71  denominator = QLocale::system().toDouble( parts[1], &ok );
72  if ( ok )
73  {
74  myScalesList[ i ] = toString( 1.0 / denominator );
75  }
76  }
77 
78  blockSignals( true );
79  clear();
80  addItems( myScalesList );
81  setScaleString( oldScale );
82  blockSignals( false );
83 }
84 
86 {
87  QComboBox::showPopup();
88 
89  if ( !currentText().contains( ':' ) )
90  {
91  return;
92  }
93  QStringList parts = currentText().split( ':' );
94  bool ok;
95  int idx = 0;
96  int min = 999999;
97  long currScale = parts.at( 1 ).toLong( &ok );
98  long nextScale, delta;
99  for ( int i = 0; i < count(); i++ )
100  {
101  parts = itemText( i ).split( ':' );
102  nextScale = parts.at( 1 ).toLong( &ok );
103  delta = qAbs( currScale - nextScale );
104  if ( delta < min )
105  {
106  min = delta;
107  idx = i;
108  }
109  }
110 
111  blockSignals( true );
112  view()->setCurrentIndex( model()->index( idx, 0 ) );
113  blockSignals( false );
114  view()->setMinimumWidth( view()->sizeHintForColumn( 0 ) );
115 }
116 
118 {
119  return toString( mScale );
120 }
121 
122 bool QgsScaleComboBox::setScaleString( const QString &scaleTxt )
123 {
124  bool ok;
125  double newScale = toDouble( scaleTxt, &ok );
126  double oldScale = mScale;
127  if ( newScale < mMinScale && newScale != 0 )
128  {
129  newScale = mMinScale;
130  }
131  if ( ! ok )
132  {
133  return false;
134  }
135  else
136  {
137  mScale = newScale;
138  setEditText( toString( mScale ) );
139  clearFocus();
140  if ( mScale != oldScale )
141  {
142  emit scaleChanged( mScale );
143  }
144  return true;
145  }
146 }
147 
149 {
150  return mScale;
151 }
152 
154 {
155  setScaleString( toString( scale ) );
156 }
157 
158 void QgsScaleComboBox::fixupScale()
159 {
160  QStringList txtList = currentText().split( ':' );
161  bool userSetScale = txtList.size() != 2;
162 
163  bool ok;
164  double newScale = toDouble( currentText(), &ok );
165 
166  // Valid string representation
167  if ( ok )
168  {
169  // if a user types scale = 2345, we transform to 1:2345
170  if ( userSetScale && newScale >= 1.0 )
171  {
172  newScale = 1 / newScale;
173  }
174  setScale( newScale );
175  }
176  else
177  {
178  setScale( mScale );
179  }
180 }
181 
183 {
184  if ( scale == 0 )
185  {
186  return QStringLiteral( "0" );
187  }
188  else if ( scale > 1 )
189  {
190  return QStringLiteral( "%1:1" ).arg( QLocale::system().toString( qRound( scale ) ) );
191  }
192  else
193  {
194  return QStringLiteral( "1:%1" ).arg( QLocale::system().toString( qRound( 1.0 / scale ) ) );
195  }
196 }
197 
198 double QgsScaleComboBox::toDouble( const QString &scaleString, bool *returnOk )
199 {
200  bool ok = false;
201  QString scaleTxt( scaleString );
202 
203  double scale = qgsPermissiveToDouble( scaleTxt, ok );
204  if ( ok )
205  {
206  // Create a text version and set that text and rescan
207  // Idea is to get the same rounding.
208  scaleTxt = toString( scale );
209  }
210  else
211  {
212  // It is now either X:Y or not valid
213  QStringList txtList = scaleTxt.split( ':' );
214  if ( 2 == txtList.size() )
215  {
216  bool okX = false;
217  bool okY = false;
218  int x = qgsPermissiveToInt( txtList[ 0 ], okX );
219  int y = qgsPermissiveToInt( txtList[ 1 ], okY );
220  if ( okX && okY )
221  {
222  // Scale is fraction of x and y
223  scale = ( double )x / ( double )y;
224  ok = true;
225  }
226  }
227  }
228 
229  // Set up optional return flag
230  if ( returnOk )
231  {
232  *returnOk = ok;
233  }
234  return scale;
235 }
236 
238 {
239  mMinScale = scale;
240  if ( mScale < scale && mScale != 0 )
241  {
242  setScale( scale );
243  }
244 }
This class is a composition of two QSettings instances:
Definition: qgssettings.h:54
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:87
void setScale(double scale)
Function to set the selected scale from double.
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:94
bool setScaleString(const QString &scaleTxt)
Function to set the selected scale from text.
void showPopup() override
void scaleChanged(double scale)
Signal is emitted when user has finished editing/selecting a new scale.
static double toDouble(const QString &scaleString, bool *ok=nullptr)
Helper function to convert a scale string to double.
double scale() const
Function to read the selected scale as double.
void setMinScale(double scale)
Set the minimum allowed scale.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:452
static QString toString(double scale)
Helper function to convert a double to scale string.
const QString PROJECT_SCALES
Definition: qgis.cpp:65
QString scaleString()
Function to read the selected scale as text.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
void updateScales(const QStringList &scales=QStringList())
QgsScaleComboBox(QWidget *parent=nullptr)