doublespinbox.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2004 by David Saxton                               *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "cnitem.h"
00012 #include "doublespinbox.h"
00013 
00014 #include <kdebug.h>
00015 #include <kglobal.h>
00016 #include <klocale.h>
00017 
00018 #include <qlineedit.h>
00019 #include <qregexp.h>
00020 #include <qtimer.h>
00021 
00022 #include <algorithm>
00023 #include <cmath>
00024 using namespace std;
00025 
00026 
00027 inline int roundDouble( double val )
00028 {
00029         return (val > 0) ? int(val+0.5) : int(val-0.5);
00030 }
00031 
00032 
00033 DoubleSpinBox::DoubleSpinBox( double lower, double upper, double minAbs, double value, const QString &unit, QWidget * parent )
00034         : QSpinBox( parent )
00035 {
00036         m_lastEmittedValue = value;
00037         m_unit = unit;
00038         m_minValue = lower;
00039         m_maxValue = upper;
00040         m_minAbsValue = minAbs;
00041         m_queuedSuffix = QString::null;
00042         
00043         editor()->setAlignment( Qt::AlignRight );
00044         
00045         connect( this, SIGNAL(valueChanged(int)), this, SLOT(checkIfChanged()) );
00046         QSpinBox::setMinValue( -(1<<30) );
00047         QSpinBox::setMaxValue( +(1<<30) );      
00048         setValue( value );
00049         
00050         setValidator( 0 );
00051 }
00052 
00053 
00054 DoubleSpinBox::~DoubleSpinBox()
00055 {
00056 }
00057 
00058 
00059 double DoubleSpinBox::value()
00060 {
00061         return getDisplayedNumber( 0 ) * getMult();
00062 }
00063 
00064 
00065 void DoubleSpinBox::setValue( double value )
00066 {
00067         if ( value > maxValue() )
00068                 value = maxValue();
00069         
00070         else if ( value < minValue() )
00071                 value = minValue();
00072         
00073         if ( std::abs(value) < m_minAbsValue*0.9999 )
00074                 value = 0.0;
00075         
00076         updateSuffix( value );
00077         
00078         QSpinBox::setValue( roundDouble( (value / Item::getMultiplier( value )) * 100 ) );
00079 }
00080 
00081 
00082 void DoubleSpinBox::setUnit( const QString & unit )
00083 {
00084         updateSuffix( value() );
00085         m_unit = unit;
00086 }
00087 
00088 
00089 void DoubleSpinBox::updateSuffix( double value )
00090 {
00091         m_queuedSuffix = " " + CNItem::getNumberMag( value ) + m_unit;
00092         
00093         // Set suffix to be empty if it is nothing but white space
00094         if ( m_queuedSuffix.stripWhiteSpace().isEmpty() )
00095                 m_queuedSuffix = "";
00096         
00097         QTimer::singleShot( 0, this, SLOT(setQueuedSuffix()) );
00098 }
00099 
00100 
00101 void DoubleSpinBox::setQueuedSuffix()
00102 {
00103         bool changed = false;
00104         if ( !m_queuedSuffix.isNull() && suffix() != m_queuedSuffix )
00105         {
00106                 setSuffix( m_queuedSuffix );
00107                 changed = true;
00108         }
00109         m_queuedSuffix = QString::null;
00110         
00111         if ( changed )
00112                 emit valueChanged( value() );
00113 }
00114 
00115 
00116 double DoubleSpinBox::getMult()
00117 {
00118         QString text = this->text().stripWhiteSpace();
00119         if ( !m_queuedSuffix.isNull() )
00120         {
00121                 QString nsSuffix = suffix().stripWhiteSpace();
00122                 
00123                 if ( nsSuffix.isEmpty() )
00124                         text.append( m_queuedSuffix );
00125                 else
00126                         text.replace( nsSuffix, m_queuedSuffix );
00127         }
00128         
00129         if ( text.length() == 0 )
00130                 return 1.0;
00131         
00132         if ( text.endsWith( m_unit, false ) )
00133                 text = text.remove( text.length() - m_unit.length(), m_unit.length() );
00134         
00135         text.stripWhiteSpace();
00136         
00137         QChar siExp = text[ text.length()-1 ];
00138         
00139         if ( siExp.isLetter() || siExp.isSymbol() ) 
00140                 return CNItem::getMultiplier((QString)siExp);
00141         
00142         else
00143                 return 1;
00144 }
00145 
00146 
00147 double DoubleSpinBox::getDisplayedNumber( bool * ok )
00148 {
00149         KLocale * locale = KGlobal::locale();
00150         
00151         // Fetch the characters that we don't want to discard
00152         const QString exclude = locale->decimalSymbol()
00153                         + locale->thousandsSeparator()
00154                         + locale->positiveSign()
00155                         + locale->negativeSign();
00156         
00157         QString number = cleanText().remove( QRegExp("[^"+exclude+"\\d]") );
00158         
00159         return locale->readNumber( number, ok );
00160 }
00161 
00162 
00163 int DoubleSpinBox::mapTextToValue( bool * ok )
00164 {
00165         (void)ok;
00166         
00167         double value = this->value();
00168         
00169         if ( value > maxValue() )
00170                 value = maxValue();
00171         
00172         else if ( value < minValue() )
00173                 value = minValue();
00174         
00175         if ( std::abs(value) < m_minAbsValue*0.9999 )
00176                 value = 0.0;
00177         
00178         updateSuffix( value );
00179         
00180         value /= Item::getMultiplier( value );
00181         
00182         // Precision of 2 extra digits
00183         return int( value * 100 );
00184 }
00185 
00186 
00187 QString DoubleSpinBox::mapValueToText( int v )
00188 {
00189         double val = double(v)/100.0;
00190         
00191         int leftDigits = (int)floor( log10( abs(val) ) ) + 1;
00192         if ( leftDigits < 0 )
00193                 leftDigits = 0;
00194         else if ( leftDigits > 3 )
00195                 leftDigits = 3;
00196         
00197         KLocale * locale = KGlobal::locale();
00198         return locale->formatNumber( val, 3-leftDigits );
00199 }
00200 
00201 
00202 void DoubleSpinBox::checkIfChanged()
00203 {
00204         double newValue = value();
00205         
00206         if ( m_lastEmittedValue == newValue )
00207                 return;
00208         
00209         m_lastEmittedValue = newValue;
00210         emit valueChanged( m_lastEmittedValue );
00211 }
00212 
00213 
00214 double DoubleSpinBox::roundToOneSF( double value )
00215 {
00216         if ( value == 0.0 )
00217                 return 0.0;
00218         
00219         value *= 1.000001;
00220         double tens = pow( 10.0, floor(log10( abs(value) )) );
00221         
00222         return int ( value / tens ) * tens;
00223 }
00224 
00225 
00226 void DoubleSpinBox::stepUp()
00227 {
00228         double value = roundToOneSF( this->value() );
00229         
00230         if ( value == 0 )
00231                 value = m_minAbsValue;
00232         
00233         else if ( value > 0 )
00234                 value += std::pow( 10., std::floor( std::log10(value) ) );
00235         
00236         else
00237         {
00238                 double sub = std::pow(10., std::floor( std::log10(std::abs(value))-1) );
00239                 value += std::pow( 10., std::floor( std::log10(std::abs(value)-sub) ) );
00240         }
00241         
00242         value *= 1.00001;
00243         
00244         if ( std::abs(value) < m_minAbsValue )
00245                 value = 0.;
00246         
00247         setValue( value );
00248 }
00249 
00250 
00251 void DoubleSpinBox::stepDown()
00252 {
00253         double value = roundToOneSF( this->value() );
00254         
00255         if ( value == 0 )
00256                 value = -m_minAbsValue;
00257         
00258         else if ( value > 0 )
00259         {
00260                 double sub = std::pow(10., std::floor( std::log10(value)-1) );
00261                 value -= std::pow( 10., std::floor( std::log10(value-sub) ) );
00262         }
00263         else
00264         {
00265                 double add = std::pow(10., std::floor( std::log10(std::abs(value))-1) );
00266                 value -= std::pow( 10., std::floor( std::log10(std::abs(value)+add) ) );
00267         }
00268         
00269         value *= 1.00001;
00270         
00271         if ( std::abs(value) < m_minAbsValue )
00272                 value = 0.;
00273         
00274         setValue( value );
00275 }
00276 
00277 #include "doublespinbox.moc"
00278 

Generated on Tue May 8 17:05:29 2007 for KTechLab by  doxygen 1.5.1