00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #include <config.h>
00032 #ifdef HAVE_LIMITS_H
00033 #include <limits.h>
00034 #endif
00035 #include <assert.h>
00036 #include <math.h>
00037 #include <algorithm>
00038 
00039 #include <qapplication.h>
00040 #include <qlabel.h>
00041 #include <qlineedit.h>
00042 #include <qsize.h>
00043 #include <qslider.h>
00044 #include <qspinbox.h>
00045 #include <qstyle.h>
00046 
00047 #include <kglobal.h>
00048 #include <klocale.h>
00049 #include <kdebug.h>
00050 
00051 #include "kdialog.h"
00052 #include "knumvalidator.h"
00053 #include "knuminput.h"
00054 
00055 static inline int calcDiffByTen( int x, int y ) {
00056     
00057     return ( x / 10 ) - ( y / 10 )  +  ( x % 10 - y % 10 ) / 10;
00058 }
00059 
00060 
00061 
00062 KNumInput::KNumInput(QWidget* parent, const char* name)
00063     : QWidget(parent, name)
00064 {
00065     init();
00066 }
00067 
00068 KNumInput::KNumInput(KNumInput* below, QWidget* parent, const char* name)
00069     : QWidget(parent, name)
00070 {
00071     init();
00072 
00073     if(below) {
00074         m_next = below->m_next;
00075         m_prev = below;
00076         below->m_next = this;
00077         if(m_next)
00078             m_next->m_prev = this;
00079     }
00080 }
00081 
00082 void KNumInput::init()
00083 {
00084     m_prev = m_next = 0;
00085     m_colw1 = m_colw2 = 0;
00086 
00087     m_label = 0;
00088     m_slider = 0;
00089     m_alignment = 0;
00090 }
00091 
00092 KNumInput::~KNumInput()
00093 {
00094     if(m_prev)
00095         m_prev->m_next = m_next;
00096 
00097     if(m_next)
00098         m_next->m_prev = m_prev;
00099 }
00100 
00101 void KNumInput::setLabel(const QString & label, int a)
00102 {
00103     if(label.isEmpty()) {
00104         delete m_label;
00105         m_label = 0;
00106         m_alignment = 0;
00107     }
00108     else {
00109         if (m_label) m_label->setText(label);
00110         else m_label = new QLabel(label, this, "KNumInput::QLabel");
00111         m_label->setAlignment((a & (~(AlignTop|AlignBottom|AlignVCenter)))
00112                               | AlignVCenter);
00113         
00114         if(!(a & (AlignTop|AlignBottom|AlignVCenter)))
00115            a |= AlignTop;
00116         m_alignment = a;
00117     }
00118 
00119     layout(true);
00120 }
00121 
00122 QString KNumInput::label() const
00123 {
00124     if (m_label) return m_label->text();
00125     return QString::null;
00126 }
00127 
00128 void KNumInput::layout(bool deep)
00129 {
00130     int w1 = m_colw1;
00131     int w2 = m_colw2;
00132 
00133     
00134     m_sizeLabel = (m_label ? m_label->sizeHint() : QSize(0,0));
00135 
00136     if(m_label && (m_alignment & AlignVCenter))
00137         m_colw1 = m_sizeLabel.width() + 4;
00138     else
00139         m_colw1 = 0;
00140 
00141     
00142     m_sizeSlider = (m_slider ? m_slider->sizeHint() : QSize(0, 0));
00143 
00144     doLayout();
00145 
00146     if(!deep) {
00147         m_colw1 = w1;
00148         m_colw2 = w2;
00149         return;
00150     }
00151 
00152     KNumInput* p = this;
00153     while(p) {
00154         p->doLayout();
00155         w1 = QMAX(w1, p->m_colw1);
00156         w2 = QMAX(w2, p->m_colw2);
00157         p = p->m_prev;
00158     }
00159 
00160     p = m_next;
00161     while(p) {
00162         p->doLayout();
00163         w1 = QMAX(w1, p->m_colw1);
00164         w2 = QMAX(w2, p->m_colw2);
00165         p = p->m_next;
00166     }
00167 
00168     p = this;
00169     while(p) {
00170         p->m_colw1 = w1;
00171         p->m_colw2 = w2;
00172         p = p->m_prev;
00173     }
00174 
00175     p = m_next;
00176     while(p) {
00177         p->m_colw1 = w1;
00178         p->m_colw2 = w2;
00179         p = p->m_next;
00180     }
00181 
00182 
00183 }
00184 
00185 QSizePolicy KNumInput::sizePolicy() const
00186 {
00187     return QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
00188 }
00189 
00190 QSize KNumInput::sizeHint() const
00191 {
00192     return minimumSizeHint();
00193 }
00194 
00195 void KNumInput::setSteps(int minor, int major)
00196 {
00197     if(m_slider)
00198         m_slider->setSteps( minor, major );
00199 }
00200 
00201 
00202 
00203 
00204 KIntSpinBox::KIntSpinBox(QWidget *parent, const char *name)
00205     : QSpinBox(0, 99, 1, parent, name)
00206 {
00207     editor()->setAlignment(AlignRight);
00208     val_base = 10;
00209     setValue(0);
00210 }
00211 
00212 KIntSpinBox::~KIntSpinBox()
00213 {
00214 }
00215 
00216 KIntSpinBox::KIntSpinBox(int lower, int upper, int step, int value, int base,
00217                          QWidget* parent, const char* name)
00218     : QSpinBox(lower, upper, step, parent, name)
00219 {
00220     editor()->setAlignment(AlignRight);
00221     val_base = base;
00222     setValue(value);
00223 }
00224 
00225 void KIntSpinBox::setBase(int base)
00226 {
00227     val_base = base;
00228 }
00229 
00230 
00231 int KIntSpinBox::base() const
00232 {
00233     return val_base;
00234 }
00235 
00236 QString KIntSpinBox::mapValueToText(int v)
00237 {
00238     return QString::number(v, val_base);
00239 }
00240 
00241 int KIntSpinBox::mapTextToValue(bool* ok)
00242 {
00243     return cleanText().toInt(ok, val_base);
00244 }
00245 
00246 void KIntSpinBox::setEditFocus(bool mark)
00247 {
00248     editor()->setFocus();
00249     if(mark)
00250         editor()->selectAll();
00251 }
00252 
00253 
00254 
00255 
00256 class KIntNumInput::KIntNumInputPrivate {
00257 public:
00258     int referencePoint;
00259     short blockRelative;
00260     KIntNumInputPrivate( int r )
00261     : referencePoint( r ),
00262       blockRelative( 0 ) {}
00263 };
00264 
00265 
00266 KIntNumInput::KIntNumInput(KNumInput* below, int val, QWidget* parent,
00267                            int _base, const char* name)
00268     : KNumInput(below, parent, name)
00269 {
00270     init(val, _base);
00271 }
00272 
00273 KIntNumInput::KIntNumInput(QWidget *parent, const char *name)
00274     : KNumInput(parent, name)
00275 {
00276     init(0, 10);
00277 }
00278 
00279 KIntNumInput::KIntNumInput(int val, QWidget *parent, int _base, const char *name)
00280     : KNumInput(parent, name)
00281 {
00282     init(val, _base);
00283 
00284 }
00285 
00286 void KIntNumInput::init(int val, int _base)
00287 {
00288     d = new KIntNumInputPrivate( val );
00289     m_spin = new KIntSpinBox(INT_MIN, INT_MAX, 1, val, _base, this, "KIntNumInput::KIntSpinBox");
00290     
00291     
00292     
00293     if (_base != 10)
00294         m_spin->setValidator(new KIntValidator(this, _base, "KNumInput::KIntValidtr"));
00295 
00296     connect(m_spin, SIGNAL(valueChanged(int)), SLOT(spinValueChanged(int)));
00297     connect(this, SIGNAL(valueChanged(int)),
00298         SLOT(slotEmitRelativeValueChanged(int)));
00299 
00300     setFocusProxy(m_spin);
00301     layout(true);
00302 }
00303 
00304 void KIntNumInput::setReferencePoint( int ref ) {
00305     
00306     ref = kMin( maxValue(), kMax( minValue(),  ref ) );
00307     d->referencePoint = ref;
00308 }
00309 
00310 int KIntNumInput::referencePoint() const {
00311     return d->referencePoint;
00312 }
00313 
00314 void KIntNumInput::spinValueChanged(int val)
00315 {
00316     if(m_slider)
00317         m_slider->setValue(val);
00318 
00319     emit valueChanged(val);
00320 }
00321 
00322 void KIntNumInput::slotEmitRelativeValueChanged( int value ) {
00323     if ( d->blockRelative || !d->referencePoint ) return;
00324     emit relativeValueChanged( double( value ) / double( d->referencePoint ) );
00325 }
00326 
00327 void KIntNumInput::setRange(int lower, int upper, int step, bool slider)
00328 {
00329     upper = kMax(upper, lower);
00330     lower = kMin(upper, lower);
00331     m_spin->setMinValue(lower);
00332     m_spin->setMaxValue(upper);
00333     m_spin->setLineStep(step);
00334 
00335     step = m_spin->lineStep(); 
00336 
00337     if(slider) {
00338     if (m_slider)
00339         m_slider->setRange(lower, upper);
00340     else {
00341         m_slider = new QSlider(lower, upper, step, m_spin->value(),
00342                    QSlider::Horizontal, this);
00343         m_slider->setTickmarks(QSlider::Below);
00344         connect(m_slider, SIGNAL(valueChanged(int)),
00345             m_spin, SLOT(setValue(int)));
00346     }
00347 
00348     
00349         int major = calcDiffByTen( upper, lower );
00350     if ( major==0 ) major = step; 
00351 
00352         m_slider->setSteps(step, major);
00353         m_slider->setTickInterval(major);
00354     }
00355     else {
00356         delete m_slider;
00357         m_slider = 0;
00358     }
00359 
00360     
00361     setReferencePoint( referencePoint() );
00362 
00363     layout(true);
00364 }
00365 
00366 void KIntNumInput::setMinValue(int min)
00367 {
00368     setRange(min, m_spin->maxValue(), m_spin->lineStep(), m_slider);
00369 }
00370 
00371 int KIntNumInput::minValue() const
00372 {
00373     return m_spin->minValue();
00374 }
00375 
00376 void KIntNumInput::setMaxValue(int max)
00377 {
00378     setRange(m_spin->minValue(), max, m_spin->lineStep(), m_slider);
00379 }
00380 
00381 int KIntNumInput::maxValue() const
00382 {
00383     return m_spin->maxValue();
00384 }
00385 
00386 void KIntNumInput::setSuffix(const QString &suffix)
00387 {
00388     m_spin->setSuffix(suffix);
00389 
00390     layout(true);
00391 }
00392 
00393 QString KIntNumInput::suffix() const
00394 {
00395     return m_spin->suffix();
00396 }
00397 
00398 void KIntNumInput::setPrefix(const QString &prefix)
00399 {
00400     m_spin->setPrefix(prefix);
00401 
00402     layout(true);
00403 }
00404 
00405 QString KIntNumInput::prefix() const
00406 {
00407     return m_spin->prefix();
00408 }
00409 
00410 void KIntNumInput::setEditFocus(bool mark)
00411 {
00412     m_spin->setEditFocus(mark);
00413 }
00414 
00415 QSize KIntNumInput::minimumSizeHint() const
00416 {
00417     constPolish();
00418 
00419     int w;
00420     int h;
00421 
00422     h = 2 + QMAX(m_sizeSpin.height(), m_sizeSlider.height());
00423 
00424     
00425     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
00426         h += 4 + m_sizeLabel.height();
00427     else
00428         
00429         h = QMAX(h, m_sizeLabel.height() + 2);
00430 
00431     w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
00432     w += m_colw1 + m_colw2;
00433 
00434     if(m_alignment & (AlignTop|AlignBottom))
00435         w = QMAX(w, m_sizeLabel.width() + 4);
00436 
00437     return QSize(w, h);
00438 }
00439 
00440 void KIntNumInput::doLayout()
00441 {
00442     m_sizeSpin = m_spin->sizeHint();
00443     m_colw2 = m_sizeSpin.width();
00444 
00445     if (m_label)
00446         m_label->setBuddy(m_spin);
00447 }
00448 
00449 void KIntNumInput::resizeEvent(QResizeEvent* e)
00450 {
00451     int w = m_colw1;
00452     int h = 0;
00453 
00454     if(m_label && (m_alignment & AlignTop)) {
00455         m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
00456         h += m_sizeLabel.height() + KDialog::spacingHint();
00457     }
00458 
00459     if(m_label && (m_alignment & AlignVCenter))
00460         m_label->setGeometry(0, 0, w, m_sizeSpin.height());
00461 
00462     if (qApp->reverseLayout())
00463     {
00464         m_spin->setGeometry(w, h, m_slider ? m_colw2 : QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
00465         w += m_colw2 + 8;
00466 
00467         if(m_slider)
00468             m_slider->setGeometry(w, h, e->size().width() - w, m_sizeSpin.height());
00469     }
00470     else if(m_slider) {
00471         m_slider->setGeometry(w, h, e->size().width() - (w + m_colw2 + KDialog::spacingHint()), m_sizeSpin.height());
00472         m_spin->setGeometry(w + m_slider->size().width() + KDialog::spacingHint(), h, m_colw2, m_sizeSpin.height());
00473     }
00474     else {
00475         m_spin->setGeometry(w, h, QMAX(m_colw2, e->size().width() - w), m_sizeSpin.height());
00476     }
00477 
00478     h += m_sizeSpin.height() + 2;
00479 
00480     if(m_label && (m_alignment & AlignBottom))
00481         m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
00482 }
00483 
00484 KIntNumInput::~KIntNumInput()
00485 {
00486     delete d;
00487 }
00488 
00489 void KIntNumInput::setValue(int val)
00490 {
00491     m_spin->setValue(val);
00492     
00493 }
00494 
00495 void KIntNumInput::setRelativeValue( double r ) {
00496     if ( !d->referencePoint ) return;
00497     ++d->blockRelative;
00498     setValue( int( d->referencePoint * r + 0.5 ) );
00499     --d->blockRelative;
00500 }
00501 
00502 double KIntNumInput::relativeValue() const {
00503     if ( !d->referencePoint ) return 0;
00504     return double( value() ) / double ( d->referencePoint );
00505 }
00506 
00507 int  KIntNumInput::value() const
00508 {
00509     return m_spin->value();
00510 }
00511 
00512 void KIntNumInput::setSpecialValueText(const QString& text)
00513 {
00514     m_spin->setSpecialValueText(text);
00515     layout(true);
00516 }
00517 
00518 QString KIntNumInput::specialValueText() const
00519 {
00520     return m_spin->specialValueText();
00521 }
00522 
00523 void KIntNumInput::setLabel(const QString & label, int a)
00524 {
00525     KNumInput::setLabel(label, a);
00526 
00527     if(m_label)
00528         m_label->setBuddy(m_spin);
00529 }
00530 
00531 
00532 
00533 class KDoubleNumInput::KDoubleNumInputPrivate {
00534 public:
00535     KDoubleNumInputPrivate( double r )
00536     : spin( 0 ),
00537       referencePoint( r ),
00538       blockRelative ( 0 ) {}
00539     KDoubleSpinBox * spin;
00540     double referencePoint;
00541     short blockRelative;
00542 };
00543 
00544 KDoubleNumInput::KDoubleNumInput(QWidget *parent, const char *name)
00545     : KNumInput(parent, name)
00546 {
00547     init(0.0, 0.0, 9999.0, 0.01, 2);
00548 }
00549 
00550 KDoubleNumInput::KDoubleNumInput(double lower, double upper, double value,
00551                  double step, int precision, QWidget* parent,
00552                  const char *name)
00553     : KNumInput(parent, name)
00554 {
00555     init(value, lower, upper, step, precision);
00556 }
00557 
00558 KDoubleNumInput::KDoubleNumInput(KNumInput *below,
00559                  double lower, double upper, double value,
00560                  double step, int precision, QWidget* parent,
00561                  const char *name)
00562     : KNumInput(below, parent, name)
00563 {
00564     init(value, lower, upper, step, precision);
00565 }
00566 
00567 KDoubleNumInput::KDoubleNumInput(double value, QWidget *parent, const char *name)
00568     : KNumInput(parent, name)
00569 {
00570     init(value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
00571 }
00572 
00573 KDoubleNumInput::KDoubleNumInput(KNumInput* below, double value, QWidget* parent,
00574                                  const char* name)
00575     : KNumInput(below, parent, name)
00576 {
00577     init( value, kMin(0.0, value), kMax(0.0, value), 0.01, 2 );
00578 }
00579 
00580 KDoubleNumInput::~KDoubleNumInput()
00581 {
00582     delete d;
00583 }
00584 
00585 
00586 
00587 bool KDoubleNumInput::eventFilter( QObject * o, QEvent * e ) {
00588     return KNumInput::eventFilter( o, e );
00589 }
00590 
00591 void KDoubleNumInput::resetEditBox() {
00592 
00593 }
00594 
00595 
00596 
00597 
00598 
00599 void KDoubleNumInput::init(double value, double lower, double upper,
00600                double step, int precision )
00601 {
00602     
00603     edit = 0;
00604     m_range = true;
00605     m_value = 0.0;
00606     m_precision = 2;
00607     
00608 
00609     d = new KDoubleNumInputPrivate( value );
00610 
00611     d->spin = new KDoubleSpinBox( lower, upper, step, value, precision,
00612                   this, "KDoubleNumInput::d->spin" );
00613     setFocusProxy(d->spin);
00614     connect( d->spin, SIGNAL(valueChanged(double)),
00615          this, SIGNAL(valueChanged(double)) );
00616     connect( this, SIGNAL(valueChanged(double)),
00617          this, SLOT(slotEmitRelativeValueChanged(double)) );
00618 
00619     updateLegacyMembers();
00620 
00621     layout(true);
00622 }
00623 
00624 void KDoubleNumInput::updateLegacyMembers() {
00625     
00626     
00627     m_lower = minValue();
00628     m_upper = maxValue();
00629     m_step = d->spin->lineStep();
00630     m_specialvalue = specialValueText();
00631 }
00632 
00633 
00634 double KDoubleNumInput::mapSliderToSpin( int val ) const
00635 {
00636     
00637     double spinmin = d->spin->minValue();
00638     double spinmax = d->spin->maxValue();
00639     double slidemin = m_slider->minValue(); 
00640     double slidemax = m_slider->maxValue(); 
00641     double rel = ( double(val) - slidemin ) / ( slidemax - slidemin );
00642     return spinmin + rel * ( spinmax - spinmin );
00643 }
00644 
00645 void KDoubleNumInput::sliderMoved(int val)
00646 {
00647     d->spin->setValue( mapSliderToSpin( val ) );
00648 }
00649 
00650 void KDoubleNumInput::slotEmitRelativeValueChanged( double value )
00651 {
00652     if ( !d->referencePoint ) return;
00653     emit relativeValueChanged( value / d->referencePoint );
00654 }
00655 
00656 QSize KDoubleNumInput::minimumSizeHint() const
00657 {
00658     constPolish();
00659 
00660     int w;
00661     int h;
00662 
00663     h = 2 + QMAX(m_sizeEdit.height(), m_sizeSlider.height());
00664 
00665     
00666     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
00667         h += 4 + m_sizeLabel.height();
00668     else
00669         
00670     h = QMAX(h, m_sizeLabel.height() + 2);
00671 
00672     w = m_slider ? m_slider->sizeHint().width() + 8 : 0;
00673     w += m_colw1 + m_colw2;
00674 
00675     if(m_alignment & (AlignTop|AlignBottom))
00676         w = QMAX(w, m_sizeLabel.width() + 4);
00677 
00678     return QSize(w, h);
00679 }
00680 
00681 void KDoubleNumInput::resizeEvent(QResizeEvent* e)
00682 {
00683     int w = m_colw1;
00684     int h = 0;
00685 
00686     if(m_label && (m_alignment & AlignTop)) {
00687         m_label->setGeometry(0, 0, e->size().width(), m_sizeLabel.height());
00688         h += m_sizeLabel.height() + 4;
00689     }
00690 
00691     if(m_label && (m_alignment & AlignVCenter))
00692         m_label->setGeometry(0, 0, w, m_sizeEdit.height());
00693 
00694     if (qApp->reverseLayout())
00695     {
00696         d->spin->setGeometry(w, h, m_slider ? m_colw2
00697                                             : e->size().width() - w, m_sizeEdit.height());
00698         w += m_colw2 + KDialog::spacingHint();
00699 
00700         if(m_slider)
00701             m_slider->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
00702     }
00703     else if(m_slider) {
00704         m_slider->setGeometry(w, h, e->size().width() -
00705                                     (m_colw1 + m_colw2 + KDialog::spacingHint()),
00706                               m_sizeEdit.height());
00707         d->spin->setGeometry(w + m_slider->width() + KDialog::spacingHint(), h,
00708                              m_colw2, m_sizeEdit.height());
00709     }
00710     else {
00711         d->spin->setGeometry(w, h, e->size().width() - w, m_sizeEdit.height());
00712     }
00713 
00714     h += m_sizeEdit.height() + 2;
00715 
00716     if(m_label && (m_alignment & AlignBottom))
00717         m_label->setGeometry(0, h, m_sizeLabel.width(), m_sizeLabel.height());
00718 }
00719 
00720 void KDoubleNumInput::doLayout()
00721 {
00722     m_sizeEdit = d->spin->sizeHint();
00723     m_colw2 = m_sizeEdit.width();
00724 }
00725 
00726 void KDoubleNumInput::setValue(double val)
00727 {
00728     d->spin->setValue( val );
00729 }
00730 
00731 void KDoubleNumInput::setRelativeValue( double r )
00732 {
00733     if ( !d->referencePoint ) return;
00734     ++d->blockRelative;
00735     setValue( r * d->referencePoint );
00736     --d->blockRelative;
00737 }
00738 
00739 void KDoubleNumInput::setReferencePoint( double ref )
00740 {
00741     
00742     ref = kMin( maxValue(), kMax( minValue(), ref ) );
00743     d->referencePoint = ref;
00744 }
00745 
00746 void KDoubleNumInput::setRange(double lower, double upper, double step,
00747                                                            bool slider)
00748 {
00749     if( m_slider ) {
00750     
00751     QSpinBox * spin = d->spin;
00752     disconnect(spin, SIGNAL(valueChanged(int)),
00753         m_slider, SLOT(setValue(int)) );
00754     }
00755     d->spin->setRange( lower, upper, step, d->spin->precision() );
00756 
00757     if(slider) {
00758     
00759     QSpinBox * spin = d->spin;
00760         int slmax = spin->maxValue();
00761     int slmin = spin->minValue();
00762         int slvalue = spin->value();
00763     int slstep = spin->lineStep();
00764         if (m_slider) {
00765             m_slider->setRange(slmin, slmax);
00766         m_slider->setLineStep(slstep);
00767             m_slider->setValue(slvalue);
00768         } else {
00769             m_slider = new QSlider(slmin, slmax, slstep, slvalue,
00770                                    QSlider::Horizontal, this);
00771             m_slider->setTickmarks(QSlider::Below);
00772         
00773             connect(m_slider, SIGNAL(valueChanged(int)),
00774                     SLOT(sliderMoved(int)) );
00775         }
00776     connect(spin, SIGNAL(valueChanged(int)),
00777             m_slider, SLOT(setValue(int)) );
00778     
00779     int major = calcDiffByTen( slmax, slmin );
00780     if ( !major ) major = slstep; 
00781         m_slider->setTickInterval(major);
00782     } else {
00783         delete m_slider;
00784         m_slider = 0;
00785     }
00786 
00787     setReferencePoint( referencePoint() );
00788 
00789     layout(true);
00790     updateLegacyMembers();
00791 }
00792 
00793 void KDoubleNumInput::setMinValue(double min)
00794 {
00795     setRange(min, maxValue(), d->spin->lineStep(), m_slider);
00796 }
00797 
00798 double KDoubleNumInput::minValue() const
00799 {
00800     return d->spin->minValue();
00801 }
00802 
00803 void KDoubleNumInput::setMaxValue(double max)
00804 {
00805     setRange(minValue(), max, d->spin->lineStep(), m_slider);
00806 }
00807 
00808 double KDoubleNumInput::maxValue() const
00809 {
00810     return d->spin->maxValue();
00811 }
00812 
00813 double  KDoubleNumInput::value() const
00814 {
00815     return d->spin->value();
00816 }
00817 
00818 double KDoubleNumInput::relativeValue() const
00819 {
00820     if ( !d->referencePoint ) return 0;
00821     return value() / d->referencePoint;
00822 }
00823 
00824 double KDoubleNumInput::referencePoint() const
00825 {
00826     return d->referencePoint;
00827 }
00828 
00829 QString KDoubleNumInput::suffix() const
00830 {
00831     return d->spin->suffix();
00832 }
00833 
00834 QString KDoubleNumInput::prefix() const
00835 {
00836     return d->spin->prefix();
00837 }
00838 
00839 void KDoubleNumInput::setSuffix(const QString &suffix)
00840 {
00841     d->spin->setSuffix( suffix );
00842 
00843     layout(true);
00844 }
00845 
00846 void KDoubleNumInput::setPrefix(const QString &prefix)
00847 {
00848     d->spin->setPrefix( prefix );
00849 
00850     layout(true);
00851 }
00852 
00853 void KDoubleNumInput::setPrecision(int precision)
00854 {
00855     d->spin->setPrecision( precision );
00856 
00857     layout(true);
00858 }
00859 
00860 int KDoubleNumInput::precision() const
00861 {
00862     return d->spin->precision();
00863 }
00864 
00865 void KDoubleNumInput::setSpecialValueText(const QString& text)
00866 {
00867     d->spin->setSpecialValueText( text );
00868 
00869     layout(true);
00870     updateLegacyMembers();
00871 }
00872 
00873 void KDoubleNumInput::setLabel(const QString & label, int a)
00874 {
00875     KNumInput::setLabel(label, a);
00876 
00877     if(m_label)
00878         m_label->setBuddy(d->spin);
00879 
00880 }
00881 
00882 
00883 
00884 
00885 class KDoubleSpinBoxValidator : public KDoubleValidator
00886 {
00887 public:
00888     KDoubleSpinBoxValidator( double bottom, double top, int decimals, KDoubleSpinBox* sb, const char *name )
00889         : KDoubleValidator( bottom, top, decimals, sb, name ), spinBox( sb ) { }
00890 
00891     virtual State validate( QString& str, int& pos ) const;
00892 
00893 private:
00894     KDoubleSpinBox *spinBox;
00895 };
00896 
00897 QValidator::State KDoubleSpinBoxValidator::validate( QString& str, int& pos ) const
00898 {
00899     QString pref = spinBox->prefix();
00900     QString suff = spinBox->suffix();
00901     QString suffStriped = suff.stripWhiteSpace();
00902     uint overhead = pref.length() + suff.length();
00903     State state = Invalid;
00904 
00905     if ( overhead == 0 ) {
00906         state = KDoubleValidator::validate( str, pos );
00907     } else {
00908         bool stripedVersion = false;
00909         if ( str.length() >= overhead && str.startsWith(pref)
00910              && (str.endsWith(suff)
00911                  || (stripedVersion = str.endsWith(suffStriped))) ) {
00912             if ( stripedVersion )
00913                 overhead = pref.length() + suffStriped.length();
00914             QString core = str.mid( pref.length(), str.length() - overhead );
00915             int corePos = pos - pref.length();
00916             state = KDoubleValidator::validate( core, corePos );
00917             pos = corePos + pref.length();
00918             str.replace( pref.length(), str.length() - overhead, core );
00919         } else {
00920             state = KDoubleValidator::validate( str, pos );
00921             if ( state == Invalid ) {
00922                 
00923                 QString special = spinBox->specialValueText().stripWhiteSpace();
00924                 QString candidate = str.stripWhiteSpace();
00925 
00926                 if ( special.startsWith(candidate) ) {
00927                     if ( candidate.length() == special.length() ) {
00928                         state = Acceptable;
00929                     } else {
00930                         state = Intermediate;
00931                     }
00932                 }
00933             }
00934         }
00935     }
00936     return state;
00937 }
00938 
00939 
00940 
00941 
00942 
00943 
00944 
00945 
00946 
00947 
00948 
00949 class KDoubleSpinBox::Private {
00950 public:
00951   Private( int precision=1 )
00952     : mPrecision( precision ),
00953       mValidator( 0 )
00954   {
00955   }
00956 
00957   int factor() const {
00958     int f = 1;
00959     for ( int i = 0 ; i < mPrecision ; ++i ) f *= 10;
00960     return f;
00961   }
00962 
00963   double basicStep() const {
00964     return 1.0/double(factor());
00965   }
00966 
00967   int mapToInt( double value, bool * ok ) const {
00968     assert( ok );
00969     const double f = factor();
00970     if ( value > double(INT_MAX) / f ) {
00971       kdWarning() << "KDoubleSpinBox: can't represent value " << value
00972           << "in terms of fixed-point numbers with precision "
00973           << mPrecision << endl;
00974       *ok = false;
00975       return INT_MAX;
00976     } else if ( value < double(INT_MIN) / f ) {
00977       kdWarning() << "KDoubleSpinBox: can't represent value " << value
00978           << "in terms of fixed-point numbers with precision "
00979           << mPrecision << endl;
00980       *ok = false;
00981       return INT_MIN;
00982     } else {
00983       *ok = true;
00984       return int( value * f + ( value < 0 ? -0.5 : 0.5 ) );
00985     }
00986   }
00987 
00988   double mapToDouble( int value ) const {
00989     return double(value) * basicStep();
00990   }
00991 
00992   int mPrecision;
00993   KDoubleSpinBoxValidator * mValidator;
00994 };
00995 
00996 KDoubleSpinBox::KDoubleSpinBox( QWidget * parent, const char * name )
00997   : QSpinBox( parent, name )
00998 {
00999   editor()->setAlignment( Qt::AlignRight );
01000   d = new Private();
01001   updateValidator();
01002 }
01003 
01004 KDoubleSpinBox::KDoubleSpinBox( double lower, double upper, double step,
01005                 double value, int precision,
01006                 QWidget * parent, const char * name )
01007   : QSpinBox( parent, name )
01008 {
01009   editor()->setAlignment( Qt::AlignRight );
01010   d = new Private();
01011   setRange( lower, upper, step, precision );
01012   setValue( value );
01013   connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
01014 }
01015 
01016 KDoubleSpinBox::~KDoubleSpinBox() {
01017   delete d; d = 0;
01018 }
01019 
01020 bool KDoubleSpinBox::acceptLocalizedNumbers() const {
01021   if ( !d->mValidator ) return true; 
01022                                      
01023   return d->mValidator->acceptLocalizedNumbers();
01024 }
01025 
01026 void KDoubleSpinBox::setAcceptLocalizedNumbers( bool accept ) {
01027   if ( !d->mValidator ) updateValidator();
01028   d->mValidator->setAcceptLocalizedNumbers( accept );
01029 }
01030 
01031 void KDoubleSpinBox::setRange( double lower, double upper, double step,
01032                    int precision ) {
01033   lower = kMin(upper, lower);
01034   upper = kMax(upper, lower);
01035   setPrecision( precision, true ); 
01036   setMinValue( lower );            
01037   setMaxValue( upper );            
01038   setLineStep( step );             
01039 }
01040 
01041 int KDoubleSpinBox::precision() const {
01042   return d->mPrecision;
01043 }
01044 
01045 void KDoubleSpinBox::setPrecision( int precision ) {
01046     setPrecision( precision, false );
01047 }
01048 
01049 void KDoubleSpinBox::setPrecision( int precision, bool force ) {
01050   if ( precision < 1 ) return;
01051   if ( !force ) {
01052     int maxPrec = maxPrecision();
01053     if ( precision > maxPrec )
01054       precision = maxPrec;
01055   }
01056   d->mPrecision = precision;
01057   updateValidator();
01058 }
01059 
01060 int KDoubleSpinBox::maxPrecision() const {
01061     
01062     
01063     
01064     
01065     double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
01066     if ( maxAbsValue == 0 ) return 6; 
01067 
01068     return int( floor( log10( double(INT_MAX) / maxAbsValue ) ) );
01069 }
01070 
01071 double KDoubleSpinBox::value() const {
01072   return d->mapToDouble( base::value() );
01073 }
01074 
01075 void KDoubleSpinBox::setValue( double value ) {
01076     if ( value == this->value() ) return;
01077     if ( value < minValue() )
01078     base::setValue( base::minValue() );
01079     else if ( value > maxValue() )
01080     base::setValue( base::maxValue() );
01081     else {
01082     bool ok = false;
01083     base::setValue( d->mapToInt( value, &ok ) );
01084     assert( ok );
01085     }
01086 }
01087 
01088 double KDoubleSpinBox::minValue() const {
01089   return d->mapToDouble( base::minValue() );
01090 }
01091 
01092 void KDoubleSpinBox::setMinValue( double value ) {
01093   bool ok = false;
01094   int min = d->mapToInt( value, &ok );
01095   if ( !ok ) return;
01096   base::setMinValue( min );
01097   updateValidator();
01098 }
01099 
01100 
01101 double KDoubleSpinBox::maxValue() const {
01102   return d->mapToDouble( base::maxValue() );
01103 }
01104 
01105 void KDoubleSpinBox::setMaxValue( double value ) {
01106   bool ok = false;
01107   int max = d->mapToInt( value, &ok );
01108   if ( !ok ) return;
01109   base::setMaxValue( max );
01110   updateValidator();
01111 }
01112 
01113 double KDoubleSpinBox::lineStep() const {
01114   return d->mapToDouble( base::lineStep() );
01115 }
01116 
01117 void KDoubleSpinBox::setLineStep( double step ) {
01118   bool ok = false;
01119   if ( step > maxValue() - minValue() )
01120     base::setLineStep( 1 );
01121   else
01122     base::setLineStep( kMax( d->mapToInt( step, &ok ), 1 ) );
01123 }
01124 
01125 QString KDoubleSpinBox::mapValueToText( int value ) {
01126   if ( acceptLocalizedNumbers() )
01127     return KGlobal::locale()
01128       ->formatNumber( d->mapToDouble( value ), d->mPrecision );
01129   else
01130     return QString().setNum( d->mapToDouble( value ), 'f', d->mPrecision );
01131 }
01132 
01133 int KDoubleSpinBox::mapTextToValue( bool * ok ) {
01134   double value;
01135   if ( acceptLocalizedNumbers() )
01136     value = KGlobal::locale()->readNumber( cleanText(), ok );
01137   else
01138     value = cleanText().toDouble( ok );
01139   if ( !*ok ) return 0;
01140   if ( value > maxValue() )
01141     value = maxValue();
01142   else if ( value < minValue() )
01143     value = minValue();
01144   return d->mapToInt( value, ok );
01145 }
01146 
01147 void KDoubleSpinBox::setValidator( const QValidator * ) {
01148   
01149 }
01150 
01151 void KDoubleSpinBox::slotValueChanged( int value ) {
01152   emit valueChanged( d->mapToDouble( value ) );
01153 }
01154 
01155 void KDoubleSpinBox::updateValidator() {
01156   if ( !d->mValidator ) {
01157     d->mValidator =  new KDoubleSpinBoxValidator( minValue(), maxValue(), precision(),
01158                        this, "d->mValidator" );
01159     base::setValidator( d->mValidator );
01160   } else
01161     d->mValidator->setRange( minValue(), maxValue(), precision() );
01162 }
01163 
01164 void KNumInput::virtual_hook( int, void* )
01165 {  }
01166 
01167 void KIntNumInput::virtual_hook( int id, void* data )
01168 { KNumInput::virtual_hook( id, data ); }
01169 
01170 void KDoubleNumInput::virtual_hook( int id, void* data )
01171 { KNumInput::virtual_hook( id, data ); }
01172 
01173 void KIntSpinBox::virtual_hook( int, void* )
01174 {  }
01175 
01176 void KDoubleSpinBox::virtual_hook( int, void* )
01177 {  }
01178 
01179 #include "knuminput.moc"