• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

knuminput.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 /*
00003  * knuminput.cpp
00004  *
00005  * Initial implementation:
00006  *     Copyright (c) 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
00007  * Rewritten and maintained by:
00008  *     Copyright (c) 2000 Dirk A. Mueller <mueller@kde.org>
00009  * KDoubleSpinBox:
00010  *     Copyright (c) 2002 Marc Mutz <mutz@kde.org>
00011  *
00012  *  Requires the Qt widget libraries, available at no cost at
00013  *  http://www.troll.no/
00014  *
00015  *  This library is free software; you can redistribute it and/or
00016  *  modify it under the terms of the GNU Library General Public
00017  *  License as published by the Free Software Foundation; either
00018  *  version 2 of the License, or (at your option) any later version.
00019  *
00020  *  This library is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00023  *  Library General Public License for more details.
00024  *
00025  *  You should have received a copy of the GNU Library General Public License
00026  *  along with this library; see the file COPYING.LIB.  If not, write to
00027  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00028  *  Boston, MA 02110-1301, USA.
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     // calculate ( x - y ) / 10 without overflowing ints:
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         // if no vertical alignment set, use Top alignment
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     // label sizeHint
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     // slider sizeHint
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 //    kdDebug() << "w1 " << w1 << " w2 " << w2 << endl;
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     // the KIntValidator is broken beyond believe for
00291     // spinboxes which have suffix or prefix texts, so
00292     // better don't use it unless absolutely necessary
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     // clip to valid range:
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(); // maybe QRangeControl didn't like out 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     // calculate (upper-lower)/10 without overflowing int's:
00349         int major = calcDiffByTen( upper, lower );
00350     if ( major==0 ) major = step; // #### workaround Qt bug in 2.1-beta4
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     // check that reference point is still inside valid range:
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     // if in extra row, then count it here
00425     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
00426         h += 4 + m_sizeLabel.height();
00427     else
00428         // label is in the same row as the other widgets
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     // slider value is changed by spinValueChanged
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 // ### remove when BIC changes are allowed again:
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 // ### end stuff to remove when BIC changes are allowed again
00596 
00597 
00598 
00599 void KDoubleNumInput::init(double value, double lower, double upper,
00600                double step, int precision )
00601 {
00602     // ### init no longer used members:
00603     edit = 0;
00604     m_range = true;
00605     m_value = 0.0;
00606     m_precision = 2;
00607     // ### end
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     // ### update legacy members that are either not private or for
00626     // which an inlined getter exists:
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     // map [slidemin,slidemax] to [spinmin,spinmax]
00637     double spinmin = d->spin->minValue();
00638     double spinmax = d->spin->maxValue();
00639     double slidemin = m_slider->minValue(); // cast int to double to avoid
00640     double slidemax = m_slider->maxValue(); // overflow in rel denominator
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     // if in extra row, then count it here
00666     if(m_label && (m_alignment & (AlignBottom|AlignTop)))
00667         h += 4 + m_sizeLabel.height();
00668     else
00669         // label is in the same row as the other widgets
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     // clip to valid range:
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     // don't update the slider to avoid an endless recursion
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     // upcast to base type to get the min/maxValue in int form:
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         // feedback line: when one moves, the other moves, too:
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     // calculate ( slmax - slmin ) / 10 without overflowing ints:
00779     int major = calcDiffByTen( slmax, slmin );
00780     if ( !major ) major = slstep; // ### needed?
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                 // stripWhiteSpace(), cf. QSpinBox::interpretText()
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 // We use a kind of fixed-point arithmetic to represent the range of
00940 // doubles [mLower,mUpper] in steps of 10^(-mPrecision). Thus, the
00941 // following relations hold:
00942 //
00943 // 1. factor = 10^mPrecision
00944 // 2. basicStep = 1/factor = 10^(-mPrecision);
00945 // 3. lowerInt = lower * factor;
00946 // 4. upperInt = upper * factor;
00947 // 5. lower = lowerInt * basicStep;
00948 // 6. upper = upperInt * basicStep;
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; // we'll set one that does;
01023                                      // can't do it now, since we're const
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 ); // disable bounds checking, since
01037   setMinValue( lower );            // it's done in set{Min,Max}Value
01038   setMaxValue( upper );            // anyway and we want lower, upper
01039   setLineStep( step );             // and step to have the right precision
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     // INT_MAX must be > maxAbsValue * 10^precision
01063     // ==> 10^precision < INT_MAX / maxAbsValue
01064     // ==> precision < log10 ( INT_MAX / maxAbsValue )
01065     // ==> maxPrecision = floor( log10 ( INT_MAX / maxAbsValue ) );
01066     double maxAbsValue = kMax( fabs(minValue()), fabs(maxValue()) );
01067     if ( maxAbsValue == 0 ) return 6; // return arbitrary value to avoid dbz...
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   // silently discard the new validator. We don't want another one ;-)
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 { /*BASE::virtual_hook( id, data );*/ }
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 { /*BASE::virtual_hook( id, data );*/ }
01176 
01177 void KDoubleSpinBox::virtual_hook( int, void* )
01178 { /*BASE::virtual_hook( id, data );*/ }
01179 
01180 #include "knuminput.moc"

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal