lib

KoUnitWidgets.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, Rob Buis(buis@kde.org)
00003    Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KoUnitWidgets.h"
00022 #include "KoUnitWidgets.moc"
00023 #include <kdebug.h>
00024 #include <kglobal.h>
00025 #include <klocale.h>
00026 #include <qpushbutton.h>
00027 #include <qlayout.h>
00028 
00029 
00030 // ----------------------------------------------------------------
00031 //                          Support classes
00032 
00033 
00034 KoUnitDoubleValidator::KoUnitDoubleValidator( KoUnitDoubleBase *base, QObject *parent, const char *name )
00035 : KDoubleValidator( parent, name ), m_base( base )
00036 {
00037 }
00038 
00039 QValidator::State
00040 KoUnitDoubleValidator::validate( QString &s, int &pos ) const
00041 {
00042 
00043     kdDebug(30004) << "KoUnitDoubleValidator::validate : " << s << " at " << pos << endl;
00044     QValidator::State result = Acceptable;
00045 
00046     QRegExp regexp ("([ a-zA-Z]+)$"); // Letters or spaces at end
00047     const int res = regexp.search( s );
00048 
00049     if ( res == -1 )
00050     {
00051         // Nothing like an unit? The user is probably editing the unit
00052         kdDebug(30004) << "Intermediate (no unit)" << endl;
00053         return Intermediate;
00054     }
00055 
00056     // ### TODO: are all the QString::stripWhiteSpace really necessary?
00057     const QString number ( s.left( res ).stripWhiteSpace() );
00058     const QString unitName ( regexp.cap( 1 ).stripWhiteSpace().lower() );
00059 
00060     kdDebug(30004) << "Split:" << number << ":" << unitName << ":" << endl;
00061 
00062     bool ok = false;
00063     const double value = m_base->toDouble( number, &ok );
00064     double newVal = 0.0;
00065     if( ok )
00066     {
00067         KoUnit::Unit unit = KoUnit::unit( unitName, &ok );
00068         if ( ok )
00069             newVal = KoUnit::fromUserValue( value, unit );
00070         else
00071         {
00072             // Probably the user is trying to edit the unit
00073             kdDebug(30004) << "Intermediate (unknown unit)" << endl;
00074             return Intermediate;
00075         }
00076     }
00077     else
00078     {
00079         kdWarning(30004) << "Not a number: " << number << endl;
00080         return Invalid;
00081     }
00082 
00083     newVal = KoUnit::ptToUnit( newVal, m_base->m_unit );
00084 
00085     s = m_base->getVisibleText( newVal );
00086 
00087     return result;
00088 }
00089 
00090 
00091 QString KoUnitDoubleBase::getVisibleText( double value ) const
00092 {
00093     const QString num ( QString( "%1%2").arg( KGlobal::locale()->formatNumber( value, m_precision ), KoUnit::unitName( m_unit ) ) );
00094     kdDebug(30004) << "getVisibleText: " << QString::number( value, 'f', 12 ) << " => " << num << endl;
00095     return num;
00096 }
00097 
00098 double KoUnitDoubleBase::toDouble( const QString& str, bool* ok ) const
00099 {
00100     QString str2( str );
00101     /* KLocale::readNumber wants the thousand separator exactly at 1000.
00102        But when editing, it might be anywhere. So we need to remove it. */
00103     const QString sep( KGlobal::locale()->thousandsSeparator() );
00104     if ( !sep.isEmpty() )
00105         str2.remove( sep );
00106     str2.remove( KoUnit::unitName( m_unit ) );
00107     const double dbl = KGlobal::locale()->readNumber( str2, ok );
00108     if ( ok )
00109       kdDebug(30004) << "toDouble:" << str << ": => :" << str2 << ": => " << QString::number( dbl, 'f', 12 ) << endl;
00110     else
00111         kdWarning(30004) << "toDouble error:" << str << ": => :" << str2 << ":" << endl;
00112     return dbl;
00113 }
00114 
00115 
00116 // ----------------------------------------------------------------
00117 //                          Widget classes
00118 
00119 
00120 KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( QWidget *parent, const char *name )
00121     : KDoubleSpinBox( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 )
00122     , m_lowerInPoints( -9999 )
00123     , m_upperInPoints( 9999 )
00124     , m_stepInPoints( 1 )
00125 {
00126     KDoubleSpinBox::setPrecision( 2 );
00127     m_validator = new KoUnitDoubleValidator( this, this );
00128     QSpinBox::setValidator( m_validator );
00129     setAcceptLocalizedNumbers( true );
00130     setUnit( KoUnit::U_PT );
00131 
00132     connect(this, SIGNAL(valueChanged( double )), SLOT(privateValueChanged()));
00133 }
00134 
00135 
00136 KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( QWidget *parent, 
00137                             double lower, double upper,
00138                             double step, 
00139                             double value, 
00140                             KoUnit::Unit unit, 
00141                             unsigned int precision, 
00142                             const char *name )
00143     : KDoubleSpinBox( lower, upper, step, value, precision, parent, name ),
00144       KoUnitDoubleBase( unit, precision ),
00145     m_lowerInPoints( lower ), m_upperInPoints( upper ), m_stepInPoints( step )
00146 {
00147     m_unit = KoUnit::U_PT;
00148     m_validator = new KoUnitDoubleValidator( this, this );
00149     QSpinBox::setValidator( m_validator );
00150     setAcceptLocalizedNumbers( true );
00151     setUnit( unit );
00152     changeValue( value );
00153     setLineStep( 0.5 );
00154 
00155     connect(this, SIGNAL(valueChanged( double )), SLOT(privateValueChanged()));
00156 }
00157 
00158 void
00159 KoUnitDoubleSpinBox::changeValue( double val )
00160 {
00161     KDoubleSpinBox::setValue( KoUnit::toUserValue( val, m_unit ) );
00162     // TODO: emit valueChanged ONLY if the value was out-of-bounds
00163     // This will allow the 'user' dialog to set a dirty bool and ensure
00164     // a proper value is getting saved.
00165 }
00166 
00167 void KoUnitDoubleSpinBox::privateValueChanged() {
00168     emit valueChangedPt( value () );
00169 }
00170 
00171 void
00172 KoUnitDoubleSpinBox::setUnit( KoUnit::Unit unit )
00173 {
00174     double oldvalue = KoUnit::fromUserValue( KDoubleSpinBox::value(), m_unit );
00175     KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, unit ) );
00176     KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, unit ) );
00177     KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, unit ) );
00178     KDoubleSpinBox::setValue( KoUnit::ptToUnit( oldvalue, unit ) );
00179     m_unit = unit;
00180     setSuffix( KoUnit::unitName( unit ).prepend( ' ' ) );
00181 }
00182 
00183 double KoUnitDoubleSpinBox::value( void ) const
00184 {
00185     return KoUnit::fromUserValue( KDoubleSpinBox::value(), m_unit );
00186 }
00187 
00188 void KoUnitDoubleSpinBox::setMinValue( double min )
00189 {
00190   m_lowerInPoints = min;
00191   KDoubleSpinBox::setMinValue( KoUnit::toUserValue( m_lowerInPoints, m_unit ) );
00192 }
00193 
00194 void KoUnitDoubleSpinBox::setMaxValue( double max )
00195 {
00196   m_upperInPoints = max;
00197   KDoubleSpinBox::setMaxValue( KoUnit::toUserValue( m_upperInPoints, m_unit ) );
00198 }
00199 
00200 void KoUnitDoubleSpinBox::setLineStep( double step )
00201 {
00202   m_stepInPoints = KoUnit::toUserValue(step, KoUnit::U_PT );
00203   KDoubleSpinBox::setLineStep( step );
00204 }
00205 
00206 void KoUnitDoubleSpinBox::setLineStepPt( double step )
00207 {
00208   m_stepInPoints = step;
00209   KDoubleSpinBox::setLineStep( KoUnit::toUserValue( m_stepInPoints, m_unit ) );
00210 }
00211 
00212 void KoUnitDoubleSpinBox::setMinMaxStep( double min, double max, double step )
00213 {
00214   setMinValue( min );
00215   setMaxValue( max );
00216   setLineStepPt( step );
00217 }
00218 
00219 // ----------------------------------------------------------------
00220 
00221 
00222 KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( QWidget *parent, const char *name )
00223     : KLineEdit( parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ), m_value( 0.0 ), m_lower( 0.0 ), m_upper( 9999.99 ),
00224     m_lowerInPoints( 0.0 ), m_upperInPoints( 9999.99 )
00225 {
00226     setAlignment( Qt::AlignRight );
00227     m_validator = new KoUnitDoubleValidator( this, this );
00228     setValidator( m_validator );
00229     setUnit( KoUnit::U_PT );
00230     changeValue(  KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) );
00231 }
00232 
00233 KoUnitDoubleLineEdit::KoUnitDoubleLineEdit( QWidget *parent, double lower, double upper, double value, KoUnit::Unit unit,
00234     unsigned int precision, const char *name )
00235     : KLineEdit( parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ),
00236     m_lowerInPoints( lower ), m_upperInPoints( upper )
00237 {
00238     setAlignment( Qt::AlignRight );
00239     m_validator = new KoUnitDoubleValidator( this, this );
00240     setValidator( m_validator );
00241     setUnit( unit );
00242     changeValue(  KoUnit::ptToUnit( value, unit ) );
00243 }
00244 
00245 void
00246 KoUnitDoubleLineEdit::changeValue( double value )
00247 {
00248     m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
00249     setText( getVisibleText( m_value ) );
00250 }
00251 
00252 void
00253 KoUnitDoubleLineEdit::setUnit( KoUnit::Unit unit )
00254 {
00255     KoUnit::Unit old = m_unit;
00256     m_unit = unit;
00257     m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit );
00258     m_upper = KoUnit::ptToUnit( m_upperInPoints, unit );
00259     changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) );
00260 }
00261 
00262 bool
00263 KoUnitDoubleLineEdit::eventFilter( QObject* o, QEvent* ev )
00264 {
00265 #if 0
00266     if( ev->type() == QEvent::FocusOut || ev->type() == QEvent::Leave || ev->type() == QEvent::Hide )
00267     {
00268         bool ok;
00269         double value = toDouble( text(), &ok );
00270         changeValue( value );
00271         return false;
00272     }
00273     else
00274 #endif
00275             return QLineEdit::eventFilter( o, ev );
00276 }
00277 
00278 double KoUnitDoubleLineEdit::value( void ) const
00279 {
00280     return KoUnit::fromUserValue( m_value, m_unit );
00281 }
00282 
00283 
00284 // ----------------------------------------------------------------
00285 
00286 
00287 KoUnitDoubleComboBox::KoUnitDoubleComboBox( QWidget *parent, const char *name )
00288      : KComboBox( true, parent, name ), KoUnitDoubleBase( KoUnit::U_PT, 2 ), m_value( 0.0 ), m_lower( 0.0 ), m_upper( 9999.99 ), m_lowerInPoints( 0.0 ), m_upperInPoints( 9999.99 )
00289 {
00290     lineEdit()->setAlignment( Qt::AlignRight );
00291     m_validator = new KoUnitDoubleValidator( this, this );
00292     lineEdit()->setValidator( m_validator );
00293     setUnit( KoUnit::U_PT );
00294     changeValue(  KoUnit::ptToUnit( 0.0, KoUnit::U_PT ) );
00295     connect( this, SIGNAL( activated( int ) ), this, SLOT( slotActivated( int ) ) );
00296 }
00297 
00298 KoUnitDoubleComboBox::KoUnitDoubleComboBox( QWidget *parent, double lower, double upper, double value, KoUnit::Unit unit,
00299      unsigned int precision, const char *name )
00300      : KComboBox( true, parent, name ), KoUnitDoubleBase( unit, precision ), m_value( value ), m_lower( lower ), m_upper( upper ),
00301      m_lowerInPoints( lower ), m_upperInPoints( upper )
00302 {
00303     lineEdit()->setAlignment( Qt::AlignRight );
00304     m_validator = new KoUnitDoubleValidator( this, this );
00305     lineEdit()->setValidator( m_validator );
00306     setUnit( unit );
00307     changeValue(  KoUnit::ptToUnit( value, unit ) );
00308     connect( this, SIGNAL( activated( int ) ), this, SLOT( slotActivated( int ) ) );
00309 }
00310 
00311 void
00312 KoUnitDoubleComboBox::changeValue( double value )
00313 {
00314     QString oldLabel = lineEdit()->text();
00315     updateValue( value );
00316     if( lineEdit()->text() != oldLabel )
00317         emit valueChanged( m_value );
00318 }
00319 
00320 void
00321 KoUnitDoubleComboBox::updateValue( double value )
00322 {
00323     m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
00324     lineEdit()->setText( getVisibleText( m_value ) );
00325 }
00326 
00327 void
00328 KoUnitDoubleComboBox::insertItem( double value, int index )
00329 {
00330     KComboBox::insertItem( getVisibleText( value ), index );
00331 }
00332 
00333 void
00334 KoUnitDoubleComboBox::slotActivated( int index )
00335 {
00336     double oldvalue = m_value;
00337     bool ok;
00338     double value = toDouble( text( index ), &ok );
00339     m_value = value < m_lower ? m_lower : ( value > m_upper ? m_upper : value );
00340     if( m_value != oldvalue )
00341         emit valueChanged( m_value );
00342 }
00343 
00344 void
00345 KoUnitDoubleComboBox::setUnit( KoUnit::Unit unit )
00346 {
00347     KoUnit::Unit old = m_unit;
00348     m_unit = unit;
00349     m_lower = KoUnit::ptToUnit( m_lowerInPoints, unit );
00350     m_upper = KoUnit::ptToUnit( m_upperInPoints, unit );
00351     changeValue( KoUnit::ptToUnit( KoUnit::fromUserValue( m_value, old ), unit ) );
00352 }
00353 
00354 bool
00355 KoUnitDoubleComboBox::eventFilter( QObject* o, QEvent* ev )
00356 {
00357 #if 0
00358     if( ev->type() == QEvent::FocusOut || ev->type() == QEvent::Leave || ev->type() == QEvent::Hide )
00359     {
00360         bool ok;
00361         double value = toDouble( lineEdit()->text(), &ok );
00362         changeValue( value );
00363         return false;
00364     }
00365     else
00366 #endif
00367             return QComboBox::eventFilter( o, ev );
00368 }
00369 
00370 double KoUnitDoubleComboBox::value( void ) const
00371 {
00372     return KoUnit::fromUserValue( m_value, m_unit );
00373 }
00374 
00375 
00376 // ----------------------------------------------------------------
00377 
00378 
00379 KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( QWidget *parent, const char *name )
00380     : QWidget( parent ), m_step( 1.0 )
00381 {
00382     QGridLayout *layout = new QGridLayout( this, 2, 3 );
00383     //layout->setMargin( 2 );
00384     QPushButton *up = new QPushButton( "+", this );
00385     //up->setFlat( true );
00386     up->setMaximumHeight( 15 );
00387     up->setMaximumWidth( 15 );
00388     layout->addWidget( up, 0, 0 );
00389     connect( up, SIGNAL( clicked() ), this, SLOT( slotUpClicked() ) );
00390 
00391     QPushButton *down = new QPushButton( "-", this );
00392     down->setMaximumHeight( 15 );
00393     down->setMaximumWidth( 15 );
00394     layout->addWidget( down, 1, 0 );
00395     connect( down, SIGNAL( clicked() ), this, SLOT( slotDownClicked() ) );
00396 
00397     m_combo = new KoUnitDoubleComboBox( this, KoUnit::ptToUnit( 0.0, KoUnit::U_PT ), KoUnit::ptToUnit( 9999.99, KoUnit::U_PT ), 0.0, KoUnit::U_PT, 2, name );
00398     connect( m_combo, SIGNAL( valueChanged( double ) ), this, SIGNAL( valueChanged( double ) ) );
00399     layout->addMultiCellWidget( m_combo, 0, 1, 2, 2 );
00400 }
00401 
00402 KoUnitDoubleSpinComboBox::KoUnitDoubleSpinComboBox( QWidget *parent, double lower, double upper, double step, double value,
00403                                                     KoUnit::Unit unit, unsigned int precision, const char *name )
00404     : QWidget( parent ), m_step( step )//, m_lowerInPoints( lower ), m_upperInPoints( upper )
00405 {
00406     QGridLayout *layout = new QGridLayout( this, 2, 3 );
00407     //layout->setMargin( 2 );
00408     QPushButton *up = new QPushButton( "+", this );
00409     //up->setFlat( true );
00410     up->setMaximumHeight( 15 );
00411     up->setMaximumWidth( 15 );
00412     layout->addWidget( up, 0, 0 );
00413     connect( up, SIGNAL( clicked() ), this, SLOT( slotUpClicked() ) );
00414 
00415     QPushButton *down = new QPushButton( "-", this );
00416     down->setMaximumHeight( 15 );
00417     down->setMaximumWidth( 15 );
00418     layout->addWidget( down, 1, 0 );
00419     connect( down, SIGNAL( clicked() ), this, SLOT( slotDownClicked() ) );
00420 
00421     m_combo = new KoUnitDoubleComboBox( this, KoUnit::ptToUnit( lower, unit ), KoUnit::ptToUnit( upper, unit ), value, unit, precision, name );
00422     connect( m_combo, SIGNAL( valueChanged( double ) ), this, SIGNAL( valueChanged( double ) ) );
00423     layout->addMultiCellWidget( m_combo, 0, 1, 2, 2 );
00424 }
00425 
00426 void
00427 KoUnitDoubleSpinComboBox::slotUpClicked()
00428 {
00429     m_combo->changeValue( m_combo->value() + m_step );
00430 }
00431 
00432 void
00433 KoUnitDoubleSpinComboBox::slotDownClicked()
00434 {
00435     m_combo->changeValue( m_combo->value() - m_step );
00436 }
00437 
00438 void
00439 KoUnitDoubleSpinComboBox::insertItem( double value, int index )
00440 {
00441     m_combo->insertItem( value, index );
00442 }
00443 
00444 void
00445 KoUnitDoubleSpinComboBox::updateValue( double value )
00446 {
00447     m_combo->updateValue( value );
00448 }
00449 
00450 double
00451 KoUnitDoubleSpinComboBox::value() const
00452 {
00453     return m_combo->value();
00454 }
00455 
KDE Home | KDE Accessibility Home | Description of Access Keys