1 // Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File: QtxDoubleSpinBox.cxx
21 // Author: Sergey TELKOV
23 #include "QtxDoubleSpinBox.h"
26 #include <QDoubleValidator>
31 const double PSEUDO_ZERO = 1.e-20;
34 \class QtxDoubleSpinBox
35 \brief Enhanced version of the Qt's double spin box.
37 The QtxDoubleSpinBox class represents the widget for entering the
38 floating point values. In addition to the functionality provided by
39 QDoubleSpinBox, this class supports "cleared" state - this is the
40 state corresponding to "None" (or empty) entered value.
42 To set "cleared" state use setCleared() method. To check if the spin
43 box stores "cleared" state, use isCleared() method.
46 if (myDblSpinBox->isCleared()) {
47 ... // process "None" state
50 double value = myDblSpinBox->value();
51 ... // process entered value
55 Another useful feature is possibility to use scientific notation (e.g. 1.234e+18)
56 for the widegt text. To enable this, negative precision should be specified either
57 through a constructor or using setPrecision() method.
59 Note that "decimals" property of QDoubleSpinBox is almost completely substituted
60 by "myPrecision" field of QtxDoubleSpinBox class. "decimals" is still used
61 for proper size hint calculation and for rounding minimum and maximum bounds of
68 Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
69 a step value of 1.0 and a precision of 2 decimal places.
70 The value is initially set to 0.00.
72 \param parent parent object
74 QtxDoubleSpinBox::QtxDoubleSpinBox( QWidget* parent )
75 : QDoubleSpinBox( parent ),
78 // VSR 01/07/2010: Disable thousands separator for spin box
79 // (to avoid incosistency of double-2-string and string-2-double conversion)
81 loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
84 // Use precision equal to default Qt decimals
85 myPrecision = decimals();
87 connect( lineEdit(), SIGNAL( textChanged( const QString& ) ),
88 this, SLOT( onTextChanged( const QString& ) ) );
94 Constructs a spin box with specified minimum, maximum and step value.
95 The precision is set to 2 decimal places.
96 The value is initially set to the minimum value.
98 \param min spin box minimum possible value
99 \param max spin box maximum possible value
100 \param step spin box increment/decrement value
101 \param parent parent object
103 QtxDoubleSpinBox::QtxDoubleSpinBox( double min, double max, double step, QWidget* parent )
104 : QDoubleSpinBox( parent ),
107 // VSR 01/07/2010: Disable thousands separator for spin box
108 // (to avoid incosistency of double-2-string and string-2-double conversion)
110 loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
113 // Use precision equal to default Qt decimals
114 myPrecision = decimals();
118 setSingleStep( step );
120 connect( lineEdit(), SIGNAL( textChanged( const QString& ) ),
121 this, SLOT( onTextChanged( const QString& ) ) );
127 Constructs a spin box with specified minimum, maximum and step value.
128 The precision is set to <prec> decimal places.
129 The value is initially set to the minimum value.
131 \param min spin box minimum possible value
132 \param max spin box maximum possible value
133 \param step spin box increment/decrement value
134 \param prec non-negative values means the number of digits after the decimal point,
135 negative value means the maximum number of significant digits for the scientific notation
136 \param dec number of digits after the decimal point passed to base Qt class (used for correct control sizing only!)
137 \param parent parent object
139 QtxDoubleSpinBox::QtxDoubleSpinBox( double min, double max, double step, int prec, int dec, QWidget* parent )
140 : QDoubleSpinBox( parent ),
144 // VSR 01/07/2010: Disable thousands separator for spin box
145 // (to avoid incosistency of double-2-string and string-2-double conversion)
147 loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
153 setSingleStep( step );
155 connect( lineEdit(), SIGNAL( textChanged( const QString& ) ),
156 this, SLOT( onTextChanged( const QString& ) ) );
162 QtxDoubleSpinBox::~QtxDoubleSpinBox()
167 \brief Check if spin box is in the "cleared" state.
168 \return \c true if spin box is cleared
171 bool QtxDoubleSpinBox::isCleared() const
177 \brief Change "cleared" status of the spin box.
178 \param on new "cleared" status
181 void QtxDoubleSpinBox::setCleared( const bool on )
183 if ( myCleared == on )
187 setSpecialValueText( specialValueText() );
191 \brief Set precision of the spin box
193 If precision value is less than 0, the 'g' format is used for value output,
194 otherwise 'f' format is used.
196 \param prec new precision value.
199 void QtxDoubleSpinBox::setPrecision( const int prec )
201 int newPrec = qMax( prec, 0 );
202 int oldPrec = qMax( myPrecision, 0 );
204 if ( newPrec != oldPrec )
209 \brief Get precision value of the spin box
210 \return current prevision value
213 int QtxDoubleSpinBox::getPrecision() const
219 \brief Interpret text entered by the user as a value.
220 \param text text entered by the user
224 double QtxDoubleSpinBox::valueFromText( const QString& text ) const
227 return text.toDouble();
229 return QDoubleSpinBox::valueFromText(text);
233 \brief This function is used by the spin box whenever it needs to display
236 \param val spin box value
237 \return text representation of the value
240 QString QtxDoubleSpinBox::textFromValue( double val ) const
242 QString s = locale().toString( val, myPrecision >= 0 ? 'f' : 'g', qAbs( myPrecision ) );
243 return removeTrailingZeroes( s );
247 \brief Return source string with removed leading and trailing zeros.
248 \param str source string
249 \return resulting string
251 QString QtxDoubleSpinBox::removeTrailingZeroes( const QString& src ) const
253 QString delim( locale().decimalPoint() );
255 int idx = src.lastIndexOf( delim );
259 QString iPart = src.left( idx );
260 QString fPart = src.mid( idx + 1 );
262 int idx1 = fPart.lastIndexOf( QRegExp( "e[+|-]?[0-9]+" ) );
264 ePart = fPart.mid( idx1 );
265 fPart = fPart.left( idx1 );
268 fPart.remove( QRegExp( "0+$" ) );
271 if ( !fPart.isEmpty() )
272 res += delim + fPart;
279 \brief Perform \a steps increment/decrement steps.
281 The \a steps value can be any integer number. If it is > 0,
282 the value incrementing is done, otherwise value is decremented
285 \param steps number of increment/decrement steps
287 void QtxDoubleSpinBox::stepBy( int steps )
291 QDoubleSpinBox::stepBy( steps );
292 double tmpval = value();
293 if ( qAbs( tmpval ) < PSEUDO_ZERO ) tmpval = 0.;
294 if ( tmpval < minimum() ) tmpval = minimum();
295 else if ( tmpval > maximum() ) tmpval = maximum();
300 \brief This function is used to determine whether input is valid.
301 \param str currently entered value
302 \param pos cursor position in the string
303 \return validating operation result
305 QValidator::State QtxDoubleSpinBox::validate( QString& str, int& pos ) const
307 QString pref = this->prefix();
308 QString suff = this->suffix();
309 uint overhead = pref.length() + suff.length();
310 QValidator::State state = QValidator::Invalid;
312 QDoubleValidator v (NULL);
314 // If 'g' format is used (myPrecision < 0), then
315 // myPrecision - 1 digits are allowed after the decimal point.
316 // Otherwise, expect myPrecision digits after the decimal point.
317 int decs = myPrecision < 0 ? qAbs( myPrecision ) - 1 : myPrecision;
319 v.setDecimals( decs );
320 v.setBottom( minimum() );
321 v.setTop( maximum() );
322 v.setNotation( myPrecision >= 0 ? QDoubleValidator::StandardNotation :
323 QDoubleValidator::ScientificNotation );
326 state = v.validate( str, pos );
329 if ( str.length() >= overhead && str.startsWith( pref ) &&
330 str.right( suff.length() ) == suff )
332 QString core = str.mid( pref.length(), str.length() - overhead );
333 int corePos = pos - pref.length();
334 state = v.validate( core, corePos );
335 pos = corePos + pref.length();
336 str.replace( pref.length(), str.length() - overhead, core );
340 state = v.validate( str, pos );
341 if ( state == QValidator::Invalid )
343 QString special = this->specialValueText().trimmed();
344 QString candidate = str.trimmed();
345 if ( special.startsWith( candidate ) )
347 if ( candidate.length() == special.length() )
348 state = QValidator::Acceptable;
350 state = QValidator::Intermediate;
356 // Treat values ouside (min; max) range as Invalid
357 // This check is enabled by assigning "strict_validity_check" dynamic property
358 // with value "true" to the spin box instance.
359 if ( state == QValidator::Intermediate ){
361 double val = str.toDouble( &isOk );
363 QVariant propVal = property( "strict_validity_check" );
364 if ( propVal.isValid() && propVal.canConvert( QVariant::Bool ) && propVal.toBool() ){
365 if ( val < minimum() || val > maximum() )
366 state = QValidator::Invalid;
369 else if ( myPrecision < 0 ){
370 // Consider too large negative exponent as Invalid
371 QChar e( locale().exponential() );
372 int epos = str.indexOf( e, 0, Qt::CaseInsensitive );
374 epos++; // Skip exponential symbol itself
375 QString exponent = str.right( str.length() - epos );
376 int expValue = exponent.toInt( &isOk );
377 if ( isOk && expValue < std::numeric_limits<double>::min_exponent10 )
378 state = QValidator::Invalid;
387 \brief Called when user enters the text in the spin box.
388 \param txt current spin box text (not used)
390 void QtxDoubleSpinBox::onTextChanged( const QString& /*txt*/ )