QGIS API Documentation  2.11.0-Master
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 
22 #include <QAbstractItemView>
23 #include <QLocale>
24 #include <QSettings>
25 #include <QLineEdit>
26 
27 QgsScaleComboBox::QgsScaleComboBox( QWidget* parent ) : QComboBox( parent ), mScale( 1.0 )
28 {
29  updateScales();
30 
31  setEditable( true );
32  setInsertPolicy( QComboBox::NoInsert );
33  setCompleter( 0 );
34  connect( this, SIGNAL( activated( const QString & ) ), this, SLOT( fixupScale() ) );
35  connect( lineEdit(), SIGNAL( editingFinished() ), this, SLOT( fixupScale() ) );
36  fixupScale();
37 }
38 
40 {
41 }
42 
44 {
45  QStringList myScalesList;
46  QString oldScale = currentText();
47 
48  if ( scales.isEmpty() )
49  {
50  QSettings settings;
51  QString myScales = settings.value( "Map/scales", PROJECT_SCALES ).toString();
52  if ( !myScales.isEmpty() )
53  {
54  myScalesList = myScales.split( "," );
55  }
56  }
57  else
58  {
59  QStringList::const_iterator scaleIt = scales.constBegin();
60  for ( ; scaleIt != scales.constEnd(); ++scaleIt )
61  {
62  myScalesList.append( *scaleIt );
63  }
64  }
65 
66  QStringList parts;
67  double denominator;
68  bool ok;
69  for ( int i = 0; i < myScalesList.size(); ++i )
70  {
71  parts = myScalesList[ i ] .split( ':' );
72  denominator = QLocale::system().toDouble( parts[1], &ok );
73  if ( ok )
74  {
75  myScalesList[ i ] = toString( 1.0 / denominator );
76  }
77  }
78 
79  blockSignals( true );
80  clear();
81  addItems( myScalesList );
82  setScaleString( oldScale );
83  blockSignals( false );
84 }
85 
87 {
89 
90  if ( !currentText().contains( ':' ) )
91  {
92  return;
93  }
94  QStringList parts = currentText().split( ':' );
95  bool ok;
96  int idx = 0;
97  int min = 999999;
98  long currScale = parts.at( 1 ).toLong( &ok );
99  long nextScale, delta;
100  for ( int i = 0; i < count(); i++ )
101  {
102  parts = itemText( i ).split( ':' );
103  nextScale = parts.at( 1 ).toLong( &ok );
104  delta = qAbs( currScale - nextScale );
105  if ( delta < min )
106  {
107  min = delta;
108  idx = i;
109  }
110  }
111 
112  blockSignals( true );
113  view()->setCurrentIndex( model()->index( idx, 0 ) );
114  blockSignals( false );
115 }
116 
119 {
120  return toString( mScale );
121 }
122 
125 {
126  bool ok;
127  double newScale = toDouble( scaleTxt, &ok );
128  if ( ! ok )
129  {
130  return false;
131  }
132  else
133  {
134  mScale = newScale;
135  setEditText( toString( mScale ) );
136  clearFocus();
137  return true;
138  }
139 }
140 
143 {
144  return mScale;
145 }
146 
148 void QgsScaleComboBox::setScale( double scale )
149 {
150  setScaleString( toString( scale ) );
151 }
152 
154 void QgsScaleComboBox::fixupScale()
155 {
156  double newScale;
157  double oldScale = mScale;
158  bool ok, userSetScale;
159  QStringList txtList = currentText().split( ':' );
160  userSetScale = txtList.size() != 2;
161 
162  // QgsDebugMsg( QString( "entered with oldScale: %1" ).arg( oldScale ) );
163  newScale = toDouble( currentText(), &ok );
164 
165  // Valid string representation
166  if ( ok && ( newScale != oldScale ) )
167  {
168  // if a user types scale = 2345, we transform to 1:2345
169  if ( userSetScale && newScale >= 1.0 )
170  {
171  mScale = 1 / newScale;
172  }
173  else
174  {
175  mScale = newScale;
176  }
177  setScale( mScale );
178  emit scaleChanged();
179  }
180  else
181  {
182  // Invalid string representation or same scale
183  // Reset to the old
184  setScale( mScale );
185  }
186 }
187 
189 {
190  if ( scale == 0 )
191  {
192  return "0";
193  }
194  else if ( scale > 1 )
195  {
196  return QString( "%1:1" ).arg( QLocale::system().toString( qRound( scale ) ) );
197  }
198  else
199  {
200  return QString( "1:%1" ).arg( QLocale::system().toString( qRound( 1.0 / scale ) ) );
201  }
202 }
203 
204 double QgsScaleComboBox::toDouble( QString scaleString, bool * returnOk )
205 {
206  bool ok = false;
207  QString scaleTxt( scaleString );
208 
209  double scale = QGis::permissiveToDouble( scaleTxt, ok );
210  if ( ok )
211  {
212  // Create a text version and set that text and rescan
213  // Idea is to get the same rounding.
214  scaleTxt = toString( scale );
215  }
216  else
217  {
218  // It is now either X:Y or not valid
219  QStringList txtList = scaleTxt.split( ':' );
220  if ( 2 == txtList.size() )
221  {
222  bool okX = false;
223  bool okY = false;
224  int x = QGis::permissiveToInt( txtList[ 0 ], okX );
225  int y = QGis::permissiveToInt( txtList[ 1 ], okY );
226  if ( okX && okY )
227  {
228  // Scale is fraction of x and y
229  scale = ( double )x / ( double )y;
230  ok = true;
231  }
232  }
233  }
234 
235  // Set up optional return flag
236  if ( returnOk )
237  {
238  *returnOk = ok;
239  }
240  return scale;
241 }
242 
243 
static unsigned index
static int permissiveToInt(QString string, bool &ok)
Converts a string to an integer in a permissive way, eg allowing for incorrect numbers of digits betw...
Definition: qgis.cpp:195
QAbstractItemModel * model() const
virtual ~QgsScaleComboBox()
void setCurrentIndex(const QModelIndex &index)
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static double permissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, eg allowing for incorrect numbers of digits betwee...
Definition: qgis.cpp:188
const T & at(int i) const
void clear()
int y() const
static double toDouble(QString scaleString, bool *ok=NULL)
Helper function to convert a scale string to double.
void setEditText(const QString &text)
QString itemText(int index) const
void setScale(double scale)
Function to set the selected scale from double.
void setEditable(bool editable)
double toDouble(const QString &s, bool *ok) const
int size() const
QLocale system()
void showPopup() override
int count() const
void append(const T &value)
int x() const
bool isEmpty() const
bool isEmpty() const
void activated(int index)
double scale()
Function to read the selected scale as double.
bool blockSignals(bool block)
int min(int a, int b)
Definition: util.h:88
bool setScaleString(QString scaleTxt)
Function to set the selected scale from text.
static QString toString(double scale)
Helper function to convert a double to scale string.
QLineEdit * lineEdit() const
void scaleChanged()
Signal is emitted when user has finished editing/selecting a new scale.
QVariant value(const QString &key, const QVariant &defaultValue) const
void clearFocus()
const QString PROJECT_SCALES
Definition: qgis.cpp:68
QString scaleString()
Function to read the selected scale as text.
void setInsertPolicy(InsertPolicy policy)
void setCompleter(QCompleter *completer)
QgsScaleComboBox(QWidget *parent=0)
QStringList split(const QString &sep, const QString &str, bool allowEmptyEntries)
void addItems(const QStringList &texts)
void updateScales(const QStringList &scales=QStringList())
const_iterator constEnd() const
const_iterator constBegin() const
QString currentText() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual void showPopup()
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QAbstractItemView * view() const