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 connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
01003 }
01004
01005 KDoubleSpinBox::KDoubleSpinBox( double lower, double upper, double step,
01006 double value, int precision,
01007 QWidget * parent, const char * name )
01008 : QSpinBox( parent, name )
01009 {
01010 editor()->setAlignment( Qt::AlignRight );
01011 d = new Private();
01012 setRange( lower, upper, step, precision );
01013 setValue( value );
01014 connect( this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)) );
01015 }
01016
01017 KDoubleSpinBox::~KDoubleSpinBox() {
01018 delete d; d = 0;
01019 }
01020
01021 bool KDoubleSpinBox::acceptLocalizedNumbers() const {
01022 if ( !d->mValidator ) return true;
01023
01024 return d->mValidator->acceptLocalizedNumbers();
01025 }
01026
01027 void KDoubleSpinBox::setAcceptLocalizedNumbers( bool accept ) {
01028 if ( !d->mValidator ) updateValidator();
01029 d->mValidator->setAcceptLocalizedNumbers( accept );
01030 }
01031
01032 void KDoubleSpinBox::setRange( double lower, double upper, double step,
01033 int precision ) {
01034 lower = kMin(upper, lower);
01035 upper = kMax(upper, lower);
01036 setPrecision( precision, true );
01037 setMinValue( lower );
01038 setMaxValue( upper );
01039 setLineStep( step );
01040 }
01041
01042 int KDoubleSpinBox::precision() const {
01043 return d->mPrecision;
01044 }
01045
01046 void KDoubleSpinBox::setPrecision( int precision ) {
01047 setPrecision( precision, false );
01048 }
01049
01050 void KDoubleSpinBox::setPrecision( int precision, bool force ) {
01051 if ( precision < 1 ) return;
01052 if ( !force ) {
01053 int maxPrec = maxPrecision();
01054 if ( precision > maxPrec )
01055 precision = maxPrec;
01056 }
01057 d->mPrecision = precision;
01058 updateValidator();
01059 }
01060
01061 int KDoubleSpinBox::maxPrecision() const {
01062
01063
01064
01065
01066 double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
01067 if ( maxAbsValue == 0 ) return 6;
01068
01069 return int( floor( log10( double(INT_MAX) / maxAbsValue ) ) );
01070 }
01071
01072 double KDoubleSpinBox::value() const {
01073 return d->mapToDouble( base::value() );
01074 }
01075
01076 void KDoubleSpinBox::setValue( double value ) {
01077 if ( value == this->value() ) return;
01078 if ( value < minValue() )
01079 base::setValue( base::minValue() );
01080 else if ( value > maxValue() )
01081 base::setValue( base::maxValue() );
01082 else {
01083 bool ok = false;
01084 base::setValue( d->mapToInt( value, &ok ) );
01085 assert( ok );
01086 }
01087 }
01088
01089 double KDoubleSpinBox::minValue() const {
01090 return d->mapToDouble( base::minValue() );
01091 }
01092
01093 void KDoubleSpinBox::setMinValue( double value ) {
01094 bool ok = false;
01095 int min = d->mapToInt( value, &ok );
01096 if ( !ok ) return;
01097 base::setMinValue( min );
01098 updateValidator();
01099 }
01100
01101
01102 double KDoubleSpinBox::maxValue() const {
01103 return d->mapToDouble( base::maxValue() );
01104 }
01105
01106 void KDoubleSpinBox::setMaxValue( double value ) {
01107 bool ok = false;
01108 int max = d->mapToInt( value, &ok );
01109 if ( !ok ) return;
01110 base::setMaxValue( max );
01111 updateValidator();
01112 }
01113
01114 double KDoubleSpinBox::lineStep() const {
01115 return d->mapToDouble( base::lineStep() );
01116 }
01117
01118 void KDoubleSpinBox::setLineStep( double step ) {
01119 bool ok = false;
01120 if ( step > maxValue() - minValue() )
01121 base::setLineStep( 1 );
01122 else
01123 base::setLineStep( kMax( d->mapToInt( step, &ok ), 1 ) );
01124 }
01125
01126 QString KDoubleSpinBox::mapValueToText( int value ) {
01127 if ( acceptLocalizedNumbers() )
01128 return KGlobal::locale()
01129 ->formatNumber( d->mapToDouble( value ), d->mPrecision );
01130 else
01131 return QString().setNum( d->mapToDouble( value ), 'f', d->mPrecision );
01132 }
01133
01134 int KDoubleSpinBox::mapTextToValue( bool * ok ) {
01135 double value;
01136 if ( acceptLocalizedNumbers() )
01137 value = KGlobal::locale()->readNumber( cleanText(), ok );
01138 else
01139 value = cleanText().toDouble( ok );
01140 if ( !*ok ) return 0;
01141 if ( value > maxValue() )
01142 value = maxValue();
01143 else if ( value < minValue() )
01144 value = minValue();
01145 return d->mapToInt( value, ok );
01146 }
01147
01148 void KDoubleSpinBox::setValidator( const QValidator * ) {
01149
01150 }
01151
01152 void KDoubleSpinBox::slotValueChanged( int value ) {
01153 emit valueChanged( d->mapToDouble( value ) );
01154 }
01155
01156 void KDoubleSpinBox::updateValidator() {
01157 if ( !d->mValidator ) {
01158 d->mValidator = new KDoubleSpinBoxValidator( minValue(), maxValue(), precision(),
01159 this, "d->mValidator" );
01160 base::setValidator( d->mValidator );
01161 } else
01162 d->mValidator->setRange( minValue(), maxValue(), precision() );
01163 }
01164
01165 void KNumInput::virtual_hook( int, void* )
01166 { }
01167
01168 void KIntNumInput::virtual_hook( int id, void* data )
01169 { KNumInput::virtual_hook( id, data ); }
01170
01171 void KDoubleNumInput::virtual_hook( int id, void* data )
01172 { KNumInput::virtual_hook( id, data ); }
01173
01174 void KIntSpinBox::virtual_hook( int, void* )
01175 { }
01176
01177 void KDoubleSpinBox::virtual_hook( int, void* )
01178 { }
01179
01180 #include "knuminput.moc"