1 /**********************************************************************
2 **
3 **
4 ** KIntValidator:
5 **   Copyright (C) 1999 Glen Parker <glenebob@nwlink.com>
6 ** KDoubleValidator:
7 **   Copyright (c) 2002 Marc Mutz <mutz@kde.org>
8 **
9 ** This library is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU Library General Public
11 ** License as published by the Free Software Foundation; either
12 ** version 2 of the License, or (at your option) any later version.
13 **
14 ** This library is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 ** Library General Public License for more details.
18 **
19 ** You should have received a copy of the GNU Library General Public
20 ** License along with this library; if not, write to the Free
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 *****************************************************************************/
24 
25 #include "knumvalidator.h"
26 
27 #include <QWidget>
28 #include <QCharRef>
29 
30 #include <klocale.h>
31 #include <kdebug.h>
32 
33 ///////////////////////////////////////////////////////////////
34 //  Implementation of KIntValidator
35 //
36 class Q_DECL_HIDDEN KIntValidator::KIntValidatorPrivate
37 {
38 public:
KIntValidatorPrivate()39     KIntValidatorPrivate()
40         : _base(0), _min(0), _max(0)
41     {}
42     int _base;
43     int _min;
44     int _max;
45 };
46 
KIntValidator(QWidget * parent,int base)47 KIntValidator::KIntValidator(QWidget *parent, int base)
48     : QValidator(parent), d(new KIntValidatorPrivate)
49 {
50     setBase(base);
51 }
52 
KIntValidator(int bottom,int top,QWidget * parent,int base)53 KIntValidator::KIntValidator(int bottom, int top, QWidget *parent, int base)
54     : QValidator(parent), d(new KIntValidatorPrivate)
55 {
56     setBase(base);
57     setRange(bottom, top);
58 }
59 
~KIntValidator()60 KIntValidator::~KIntValidator()
61 {
62     delete d;
63 }
64 
validate(QString & str,int &) const65 QValidator::State KIntValidator::validate(QString &str, int &) const
66 {
67     bool ok;
68     int  val = 0;
69     QString newStr;
70 
71     newStr = str.trimmed();
72     if (d->_base > 10) {
73         newStr = newStr.toUpper();
74     }
75 
76     if (newStr == QLatin1String("-")) {// a special case
77         if ((d->_min || d->_max) && d->_min >= 0) {
78             ok = false;
79         } else {
80             return QValidator::Acceptable;
81         }
82     } else if (!newStr.isEmpty()) {
83         val = newStr.toInt(&ok, d->_base);
84     } else {
85         val = 0;
86         ok = true;
87     }
88 
89     if (! ok) {
90         return QValidator::Invalid;
91     }
92 
93     if ((! d->_min && ! d->_max) || (val >= d->_min && val <= d->_max)) {
94         return QValidator::Acceptable;
95     }
96 
97     if (d->_max && d->_min >= 0 && val < 0) {
98         return QValidator::Invalid;
99     }
100 
101     return QValidator::Intermediate;
102 }
103 
fixup(QString & str) const104 void KIntValidator::fixup(QString &str) const
105 {
106     int                dummy;
107     int                val;
108     QValidator::State  state;
109 
110     state = validate(str, dummy);
111 
112     if (state == QValidator::Invalid || state == QValidator::Acceptable) {
113         return;
114     }
115 
116     if (! d->_min && ! d->_max) {
117         return;
118     }
119 
120     val = str.toInt(nullptr, d->_base);
121 
122     if (val < d->_min) {
123         val = d->_min;
124     }
125     if (val > d->_max) {
126         val = d->_max;
127     }
128 
129     str.setNum(val, d->_base);
130 }
131 
setRange(int bottom,int top)132 void KIntValidator::setRange(int bottom, int top)
133 {
134     d->_min = bottom;
135     d->_max = top;
136 
137     if (d->_max < d->_min) {
138         d->_max = d->_min;
139     }
140 }
141 
setBase(int base)142 void KIntValidator::setBase(int base)
143 {
144     d->_base = base;
145     if (d->_base < 2) {
146         d->_base = 2;
147     }
148     if (d->_base > 36) {
149         d->_base = 36;
150     }
151 }
152 
bottom() const153 int KIntValidator::bottom() const
154 {
155     return d->_min;
156 }
157 
top() const158 int KIntValidator::top() const
159 {
160     return d->_max;
161 }
162 
base() const163 int KIntValidator::base() const
164 {
165     return d->_base;
166 }
167 
168 ///////////////////////////////////////////////////////////////
169 //  Implementation of KDoubleValidator
170 //
171 
172 class Q_DECL_HIDDEN KDoubleValidator::KDoubleValidatorPrivate
173 {
174 public:
KDoubleValidatorPrivate(bool accept=true)175     KDoubleValidatorPrivate(bool accept = true) : acceptLocalizedNumbers(accept) {}
176 
177     bool acceptLocalizedNumbers;
178 };
179 
KDoubleValidator(QObject * parent)180 KDoubleValidator::KDoubleValidator(QObject *parent)
181     : QDoubleValidator(parent), d(new KDoubleValidatorPrivate())
182 {
183 }
184 
KDoubleValidator(double bottom,double top,int decimals,QObject * parent)185 KDoubleValidator::KDoubleValidator(double bottom, double top, int decimals,
186                                    QObject *parent)
187     : QDoubleValidator(bottom, top, decimals, parent), d(new KDoubleValidatorPrivate())
188 {
189 }
190 
~KDoubleValidator()191 KDoubleValidator::~KDoubleValidator()
192 {
193     delete d;
194 }
195 
acceptLocalizedNumbers() const196 bool KDoubleValidator::acceptLocalizedNumbers() const
197 {
198     return d->acceptLocalizedNumbers;
199 }
200 
setAcceptLocalizedNumbers(bool accept)201 void KDoubleValidator::setAcceptLocalizedNumbers(bool accept)
202 {
203     d->acceptLocalizedNumbers = accept;
204 }
205 
validate(QString & input,int & p) const206 QValidator::State KDoubleValidator::validate(QString &input, int &p) const
207 {
208     QString s = input;
209     if (acceptLocalizedNumbers()) {
210         KLocale *l = KLocale::global();
211         // ok, we have to re-format the number to have:
212         // 1. decimalSymbol == '.'
213         // 2. negativeSign  == '-'
214         // 3. positiveSign  == <empty>
215         // 4. thousandsSeparator() == <empty> (we don't check that there
216         //    are exactly three decimals between each separator):
217         QString d = l->decimalSymbol(),
218                 n = l->negativeSign(),
219                 p = l->positiveSign(),
220                 t = l->thousandsSeparator();
221         // first, delete p's and t's:
222         if (!p.isEmpty())
223             for (int idx = s.indexOf(p); idx >= 0; idx = s.indexOf(p, idx)) {
224                 s.remove(idx, p.length());
225             }
226 
227         if (!t.isEmpty())
228             for (int idx = s.indexOf(t); idx >= 0; idx = s.indexOf(t, idx)) {
229                 s.remove(idx, t.length());
230             }
231 
232         // then, replace the d's and n's
233         if ((!n.isEmpty() && n.indexOf('.') != -1) ||
234                 (!d.isEmpty() && d.indexOf('-') != -1)) {
235             // make sure we don't replace something twice:
236             kWarning() << "KDoubleValidator: decimal symbol contains '-' or "
237                        "negative sign contains '.' -> improve algorithm" << endl;
238             return Invalid;
239         }
240 
241         if (!d.isEmpty() && d != ".")
242             for (int idx = s.indexOf(d); idx >= 0; idx = s.indexOf(d, idx + 1)) {
243                 s.replace(idx, d.length(), '.');
244             }
245 
246         if (!n.isEmpty() && n != "-")
247             for (int idx = s.indexOf(n); idx >= 0; idx = s.indexOf(n, idx + 1)) {
248                 s.replace(idx, n.length(), '-');
249             }
250     }
251 
252     return base::validate(s, p);
253 }
254 
255