Back to index

salome-gui  6.5.0
QtxDoubleSpinBox.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 // File:      QtxDoubleSpinBox.cxx
00021 // Author:    Sergey TELKOV
00022 //
00023 #include "QtxDoubleSpinBox.h"
00024 
00025 #include <QLineEdit>
00026 #include <QDoubleValidator>
00027 #include <QVariant>
00028 
00029 #include <limits>
00030 
00031 const double PSEUDO_ZERO = 1.e-20;
00032 
00074 QtxDoubleSpinBox::QtxDoubleSpinBox( QWidget* parent )
00075 : QDoubleSpinBox( parent ),
00076   myCleared( false )
00077 {
00078   // VSR 01/07/2010: Disable thousands separator for spin box
00079   // (to avoid incosistency of double-2-string and string-2-double conversion)
00080   QLocale loc;
00081   loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
00082   setLocale(loc);
00083 
00084   // Use precision equal to default Qt decimals
00085   myPrecision = decimals();
00086   
00087   connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), 
00088            this, SLOT( onTextChanged( const QString& ) ) );
00089 }
00090 
00103 QtxDoubleSpinBox::QtxDoubleSpinBox( double min, double max, double step, QWidget* parent )
00104 : QDoubleSpinBox( parent ),
00105   myCleared( false )
00106 {
00107   // VSR 01/07/2010: Disable thousands separator for spin box
00108   // (to avoid incosistency of double-2-string and string-2-double conversion)
00109   QLocale loc;
00110   loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
00111   setLocale(loc);
00112 
00113   // Use precision equal to default Qt decimals
00114   myPrecision = decimals();
00115   
00116   setMinimum( min );
00117   setMaximum( max );
00118   setSingleStep( step );
00119 
00120   connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), 
00121            this, SLOT( onTextChanged( const QString& ) ) );
00122 }
00123 
00139 QtxDoubleSpinBox::QtxDoubleSpinBox( double min, double max, double step, int prec, int dec, QWidget* parent )
00140 : QDoubleSpinBox( parent ),
00141   myCleared( false ),
00142   myPrecision( prec )
00143 {
00144   // VSR 01/07/2010: Disable thousands separator for spin box
00145   // (to avoid incosistency of double-2-string and string-2-double conversion)
00146   QLocale loc;
00147   loc.setNumberOptions(loc.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
00148   setLocale(loc);
00149 
00150   setDecimals( dec );
00151   setMinimum( min );
00152   setMaximum( max );
00153   setSingleStep( step );
00154 
00155   connect( lineEdit(), SIGNAL( textChanged( const QString& ) ), 
00156            this, SLOT( onTextChanged( const QString& ) ) );
00157 }
00158 
00162 QtxDoubleSpinBox::~QtxDoubleSpinBox()
00163 {
00164 }
00165 
00171 bool QtxDoubleSpinBox::isCleared() const
00172 {
00173   return myCleared;
00174 }
00175 
00181 void QtxDoubleSpinBox::setCleared( const bool on )
00182 {
00183   if ( myCleared == on )
00184     return;
00185   
00186   myCleared = on;
00187   setSpecialValueText( specialValueText() );
00188 }
00189 
00199 void QtxDoubleSpinBox::setPrecision( const int prec )
00200 {
00201   int newPrec = qMax( prec, 0 );
00202   int oldPrec = qMax( myPrecision, 0 );
00203   myPrecision = prec;
00204   if ( newPrec != oldPrec )
00205     update();
00206 }
00207 
00213 int QtxDoubleSpinBox::getPrecision() const
00214 {
00215   return myPrecision;
00216 }
00217 
00224 double QtxDoubleSpinBox::valueFromText( const QString& text ) const
00225 {
00226   if (myPrecision < 0)
00227     return text.toDouble();
00228 
00229   return QDoubleSpinBox::valueFromText(text);
00230 }
00231 
00240 QString QtxDoubleSpinBox::textFromValue( double val ) const
00241 {
00242   QString s = locale().toString( val, myPrecision >= 0 ? 'f' : 'g', qAbs( myPrecision ) );
00243   return removeTrailingZeroes( s );
00244 }
00245 
00251 QString QtxDoubleSpinBox::removeTrailingZeroes( const QString& src ) const
00252 {
00253   QString delim( locale().decimalPoint() );
00254 
00255   int idx = src.lastIndexOf( delim );
00256   if ( idx == -1 )
00257     return src;
00258 
00259   QString iPart = src.left( idx );
00260   QString fPart = src.mid( idx + 1 );
00261   QString ePart = "";
00262   int idx1 = fPart.lastIndexOf( QRegExp( "e[+|-]?[0-9]+" ) );
00263   if ( idx1 >= 0 ) {
00264     ePart = fPart.mid( idx1 );
00265     fPart = fPart.left( idx1 );
00266   }
00267 
00268   fPart.remove( QRegExp( "0+$" ) );
00269 
00270   QString res = iPart;
00271   if ( !fPart.isEmpty() )
00272     res += delim + fPart;
00273   res += ePart;
00274 
00275   return res;
00276 }
00277 
00287 void QtxDoubleSpinBox::stepBy( int steps )
00288 {
00289   myCleared = false;
00290 
00291   QDoubleSpinBox::stepBy( steps );
00292   double tmpval = value();
00293   if ( qAbs( tmpval ) < PSEUDO_ZERO ) tmpval = 0.;
00294   if ( tmpval < minimum() ) tmpval = minimum();
00295   else if ( tmpval > maximum() ) tmpval = maximum();
00296   setValue( tmpval );
00297 }
00298 
00305 QValidator::State QtxDoubleSpinBox::validate( QString& str, int& pos ) const
00306 {
00307   QString pref = this->prefix();
00308   QString suff = this->suffix();
00309   uint overhead = pref.length() + suff.length();
00310   QValidator::State state = QValidator::Invalid;
00311   
00312   QDoubleValidator v (NULL);
00313   
00314   // If 'g' format is used (myPrecision < 0), then
00315   // myPrecision - 1 digits are allowed after the decimal point.
00316   // Otherwise, expect myPrecision digits after the decimal point.
00317   int decs = myPrecision < 0 ? qAbs( myPrecision ) - 1 : myPrecision;
00318  
00319   v.setDecimals( decs );
00320   v.setBottom( minimum() );
00321   v.setTop( maximum() );
00322   v.setNotation( myPrecision >= 0 ? QDoubleValidator::StandardNotation : 
00323                                     QDoubleValidator::ScientificNotation );
00324 
00325   if ( overhead == 0 )
00326     state = v.validate( str, pos );
00327   else
00328     {
00329       if ( str.length() >= overhead && str.startsWith( pref ) &&
00330            str.right( suff.length() ) == suff )
00331         {
00332           QString core = str.mid( pref.length(), str.length() - overhead );
00333           int corePos = pos - pref.length();
00334           state = v.validate( core, corePos );
00335           pos = corePos + pref.length();
00336           str.replace( pref.length(), str.length() - overhead, core );
00337         }
00338       else
00339         {
00340           state = v.validate( str, pos );
00341           if ( state == QValidator::Invalid )
00342             {
00343               QString special = this->specialValueText().trimmed();
00344               QString candidate = str.trimmed();
00345               if ( special.startsWith( candidate ) )
00346                 {
00347                   if ( candidate.length() == special.length() )
00348                     state = QValidator::Acceptable;
00349                   else
00350                     state = QValidator::Intermediate;
00351                 }
00352             }
00353         }
00354     }
00355 
00356   // Treat values ouside (min; max) range as Invalid
00357   // This check is enabled by assigning "strict_validity_check" dynamic property
00358   // with value "true" to the spin box instance.
00359   if ( state == QValidator::Intermediate ){
00360     bool isOk;
00361     double val = str.toDouble( &isOk );
00362     if ( isOk ){
00363       QVariant propVal = property( "strict_validity_check" );
00364       if ( propVal.isValid() && propVal.canConvert( QVariant::Bool ) && propVal.toBool() ){
00365         if ( val < minimum() || val > maximum() )
00366           state = QValidator::Invalid;
00367       }
00368     }
00369     else if ( myPrecision < 0 ){
00370       // Consider too large negative exponent as Invalid
00371       QChar e( locale().exponential() );
00372       int epos = str.indexOf( e, 0, Qt::CaseInsensitive );
00373       if ( epos != -1 ){
00374         epos++; // Skip exponential symbol itself
00375         QString exponent = str.right( str.length() - epos );
00376         int expValue = exponent.toInt( &isOk );
00377         if ( isOk && expValue < std::numeric_limits<double>::min_exponent10 )
00378           state = QValidator::Invalid;
00379       }
00380     }
00381   }
00382 
00383   return state;
00384 }
00385 
00390 void QtxDoubleSpinBox::onTextChanged( const QString& /*txt*/ )
00391 {
00392   myCleared = false;
00393 }