src/gui/widgets/qabstractspinbox.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <qplatformdefs.h>
       
    43 #include <private/qabstractspinbox_p.h>
       
    44 #include <private/qdatetime_p.h>
       
    45 #include <private/qlineedit_p.h>
       
    46 #include <qabstractspinbox.h>
       
    47 
       
    48 #ifndef QT_NO_SPINBOX
       
    49 
       
    50 #include <qapplication.h>
       
    51 #include <qclipboard.h>
       
    52 #include <qdatetime.h>
       
    53 #include <qdatetimeedit.h>
       
    54 #include <qevent.h>
       
    55 #include <qmenu.h>
       
    56 #include <qpainter.h>
       
    57 #include <qpalette.h>
       
    58 #include <qstylepainter.h>
       
    59 #include <qdebug.h>
       
    60 #ifndef QT_NO_ACCESSIBILITY
       
    61 # include <qaccessible.h>
       
    62 #endif
       
    63 
       
    64 #if defined(Q_WS_X11)
       
    65 #include <limits.h>
       
    66 #endif
       
    67 
       
    68 //#define QABSTRACTSPINBOX_QSBDEBUG
       
    69 #ifdef QABSTRACTSPINBOX_QSBDEBUG
       
    70 #  define QASBDEBUG qDebug
       
    71 #else
       
    72 #  define QASBDEBUG if (false) qDebug
       
    73 #endif
       
    74 
       
    75 QT_BEGIN_NAMESPACE
       
    76 
       
    77 /*!
       
    78     \class QAbstractSpinBox
       
    79     \brief The QAbstractSpinBox class provides a spinbox and a line edit to
       
    80     display values.
       
    81 
       
    82     \ingroup abstractwidgets
       
    83 
       
    84     The class is designed as a common super class for widgets like
       
    85     QSpinBox, QDoubleSpinBox and QDateTimeEdit
       
    86 
       
    87     Here are the main properties of the class:
       
    88 
       
    89     \list 1
       
    90 
       
    91     \i \l text: The text that is displayed in the QAbstractSpinBox.
       
    92 
       
    93     \i \l alignment: The alignment of the text in the QAbstractSpinBox.
       
    94 
       
    95     \i \l wrapping: Whether the QAbstractSpinBox wraps from the
       
    96     minimum value to the maximum value and vica versa.
       
    97 
       
    98     \endlist
       
    99 
       
   100     QAbstractSpinBox provides a virtual stepBy() function that is
       
   101     called whenever the user triggers a step. This function takes an
       
   102     integer value to signify how many steps were taken. E.g. Pressing
       
   103     Qt::Key_Down will trigger a call to stepBy(-1).
       
   104 
       
   105     QAbstractSpinBox also provide a virtual function stepEnabled() to
       
   106     determine whether stepping up/down is allowed at any point. This
       
   107     function returns a bitset of StepEnabled.
       
   108 
       
   109     \sa QAbstractSlider, QSpinBox, QDoubleSpinBox, QDateTimeEdit,
       
   110         {Spin Boxes Example}
       
   111 */
       
   112 
       
   113 /*!
       
   114     \enum QAbstractSpinBox::StepEnabledFlag
       
   115 
       
   116     \value StepNone
       
   117     \value StepUpEnabled
       
   118     \value StepDownEnabled
       
   119 */
       
   120 
       
   121 /*!
       
   122   \fn void QAbstractSpinBox::editingFinished()
       
   123 
       
   124   This signal is emitted editing is finished. This happens when the
       
   125   spinbox loses focus and when enter is pressed.
       
   126 */
       
   127 
       
   128 /*!
       
   129     Constructs an abstract spinbox with the given \a parent with default
       
   130     \l wrapping, and \l alignment properties.
       
   131 */
       
   132 
       
   133 QAbstractSpinBox::QAbstractSpinBox(QWidget *parent)
       
   134     : QWidget(*new QAbstractSpinBoxPrivate, parent, 0)
       
   135 {
       
   136     Q_D(QAbstractSpinBox);
       
   137     d->init();
       
   138 }
       
   139 
       
   140 /*!
       
   141     \internal
       
   142 */
       
   143 QAbstractSpinBox::QAbstractSpinBox(QAbstractSpinBoxPrivate &dd, QWidget *parent)
       
   144     : QWidget(dd, parent, 0)
       
   145 {
       
   146     Q_D(QAbstractSpinBox);
       
   147     d->init();
       
   148 }
       
   149 
       
   150 /*!
       
   151     Called when the QAbstractSpinBox is destroyed.
       
   152 */
       
   153 
       
   154 QAbstractSpinBox::~QAbstractSpinBox()
       
   155 {
       
   156 }
       
   157 
       
   158 /*!
       
   159     \enum QAbstractSpinBox::ButtonSymbols
       
   160 
       
   161     This enum type describes the symbols that can be displayed on the buttons
       
   162     in a spin box.
       
   163 
       
   164     \inlineimage qspinbox-updown.png
       
   165     \inlineimage qspinbox-plusminus.png
       
   166 
       
   167     \value UpDownArrows Little arrows in the classic style.
       
   168     \value PlusMinus \bold{+} and \bold{-} symbols.
       
   169     \value NoButtons Don't display buttons.
       
   170 
       
   171     \sa QAbstractSpinBox::buttonSymbols
       
   172 */
       
   173 
       
   174 /*!
       
   175     \property QAbstractSpinBox::buttonSymbols
       
   176 
       
   177     \brief the current button symbol mode
       
   178 
       
   179     The possible values can be either \c UpDownArrows or \c PlusMinus.
       
   180     The default is \c UpDownArrows.
       
   181 
       
   182     Note that some styles might render PlusMinus and UpDownArrows
       
   183     identically.
       
   184 
       
   185     \sa ButtonSymbols
       
   186 */
       
   187 
       
   188 QAbstractSpinBox::ButtonSymbols QAbstractSpinBox::buttonSymbols() const
       
   189 {
       
   190     Q_D(const QAbstractSpinBox);
       
   191     return d->buttonSymbols;
       
   192 }
       
   193 
       
   194 void QAbstractSpinBox::setButtonSymbols(ButtonSymbols buttonSymbols)
       
   195 {
       
   196     Q_D(QAbstractSpinBox);
       
   197     if (d->buttonSymbols != buttonSymbols) {
       
   198         d->buttonSymbols = buttonSymbols;
       
   199         d->updateEditFieldGeometry();
       
   200         update();
       
   201     }
       
   202 }
       
   203 
       
   204 /*!
       
   205     \property QAbstractSpinBox::text
       
   206 
       
   207     \brief the spin box's text, including any prefix and suffix
       
   208 
       
   209     There is no default text.
       
   210 */
       
   211 
       
   212 QString QAbstractSpinBox::text() const
       
   213 {
       
   214     return lineEdit()->displayText();
       
   215 }
       
   216 
       
   217 
       
   218 /*!
       
   219     \property QAbstractSpinBox::specialValueText
       
   220     \brief the special-value text
       
   221 
       
   222     If set, the spin box will display this text instead of a numeric
       
   223     value whenever the current value is equal to minimum(). Typical use
       
   224     is to indicate that this choice has a special (default) meaning.
       
   225 
       
   226     For example, if your spin box allows the user to choose a scale factor
       
   227     (or zoom level) for displaying an image, and your application is able
       
   228     to automatically choose one that will enable the image to fit completely
       
   229     within the display window, you can set up the spin box like this:
       
   230 
       
   231     \snippet examples/widgets/spinboxes/window.cpp 3
       
   232 
       
   233     The user will then be able to choose a scale from 1% to 1000%
       
   234     or select "Auto" to leave it up to the application to choose. Your code
       
   235     must then interpret the spin box value of 0 as a request from the user
       
   236     to scale the image to fit inside the window.
       
   237 
       
   238     All values are displayed with the prefix and suffix (if set), \e
       
   239     except for the special value, which only shows the special value
       
   240     text. This special text is passed in the QSpinBox::valueChanged()
       
   241     signal that passes a QString.
       
   242 
       
   243     To turn off the special-value text display, call this function
       
   244     with an empty string. The default is no special-value text, i.e.
       
   245     the numeric value is shown as usual.
       
   246 
       
   247     If no special-value text is set, specialValueText() returns an
       
   248     empty string.
       
   249 */
       
   250 
       
   251 QString QAbstractSpinBox::specialValueText() const
       
   252 {
       
   253     Q_D(const QAbstractSpinBox);
       
   254     return d->specialValueText;
       
   255 }
       
   256 
       
   257 void QAbstractSpinBox::setSpecialValueText(const QString &specialValueText)
       
   258 {
       
   259     Q_D(QAbstractSpinBox);
       
   260 
       
   261     d->specialValueText = specialValueText;
       
   262     d->cachedSizeHint = QSize(); // minimumSizeHint doesn't care about specialValueText
       
   263     d->clearCache();
       
   264     d->updateEdit();
       
   265 }
       
   266 
       
   267 /*!
       
   268     \property QAbstractSpinBox::wrapping
       
   269 
       
   270     \brief whether the spin box is circular.
       
   271 
       
   272     If wrapping is true stepping up from maximum() value will take you
       
   273     to the minimum() value and vica versa. Wrapping only make sense if
       
   274     you have minimum() and maximum() values set.
       
   275 
       
   276     \snippet doc/src/snippets/code/src_gui_widgets_qabstractspinbox.cpp 0
       
   277 
       
   278     \sa QSpinBox::minimum(), QSpinBox::maximum()
       
   279 */
       
   280 
       
   281 bool QAbstractSpinBox::wrapping() const
       
   282 {
       
   283     Q_D(const QAbstractSpinBox);
       
   284     return d->wrapping;
       
   285 }
       
   286 
       
   287 void QAbstractSpinBox::setWrapping(bool wrapping)
       
   288 {
       
   289     Q_D(QAbstractSpinBox);
       
   290     d->wrapping = wrapping;
       
   291 }
       
   292 
       
   293 
       
   294 /*!
       
   295     \property QAbstractSpinBox::readOnly
       
   296     \brief whether the spin box is read only.
       
   297 
       
   298     In read-only mode, the user can still copy the text to the
       
   299     clipboard, or drag and drop the text;
       
   300     but cannot edit it.
       
   301 
       
   302     The QLineEdit in the QAbstractSpinBox does not show a cursor in
       
   303     read-only mode.
       
   304 
       
   305     \sa QLineEdit::readOnly
       
   306 */
       
   307 
       
   308 bool QAbstractSpinBox::isReadOnly() const
       
   309 {
       
   310     Q_D(const QAbstractSpinBox);
       
   311     return d->readOnly;
       
   312 }
       
   313 
       
   314 void QAbstractSpinBox::setReadOnly(bool enable)
       
   315 {
       
   316     Q_D(QAbstractSpinBox);
       
   317     d->readOnly = enable;
       
   318     d->edit->setReadOnly(enable);
       
   319     update();
       
   320 }
       
   321 
       
   322 /*!
       
   323     \property QAbstractSpinBox::keyboardTracking
       
   324     \brief whether keyboard tracking is enabled for the spinbox.
       
   325     \since 4.3
       
   326 
       
   327     If keyboard tracking is enabled (the default), the spinbox
       
   328     emits the valueChanged() signal while the new value is being
       
   329     entered from the keyboard.
       
   330 
       
   331     E.g. when the user enters the value 600 by typing 6, 0, and 0,
       
   332     the spinbox emits 3 signals with the values 6, 60, and 600
       
   333     respectively.
       
   334 
       
   335     If keyboard tracking is disabled, the spinbox doesn't emit the
       
   336     valueChanged() signal while typing. It emits the signal later,
       
   337     when the return key is pressed, when keyboard focus is lost, or
       
   338     when other spinbox functionality is used, e.g. pressing an arrow
       
   339     key.
       
   340 */
       
   341 
       
   342 bool QAbstractSpinBox::keyboardTracking() const
       
   343 {
       
   344     Q_D(const QAbstractSpinBox);
       
   345     return d->keyboardTracking;
       
   346 }
       
   347 
       
   348 void QAbstractSpinBox::setKeyboardTracking(bool enable)
       
   349 {
       
   350     Q_D(QAbstractSpinBox);
       
   351     d->keyboardTracking = enable;
       
   352 }
       
   353 
       
   354 /*!
       
   355     \property QAbstractSpinBox::frame
       
   356     \brief whether the spin box draws itself with a frame
       
   357 
       
   358     If enabled (the default) the spin box draws itself inside a frame,
       
   359     otherwise the spin box draws itself without any frame.
       
   360 */
       
   361 
       
   362 bool QAbstractSpinBox::hasFrame() const
       
   363 {
       
   364     Q_D(const QAbstractSpinBox);
       
   365     return d->frame;
       
   366 }
       
   367 
       
   368 
       
   369 void QAbstractSpinBox::setFrame(bool enable)
       
   370 {
       
   371     Q_D(QAbstractSpinBox);
       
   372     d->frame = enable;
       
   373     update();
       
   374     d->updateEditFieldGeometry();
       
   375 }
       
   376 
       
   377 /*!
       
   378     \property QAbstractSpinBox::accelerated
       
   379     \brief whether the spin box will accelerate the frequency of the steps when
       
   380     pressing the step Up/Down buttons.
       
   381     \since 4.2
       
   382 
       
   383     If enabled the spin box will increase/decrease the value faster
       
   384     the longer you hold the button down.
       
   385 */
       
   386 
       
   387 void QAbstractSpinBox::setAccelerated(bool accelerate)
       
   388 {
       
   389     Q_D(QAbstractSpinBox);
       
   390     d->accelerate = accelerate;
       
   391 
       
   392 }
       
   393 bool QAbstractSpinBox::isAccelerated() const
       
   394 {
       
   395     Q_D(const QAbstractSpinBox);
       
   396     return d->accelerate;
       
   397 }
       
   398 
       
   399 /*!
       
   400     \enum QAbstractSpinBox::CorrectionMode
       
   401 
       
   402     This enum type describes the mode the spinbox will use to correct
       
   403     an \l{QValidator::}{Intermediate} value if editing finishes.
       
   404 
       
   405     \value CorrectToPreviousValue The spinbox will revert to the last
       
   406                                   valid value.
       
   407 
       
   408     \value CorrectToNearestValue The spinbox will revert to the nearest
       
   409                                  valid value.
       
   410 
       
   411     \sa correctionMode
       
   412 */
       
   413 
       
   414 /*!
       
   415     \property QAbstractSpinBox::correctionMode
       
   416     \brief the mode to correct an \l{QValidator::}{Intermediate}
       
   417            value if editing finishes
       
   418     \since 4.2
       
   419 
       
   420     The default mode is QAbstractSpinBox::CorrectToPreviousValue.
       
   421 
       
   422     \sa acceptableInput, validate(), fixup()
       
   423 */
       
   424 void QAbstractSpinBox::setCorrectionMode(CorrectionMode correctionMode)
       
   425 {
       
   426     Q_D(QAbstractSpinBox);
       
   427     d->correctionMode = correctionMode;
       
   428 
       
   429 }
       
   430 QAbstractSpinBox::CorrectionMode QAbstractSpinBox::correctionMode() const
       
   431 {
       
   432     Q_D(const QAbstractSpinBox);
       
   433     return d->correctionMode;
       
   434 }
       
   435 
       
   436 
       
   437 /*!
       
   438   \property QAbstractSpinBox::acceptableInput
       
   439   \brief whether the input satisfies the current validation
       
   440   \since 4.2
       
   441 
       
   442   \sa validate(), fixup(), correctionMode
       
   443 */
       
   444 
       
   445 bool QAbstractSpinBox::hasAcceptableInput() const
       
   446 {
       
   447     Q_D(const QAbstractSpinBox);
       
   448     return d->edit->hasAcceptableInput();
       
   449 }
       
   450 
       
   451 /*!
       
   452     \property QAbstractSpinBox::alignment
       
   453     \brief the alignment of the spin box
       
   454 
       
   455     Possible Values are Qt::AlignLeft, Qt::AlignRight, and Qt::AlignHCenter.
       
   456 
       
   457     By default, the alignment is Qt::AlignLeft
       
   458 
       
   459     Attempting to set the alignment to an illegal flag combination
       
   460     does nothing.
       
   461 
       
   462     \sa Qt::Alignment
       
   463 */
       
   464 
       
   465 Qt::Alignment QAbstractSpinBox::alignment() const
       
   466 {
       
   467     Q_D(const QAbstractSpinBox);
       
   468 
       
   469     return (Qt::Alignment)d->edit->alignment();
       
   470 }
       
   471 
       
   472 void QAbstractSpinBox::setAlignment(Qt::Alignment flag)
       
   473 {
       
   474     Q_D(QAbstractSpinBox);
       
   475 
       
   476     d->edit->setAlignment(flag);
       
   477 }
       
   478 
       
   479 /*!
       
   480     Selects all the text in the spinbox except the prefix and suffix.
       
   481 */
       
   482 
       
   483 void QAbstractSpinBox::selectAll()
       
   484 {
       
   485     Q_D(QAbstractSpinBox);
       
   486 
       
   487 
       
   488     if (!d->specialValue()) {
       
   489         const int tmp = d->edit->displayText().size() - d->suffix.size();
       
   490         d->edit->setSelection(tmp, -(tmp - d->prefix.size()));
       
   491     } else {
       
   492         d->edit->selectAll();
       
   493     }
       
   494 }
       
   495 
       
   496 /*!
       
   497     Clears the lineedit of all text but prefix and suffix.
       
   498 */
       
   499 
       
   500 void QAbstractSpinBox::clear()
       
   501 {
       
   502     Q_D(QAbstractSpinBox);
       
   503 
       
   504     d->edit->setText(d->prefix + d->suffix);
       
   505     d->edit->setCursorPosition(d->prefix.size());
       
   506     d->cleared = true;
       
   507 }
       
   508 
       
   509 /*!
       
   510     Virtual function that determines whether stepping up and down is
       
   511     legal at any given time.
       
   512 
       
   513     The up arrow will be painted as disabled unless (stepEnabled() &
       
   514     StepUpEnabled) != 0.
       
   515 
       
   516     The default implementation will return (StepUpEnabled|
       
   517     StepDownEnabled) if wrapping is turned on. Else it will return
       
   518     StepDownEnabled if value is > minimum() or'ed with StepUpEnabled if
       
   519     value < maximum().
       
   520 
       
   521     If you subclass QAbstractSpinBox you will need to reimplement this function.
       
   522 
       
   523     \sa QSpinBox::minimum(), QSpinBox::maximum(), wrapping()
       
   524 */
       
   525 
       
   526 
       
   527 QAbstractSpinBox::StepEnabled QAbstractSpinBox::stepEnabled() const
       
   528 {
       
   529     Q_D(const QAbstractSpinBox);
       
   530     if (d->readOnly || d->type == QVariant::Invalid)
       
   531         return StepNone;
       
   532     if (d->wrapping)
       
   533         return StepEnabled(StepUpEnabled | StepDownEnabled);
       
   534     StepEnabled ret = StepNone;
       
   535     if (d->variantCompare(d->value, d->maximum) < 0) {
       
   536         ret |= StepUpEnabled;
       
   537     }
       
   538     if (d->variantCompare(d->value, d->minimum) > 0) {
       
   539         ret |= StepDownEnabled;
       
   540     }
       
   541     return ret;
       
   542 }
       
   543 
       
   544 /*!
       
   545    This virtual function is called by the QAbstractSpinBox to
       
   546    determine whether \a input is valid. The \a pos parameter indicates
       
   547    the position in the string. Reimplemented in the various
       
   548    subclasses.
       
   549 */
       
   550 
       
   551 QValidator::State QAbstractSpinBox::validate(QString & /* input */, int & /* pos */) const
       
   552 {
       
   553     return QValidator::Acceptable;
       
   554 }
       
   555 
       
   556 /*!
       
   557    This virtual function is called by the QAbstractSpinBox if the
       
   558    \a input is not validated to QValidator::Acceptable when Return is
       
   559    pressed or interpretText() is called. It will try to change the
       
   560    text so it is valid. Reimplemented in the various subclasses.
       
   561 */
       
   562 
       
   563 void QAbstractSpinBox::fixup(QString & /* input */) const
       
   564 {
       
   565 }
       
   566 
       
   567 /*!
       
   568   Steps up by one linestep
       
   569   Calling this slot is analogous to calling stepBy(1);
       
   570   \sa stepBy(), stepDown()
       
   571 */
       
   572 
       
   573 void QAbstractSpinBox::stepUp()
       
   574 {
       
   575     stepBy(1);
       
   576 }
       
   577 
       
   578 /*!
       
   579   Steps down by one linestep
       
   580   Calling this slot is analogous to calling stepBy(-1);
       
   581   \sa stepBy(), stepUp()
       
   582 */
       
   583 
       
   584 void QAbstractSpinBox::stepDown()
       
   585 {
       
   586     stepBy(-1);
       
   587 }
       
   588 /*!
       
   589     Virtual function that is called whenever the user triggers a step.
       
   590     The \a steps parameter indicates how many steps were taken, e.g.
       
   591     Pressing Qt::Key_Down will trigger a call to stepBy(-1),
       
   592     whereas pressing Qt::Key_Prior will trigger a call to
       
   593     stepBy(10).
       
   594 
       
   595     If you subclass QAbstractSpinBox you must reimplement this
       
   596     function. Note that this function is called even if the resulting
       
   597     value will be outside the bounds of minimum and maximum. It's this
       
   598     function's job to handle these situations.
       
   599 */
       
   600 
       
   601 void QAbstractSpinBox::stepBy(int steps)
       
   602 {
       
   603     Q_D(QAbstractSpinBox);
       
   604 
       
   605     const QVariant old = d->value;
       
   606     QString tmp = d->edit->displayText();
       
   607     int cursorPos = d->edit->cursorPosition();
       
   608     bool dontstep = false;
       
   609     EmitPolicy e = EmitIfChanged;
       
   610     if (d->pendingEmit) {
       
   611         dontstep = validate(tmp, cursorPos) != QValidator::Acceptable;
       
   612         d->cleared = false;
       
   613         d->interpret(NeverEmit);
       
   614         if (d->value != old)
       
   615             e = AlwaysEmit;
       
   616     }
       
   617     if (!dontstep) {
       
   618         d->setValue(d->bound(d->value + (d->singleStep * steps), old, steps), e);
       
   619     } else if (e == AlwaysEmit) {
       
   620         d->emitSignals(e, old);
       
   621     }
       
   622     selectAll();
       
   623 }
       
   624 
       
   625 /*!
       
   626     This function returns a pointer to the line edit of the spin box.
       
   627 */
       
   628 
       
   629 QLineEdit *QAbstractSpinBox::lineEdit() const
       
   630 {
       
   631     Q_D(const QAbstractSpinBox);
       
   632 
       
   633     return d->edit;
       
   634 }
       
   635 
       
   636 
       
   637 /*!
       
   638     \fn void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
       
   639 
       
   640     Sets the line edit of the spinbox to be \a lineEdit instead of the
       
   641     current line edit widget. \a lineEdit can not be 0.
       
   642 
       
   643     QAbstractSpinBox takes ownership of the new lineEdit
       
   644 
       
   645     If QLineEdit::validator() for the \a lineEdit returns 0, the internal
       
   646     validator of the spinbox will be set on the line edit.
       
   647 */
       
   648 
       
   649 void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
       
   650 {
       
   651     Q_D(QAbstractSpinBox);
       
   652 
       
   653     if (!lineEdit) {
       
   654         Q_ASSERT(lineEdit);
       
   655         return;
       
   656     }
       
   657     delete d->edit;
       
   658     d->edit = lineEdit;
       
   659     if (!d->edit->validator())
       
   660         d->edit->setValidator(d->validator);
       
   661 
       
   662     if (d->edit->parent() != this)
       
   663         d->edit->setParent(this);
       
   664 
       
   665     d->edit->setFrame(false);
       
   666     d->edit->setFocusProxy(this);
       
   667     d->edit->setAcceptDrops(false);
       
   668 
       
   669     if (d->type != QVariant::Invalid) {
       
   670         connect(d->edit, SIGNAL(textChanged(QString)),
       
   671                 this, SLOT(_q_editorTextChanged(QString)));
       
   672         connect(d->edit, SIGNAL(cursorPositionChanged(int,int)),
       
   673                 this, SLOT(_q_editorCursorPositionChanged(int,int)));
       
   674     }
       
   675     d->updateEditFieldGeometry();
       
   676     d->edit->setContextMenuPolicy(Qt::NoContextMenu);
       
   677 
       
   678     if (isVisible())
       
   679         d->edit->show();
       
   680     if (isVisible())
       
   681         d->updateEdit();
       
   682 }
       
   683 
       
   684 
       
   685 /*!
       
   686     This function interprets the text of the spin box. If the value
       
   687     has changed since last interpretation it will emit signals.
       
   688 */
       
   689 
       
   690 void QAbstractSpinBox::interpretText()
       
   691 {
       
   692     Q_D(QAbstractSpinBox);
       
   693     d->interpret(EmitIfChanged);
       
   694 }
       
   695 
       
   696 /*
       
   697     Reimplemented in 4.6, so be careful.
       
   698  */
       
   699 /*!
       
   700     \reimp
       
   701 */
       
   702 QVariant QAbstractSpinBox::inputMethodQuery(Qt::InputMethodQuery query) const
       
   703 {
       
   704     Q_D(const QAbstractSpinBox);
       
   705     return d->edit->inputMethodQuery(query);
       
   706 }
       
   707 
       
   708 /*!
       
   709     \reimp
       
   710 */
       
   711 
       
   712 bool QAbstractSpinBox::event(QEvent *event)
       
   713 {
       
   714     Q_D(QAbstractSpinBox);
       
   715     switch (event->type()) {
       
   716     case QEvent::FontChange:
       
   717     case QEvent::StyleChange:
       
   718         d->cachedSizeHint = d->cachedMinimumSizeHint = QSize();
       
   719         break;
       
   720     case QEvent::ApplicationLayoutDirectionChange:
       
   721     case QEvent::LayoutDirectionChange:
       
   722         d->updateEditFieldGeometry();
       
   723         break;
       
   724     case QEvent::HoverEnter:
       
   725     case QEvent::HoverLeave:
       
   726     case QEvent::HoverMove:
       
   727         if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
       
   728             d->updateHoverControl(he->pos());
       
   729         break;
       
   730     case QEvent::ShortcutOverride:
       
   731         if (d->edit->event(event))
       
   732             return true;
       
   733         break;
       
   734 #ifdef QT_KEYPAD_NAVIGATION
       
   735     case QEvent::EnterEditFocus:
       
   736     case QEvent::LeaveEditFocus:
       
   737         if (QApplication::keypadNavigationEnabled()) {
       
   738             const bool b = d->edit->event(event);
       
   739             d->edit->setSelection(d->edit->displayText().size() - d->suffix.size(),0);
       
   740             if (event->type() == QEvent::LeaveEditFocus)
       
   741                 emit editingFinished();
       
   742             if (b)
       
   743                 return true;
       
   744         }
       
   745         break;
       
   746 #endif
       
   747     case QEvent::InputMethod:
       
   748         return d->edit->event(event);
       
   749     default:
       
   750         break;
       
   751     }
       
   752     return QWidget::event(event);
       
   753 }
       
   754 
       
   755 /*!
       
   756     \reimp
       
   757 */
       
   758 
       
   759 void QAbstractSpinBox::showEvent(QShowEvent *)
       
   760 {
       
   761     Q_D(QAbstractSpinBox);
       
   762     d->reset();
       
   763 
       
   764     if (d->ignoreUpdateEdit) {
       
   765         d->ignoreUpdateEdit = false;
       
   766     } else {
       
   767         d->updateEdit();
       
   768     }
       
   769 }
       
   770 
       
   771 /*!
       
   772     \reimp
       
   773 */
       
   774 
       
   775 void QAbstractSpinBox::changeEvent(QEvent *event)
       
   776 {
       
   777     Q_D(QAbstractSpinBox);
       
   778 
       
   779     switch (event->type()) {
       
   780         case QEvent::StyleChange:
       
   781             d->spinClickTimerInterval = style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatRate, 0, this);
       
   782             d->spinClickThresholdTimerInterval =
       
   783                 style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, 0, this);
       
   784             d->reset();
       
   785             d->updateEditFieldGeometry();
       
   786             break;
       
   787         case QEvent::EnabledChange:
       
   788             if (!isEnabled()) {
       
   789                 d->reset();
       
   790             }
       
   791             break;
       
   792         case QEvent::ActivationChange:
       
   793             if (!isActiveWindow()){
       
   794                 d->reset();
       
   795                 if (d->pendingEmit) // pendingEmit can be true even if it hasn't changed.
       
   796                     d->interpret(EmitIfChanged); // E.g. 10 to 10.0
       
   797             }
       
   798             break;
       
   799         default:
       
   800             break;
       
   801     }
       
   802     QWidget::changeEvent(event);
       
   803 }
       
   804 
       
   805 /*!
       
   806     \reimp
       
   807 */
       
   808 
       
   809 void QAbstractSpinBox::resizeEvent(QResizeEvent *event)
       
   810 {
       
   811     Q_D(QAbstractSpinBox);
       
   812     QWidget::resizeEvent(event);
       
   813 
       
   814     d->updateEditFieldGeometry();
       
   815     update();
       
   816 }
       
   817 
       
   818 /*!
       
   819     \reimp
       
   820 */
       
   821 
       
   822 QSize QAbstractSpinBox::sizeHint() const
       
   823 {
       
   824     Q_D(const QAbstractSpinBox);
       
   825     if (d->cachedSizeHint.isEmpty()) {
       
   826         ensurePolished();
       
   827 
       
   828         const QFontMetrics fm(fontMetrics());
       
   829         int h = d->edit->sizeHint().height();
       
   830         int w = 0;
       
   831         QString s;
       
   832         s = d->prefix + d->textFromValue(d->minimum) + d->suffix + QLatin1Char(' ');
       
   833         s.truncate(18);
       
   834         w = qMax(w, fm.width(s));
       
   835         s = d->prefix + d->textFromValue(d->maximum) + d->suffix + QLatin1Char(' ');
       
   836         s.truncate(18);
       
   837         w = qMax(w, fm.width(s));
       
   838         if (d->specialValueText.size()) {
       
   839             s = d->specialValueText;
       
   840             w = qMax(w, fm.width(s));
       
   841         }
       
   842         w += 2; // cursor blinking space
       
   843 
       
   844         QStyleOptionSpinBox opt;
       
   845         initStyleOption(&opt);
       
   846         QSize hint(w, h);
       
   847         QSize extra(35, 6);
       
   848         opt.rect.setSize(hint + extra);
       
   849         extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
       
   850                                                 QStyle::SC_SpinBoxEditField, this).size();
       
   851         // get closer to final result by repeating the calculation
       
   852         opt.rect.setSize(hint + extra);
       
   853         extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
       
   854                                                 QStyle::SC_SpinBoxEditField, this).size();
       
   855         hint += extra;
       
   856 
       
   857         opt.rect = rect();
       
   858         d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
       
   859                             .expandedTo(QApplication::globalStrut());
       
   860     }
       
   861     return d->cachedSizeHint;
       
   862 }
       
   863 
       
   864 /*!
       
   865     \reimp
       
   866 */
       
   867 
       
   868 QSize QAbstractSpinBox::minimumSizeHint() const
       
   869 {
       
   870     Q_D(const QAbstractSpinBox);
       
   871     if (d->cachedMinimumSizeHint.isEmpty()) {
       
   872         ensurePolished();
       
   873 
       
   874         const QFontMetrics fm(fontMetrics());
       
   875         int h = d->edit->minimumSizeHint().height();
       
   876         int w = fm.width(QLatin1String("1000"));
       
   877         w += 2; // cursor blinking space
       
   878 
       
   879         QStyleOptionSpinBox opt;
       
   880         initStyleOption(&opt);
       
   881         QSize hint(w, h);
       
   882         QSize extra(35, 6);
       
   883         opt.rect.setSize(hint + extra);
       
   884         extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
       
   885                                                 QStyle::SC_SpinBoxEditField, this).size();
       
   886         // get closer to final result by repeating the calculation
       
   887         opt.rect.setSize(hint + extra);
       
   888         extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
       
   889                                                 QStyle::SC_SpinBoxEditField, this).size();
       
   890         hint += extra;
       
   891 
       
   892         opt.rect = rect();
       
   893 
       
   894         d->cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
       
   895                                    .expandedTo(QApplication::globalStrut());
       
   896     }
       
   897     return d->cachedMinimumSizeHint;
       
   898 }
       
   899 
       
   900 /*!
       
   901     \reimp
       
   902 */
       
   903 
       
   904 void QAbstractSpinBox::paintEvent(QPaintEvent *)
       
   905 {
       
   906     QStyleOptionSpinBox opt;
       
   907     initStyleOption(&opt);
       
   908     QStylePainter p(this);
       
   909     p.drawComplexControl(QStyle::CC_SpinBox, opt);
       
   910 }
       
   911 
       
   912 /*!
       
   913     \reimp
       
   914 
       
   915     This function handles keyboard input.
       
   916 
       
   917     The following keys are handled specifically:
       
   918     \table
       
   919     \row \i Enter/Return
       
   920          \i This will reinterpret the text and emit a signal even if the value has not changed
       
   921          since last time a signal was emitted.
       
   922     \row \i Up
       
   923          \i This will invoke stepBy(1)
       
   924     \row \i Down
       
   925          \i This will invoke stepBy(-1)
       
   926     \row \i Page up
       
   927          \i This will invoke stepBy(10)
       
   928     \row \i Page down
       
   929          \i This will invoke stepBy(-10)
       
   930     \endtable
       
   931 */
       
   932 
       
   933 
       
   934 void QAbstractSpinBox::keyPressEvent(QKeyEvent *event)
       
   935 {
       
   936     Q_D(QAbstractSpinBox);
       
   937 
       
   938     if (!event->text().isEmpty() && d->edit->cursorPosition() < d->prefix.size())
       
   939         d->edit->setCursorPosition(d->prefix.size());
       
   940 
       
   941     int steps = 1;
       
   942     switch (event->key()) {
       
   943     case Qt::Key_PageUp:
       
   944     case Qt::Key_PageDown:
       
   945         steps *= 10;
       
   946     case Qt::Key_Up:
       
   947     case Qt::Key_Down: {
       
   948 #ifdef QT_KEYPAD_NAVIGATION
       
   949         if (QApplication::keypadNavigationEnabled()) {
       
   950             // Reserve up/down for nav - use left/right for edit.
       
   951             if (!hasEditFocus() && (event->key() == Qt::Key_Up
       
   952                                     || event->key() == Qt::Key_Down)) {
       
   953                 event->ignore();
       
   954                 return;
       
   955             }
       
   956         }
       
   957 #endif
       
   958         event->accept();
       
   959         const bool up = (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_Up);
       
   960         if (!(stepEnabled() & (up ? StepUpEnabled : StepDownEnabled)))
       
   961             return;
       
   962         if (!up)
       
   963             steps *= -1;
       
   964         if (style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) {
       
   965             d->buttonState = (Keyboard | (up ? Up : Down));
       
   966         }
       
   967         stepBy(steps);
       
   968 #ifndef QT_NO_ACCESSIBILITY
       
   969         QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
       
   970 #endif
       
   971         return;
       
   972     }
       
   973 #ifdef QT_KEYPAD_NAVIGATION
       
   974     case Qt::Key_Left:
       
   975     case Qt::Key_Right:
       
   976         if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
       
   977             event->ignore();
       
   978             return;
       
   979         }
       
   980         break;
       
   981     case Qt::Key_Back:
       
   982         if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) {
       
   983             event->ignore();
       
   984             return;
       
   985         }
       
   986         break;
       
   987 #endif
       
   988     case Qt::Key_Enter:
       
   989     case Qt::Key_Return:
       
   990         d->edit->d_func()->control->clearUndo();
       
   991         d->interpret(d->keyboardTracking ? AlwaysEmit : EmitIfChanged);
       
   992         selectAll();
       
   993         event->ignore();
       
   994         emit editingFinished();
       
   995         return;
       
   996 
       
   997 #ifdef QT_KEYPAD_NAVIGATION
       
   998     case Qt::Key_Select:
       
   999         if (QApplication::keypadNavigationEnabled()) {
       
  1000             // Toggles between left/right moving cursor and inc/dec.
       
  1001             setEditFocus(!hasEditFocus());
       
  1002         }
       
  1003         return;
       
  1004 #endif
       
  1005 
       
  1006 #ifdef Q_WS_X11 // only X11
       
  1007     case Qt::Key_U:
       
  1008         if (event->modifiers() & Qt::ControlModifier) {
       
  1009             event->accept();
       
  1010             if (!isReadOnly())
       
  1011                 clear();
       
  1012             return;
       
  1013         }
       
  1014         break;
       
  1015 #endif
       
  1016 
       
  1017     case Qt::Key_End:
       
  1018     case Qt::Key_Home:
       
  1019         if (event->modifiers() & Qt::ShiftModifier) {
       
  1020             int currentPos = d->edit->cursorPosition();
       
  1021             const QString text = d->edit->displayText();
       
  1022             if (event->key() == Qt::Key_End) {
       
  1023                 if ((currentPos == 0 && !d->prefix.isEmpty()) || text.size() - d->suffix.size() <= currentPos) {
       
  1024                     break; // let lineedit handle this
       
  1025                 } else {
       
  1026                     d->edit->setSelection(currentPos, text.size() - d->suffix.size() - currentPos);
       
  1027                 }
       
  1028             } else {
       
  1029                 if ((currentPos == text.size() && !d->suffix.isEmpty()) || currentPos <= d->prefix.size()) {
       
  1030                     break; // let lineedit handle this
       
  1031                 } else {
       
  1032                     d->edit->setSelection(currentPos, d->prefix.size() - currentPos);
       
  1033                 }
       
  1034             }
       
  1035             event->accept();
       
  1036             return;
       
  1037         }
       
  1038         break;
       
  1039 
       
  1040     default:
       
  1041 #ifndef QT_NO_SHORTCUT
       
  1042         if (event == QKeySequence::SelectAll) {
       
  1043             selectAll();
       
  1044             event->accept();
       
  1045             return;
       
  1046         }
       
  1047 #endif
       
  1048         break;
       
  1049     }
       
  1050 
       
  1051     d->edit->event(event);
       
  1052     if (!isVisible())
       
  1053         d->ignoreUpdateEdit = true;
       
  1054 }
       
  1055 
       
  1056 /*!
       
  1057     \reimp
       
  1058 */
       
  1059 
       
  1060 void QAbstractSpinBox::keyReleaseEvent(QKeyEvent *event)
       
  1061 {
       
  1062     Q_D(QAbstractSpinBox);
       
  1063 
       
  1064     if (d->buttonState & Keyboard && !event->isAutoRepeat()
       
  1065         && style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) {
       
  1066         d->reset();
       
  1067     } else {
       
  1068         d->edit->event(event);
       
  1069     }
       
  1070 }
       
  1071 
       
  1072 /*!
       
  1073     \reimp
       
  1074 */
       
  1075 
       
  1076 #ifndef QT_NO_WHEELEVENT
       
  1077 void QAbstractSpinBox::wheelEvent(QWheelEvent *event)
       
  1078 {
       
  1079     const int steps = (event->delta() > 0 ? 1 : -1);
       
  1080     if (stepEnabled() & (steps > 0 ? StepUpEnabled : StepDownEnabled))
       
  1081         stepBy(event->modifiers() & Qt::ControlModifier ? steps * 10 : steps);
       
  1082     event->accept();
       
  1083 }
       
  1084 #endif
       
  1085 
       
  1086 
       
  1087 /*!
       
  1088     \reimp
       
  1089 */
       
  1090 void QAbstractSpinBox::focusInEvent(QFocusEvent *event)
       
  1091 {
       
  1092     Q_D(QAbstractSpinBox);
       
  1093 
       
  1094     d->edit->event(event);
       
  1095     if (event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason) {
       
  1096         selectAll();
       
  1097     }
       
  1098     QWidget::focusInEvent(event);
       
  1099 }
       
  1100 
       
  1101 /*!
       
  1102     \reimp
       
  1103 */
       
  1104 
       
  1105 void QAbstractSpinBox::focusOutEvent(QFocusEvent *event)
       
  1106 {
       
  1107     Q_D(QAbstractSpinBox);
       
  1108 
       
  1109     if (d->pendingEmit)
       
  1110         d->interpret(EmitIfChanged);
       
  1111 
       
  1112     d->reset();
       
  1113     d->edit->event(event);
       
  1114     d->updateEdit();
       
  1115     QWidget::focusOutEvent(event);
       
  1116 
       
  1117 #ifdef QT_KEYPAD_NAVIGATION
       
  1118     // editingFinished() is already emitted on LeaveEditFocus
       
  1119     if (!QApplication::keypadNavigationEnabled())
       
  1120 #endif
       
  1121     emit editingFinished();
       
  1122 }
       
  1123 
       
  1124 /*!
       
  1125     \reimp
       
  1126 */
       
  1127 
       
  1128 void QAbstractSpinBox::closeEvent(QCloseEvent *event)
       
  1129 {
       
  1130     Q_D(QAbstractSpinBox);
       
  1131 
       
  1132     d->reset();
       
  1133     if (d->pendingEmit)
       
  1134         d->interpret(EmitIfChanged);
       
  1135     QWidget::closeEvent(event);
       
  1136 }
       
  1137 
       
  1138 /*!
       
  1139     \reimp
       
  1140 */
       
  1141 
       
  1142 void QAbstractSpinBox::hideEvent(QHideEvent *event)
       
  1143 {
       
  1144     Q_D(QAbstractSpinBox);
       
  1145     d->reset();
       
  1146     if (d->pendingEmit)
       
  1147         d->interpret(EmitIfChanged);
       
  1148     QWidget::hideEvent(event);
       
  1149 }
       
  1150 
       
  1151 /*!
       
  1152     \reimp
       
  1153 */
       
  1154 
       
  1155 void QAbstractSpinBox::timerEvent(QTimerEvent *event)
       
  1156 {
       
  1157     Q_D(QAbstractSpinBox);
       
  1158 
       
  1159     bool doStep = false;
       
  1160     if (event->timerId() == d->spinClickThresholdTimerId) {
       
  1161         killTimer(d->spinClickThresholdTimerId);
       
  1162         d->spinClickThresholdTimerId = -1;
       
  1163         d->spinClickTimerId = startTimer(d->spinClickTimerInterval);
       
  1164         doStep = true;
       
  1165     } else if (event->timerId() == d->spinClickTimerId) {
       
  1166         if (d->accelerate) {
       
  1167             d->acceleration = d->acceleration + (int)(d->spinClickTimerInterval * 0.05);
       
  1168             if (d->spinClickTimerInterval - d->acceleration >= 10) {
       
  1169                 killTimer(d->spinClickTimerId);
       
  1170                 d->spinClickTimerId = startTimer(d->spinClickTimerInterval - d->acceleration);
       
  1171             }
       
  1172         }
       
  1173         doStep = true;
       
  1174     }
       
  1175 
       
  1176     if (doStep) {
       
  1177         const StepEnabled st = stepEnabled();
       
  1178         if (d->buttonState & Up) {
       
  1179             if (!(st & StepUpEnabled)) {
       
  1180                 d->reset();
       
  1181             } else {
       
  1182                 stepBy(1);
       
  1183             }
       
  1184         } else if (d->buttonState & Down) {
       
  1185             if (!(st & StepDownEnabled)) {
       
  1186                 d->reset();
       
  1187             } else {
       
  1188                 stepBy(-1);
       
  1189             }
       
  1190         }
       
  1191         return;
       
  1192     }
       
  1193     QWidget::timerEvent(event);
       
  1194     return;
       
  1195 }
       
  1196 
       
  1197 /*!
       
  1198     \reimp
       
  1199 */
       
  1200 
       
  1201 void QAbstractSpinBox::contextMenuEvent(QContextMenuEvent *event)
       
  1202 {
       
  1203 #ifdef QT_NO_CONTEXTMENU
       
  1204     Q_UNUSED(event);
       
  1205 #else
       
  1206     Q_D(QAbstractSpinBox);
       
  1207 
       
  1208     d->reset();
       
  1209     QPointer<QMenu> menu = d->edit->createStandardContextMenu();
       
  1210 
       
  1211     QAction *selAll = new QAction(tr("&Select All"), menu);
       
  1212     menu->insertAction(d->edit->d_func()->selectAllAction,
       
  1213                       selAll);
       
  1214     menu->removeAction(d->edit->d_func()->selectAllAction);
       
  1215     menu->addSeparator();
       
  1216     const uint se = stepEnabled();
       
  1217     QAction *up = menu->addAction(tr("&Step up"));
       
  1218     up->setEnabled(se & StepUpEnabled);
       
  1219     QAction *down = menu->addAction(tr("Step &down"));
       
  1220     down->setEnabled(se & StepDownEnabled);
       
  1221     menu->addSeparator();
       
  1222 
       
  1223     const QPointer<QAbstractSpinBox> that = this;
       
  1224     const QPoint pos = (event->reason() == QContextMenuEvent::Mouse)
       
  1225         ? event->globalPos() : mapToGlobal(QPoint(event->pos().x(), 0)) + QPoint(width() / 2, height() / 2);
       
  1226     const QAction *action = menu->exec(pos);
       
  1227     delete static_cast<QMenu *>(menu);
       
  1228     if (that && action) {
       
  1229         if (action == up) {
       
  1230             stepBy(1);
       
  1231         } else if (action == down) {
       
  1232             stepBy(-1);
       
  1233         } else if (action == selAll) {
       
  1234             selectAll();
       
  1235         }
       
  1236     }
       
  1237     event->accept();
       
  1238 #endif // QT_NO_CONTEXTMENU
       
  1239 }
       
  1240 
       
  1241 /*!
       
  1242     \reimp
       
  1243 */
       
  1244 
       
  1245 void QAbstractSpinBox::mouseMoveEvent(QMouseEvent *event)
       
  1246 {
       
  1247     Q_D(QAbstractSpinBox);
       
  1248 
       
  1249     d->updateHoverControl(event->pos());
       
  1250 
       
  1251     // If we have a timer ID, update the state
       
  1252     if (d->spinClickTimerId != -1 && d->buttonSymbols != NoButtons) {
       
  1253         const StepEnabled se = stepEnabled();
       
  1254         if ((se & StepUpEnabled) && d->hoverControl == QStyle::SC_SpinBoxUp)
       
  1255             d->updateState(true);
       
  1256         else if ((se & StepDownEnabled) && d->hoverControl == QStyle::SC_SpinBoxDown)
       
  1257             d->updateState(false);
       
  1258         else
       
  1259             d->reset();
       
  1260         event->accept();
       
  1261     }
       
  1262 }
       
  1263 
       
  1264 /*!
       
  1265     \reimp
       
  1266 */
       
  1267 
       
  1268 void QAbstractSpinBox::mousePressEvent(QMouseEvent *event)
       
  1269 {
       
  1270     Q_D(QAbstractSpinBox);
       
  1271 
       
  1272     if (event->button() != Qt::LeftButton || d->buttonState != None) {
       
  1273         return;
       
  1274     }
       
  1275 
       
  1276     d->updateHoverControl(event->pos());
       
  1277     event->accept();
       
  1278 
       
  1279     const StepEnabled se = (d->buttonSymbols == NoButtons) ? StepEnabled(StepNone) : stepEnabled();
       
  1280     if ((se & StepUpEnabled) && d->hoverControl == QStyle::SC_SpinBoxUp) {
       
  1281         d->updateState(true);
       
  1282     } else if ((se & StepDownEnabled) && d->hoverControl == QStyle::SC_SpinBoxDown) {
       
  1283         d->updateState(false);
       
  1284     } else {
       
  1285         event->ignore();
       
  1286     }
       
  1287 }
       
  1288 
       
  1289 /*!
       
  1290     \reimp
       
  1291 */
       
  1292 void QAbstractSpinBox::mouseReleaseEvent(QMouseEvent *event)
       
  1293 {
       
  1294     Q_D(QAbstractSpinBox);
       
  1295 
       
  1296     if ((d->buttonState & Mouse) != 0)
       
  1297         d->reset();
       
  1298     event->accept();
       
  1299 }
       
  1300 
       
  1301 // --- QAbstractSpinBoxPrivate ---
       
  1302 
       
  1303 /*!
       
  1304     \internal
       
  1305     Constructs a QAbstractSpinBoxPrivate object
       
  1306 */
       
  1307 
       
  1308 QAbstractSpinBoxPrivate::QAbstractSpinBoxPrivate()
       
  1309     : edit(0), type(QVariant::Invalid), spinClickTimerId(-1),
       
  1310       spinClickTimerInterval(100), spinClickThresholdTimerId(-1), spinClickThresholdTimerInterval(-1),
       
  1311       buttonState(None), cachedText(QLatin1String("\x01")), cachedState(QValidator::Invalid),
       
  1312       pendingEmit(false), readOnly(false), wrapping(false),
       
  1313       ignoreCursorPositionChanged(false), frame(true), accelerate(false), keyboardTracking(true),
       
  1314       cleared(false), ignoreUpdateEdit(false), correctionMode(QAbstractSpinBox::CorrectToPreviousValue),
       
  1315       acceleration(0), hoverControl(QStyle::SC_None), buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0)
       
  1316 {
       
  1317 }
       
  1318 
       
  1319 /*
       
  1320    \internal
       
  1321    Called when the QAbstractSpinBoxPrivate is destroyed
       
  1322 */
       
  1323 QAbstractSpinBoxPrivate::~QAbstractSpinBoxPrivate()
       
  1324 {
       
  1325 }
       
  1326 
       
  1327 /*!
       
  1328     \internal
       
  1329     Updates the old and new hover control. Does nothing if the hover
       
  1330     control has not changed.
       
  1331 */
       
  1332 bool QAbstractSpinBoxPrivate::updateHoverControl(const QPoint &pos)
       
  1333 {
       
  1334     Q_Q(QAbstractSpinBox);
       
  1335     QRect lastHoverRect = hoverRect;
       
  1336     QStyle::SubControl lastHoverControl = hoverControl;
       
  1337     bool doesHover = q->testAttribute(Qt::WA_Hover);
       
  1338     if (lastHoverControl != newHoverControl(pos) && doesHover) {
       
  1339         q->update(lastHoverRect);
       
  1340         q->update(hoverRect);
       
  1341         return true;
       
  1342     }
       
  1343     return !doesHover;
       
  1344 }
       
  1345 
       
  1346 /*!
       
  1347     \internal
       
  1348     Returns the hover control at \a pos.
       
  1349     This will update the hoverRect and hoverControl.
       
  1350 */
       
  1351 QStyle::SubControl QAbstractSpinBoxPrivate::newHoverControl(const QPoint &pos)
       
  1352 {
       
  1353     Q_Q(QAbstractSpinBox);
       
  1354 
       
  1355     QStyleOptionSpinBox opt;
       
  1356     q->initStyleOption(&opt);
       
  1357     opt.subControls = QStyle::SC_All;
       
  1358     hoverControl = q->style()->hitTestComplexControl(QStyle::CC_SpinBox, &opt, pos, q);
       
  1359     hoverRect = q->style()->subControlRect(QStyle::CC_SpinBox, &opt, hoverControl, q);
       
  1360     return hoverControl;
       
  1361 }
       
  1362 
       
  1363 /*!
       
  1364     \internal
       
  1365     Strips any prefix/suffix from \a text.
       
  1366 */
       
  1367 
       
  1368 QString QAbstractSpinBoxPrivate::stripped(const QString &t, int *pos) const
       
  1369 {
       
  1370     QString text = t;
       
  1371     if (specialValueText.size() == 0 || text != specialValueText) {
       
  1372         int from = 0;
       
  1373         int size = text.size();
       
  1374         bool changed = false;
       
  1375         if (prefix.size() && text.startsWith(prefix)) {
       
  1376             from += prefix.size();
       
  1377             size -= from;
       
  1378             changed = true;
       
  1379         }
       
  1380         if (suffix.size() && text.endsWith(suffix)) {
       
  1381             size -= suffix.size();
       
  1382             changed = true;
       
  1383         }
       
  1384         if (changed)
       
  1385             text = text.mid(from, size);
       
  1386     }
       
  1387 
       
  1388     const int s = text.size();
       
  1389     text = text.trimmed();
       
  1390     if (pos)
       
  1391         (*pos) -= (s - text.size());
       
  1392     return text;
       
  1393 
       
  1394 }
       
  1395 
       
  1396 void QAbstractSpinBoxPrivate::updateEditFieldGeometry()
       
  1397 {
       
  1398     Q_Q(QAbstractSpinBox);
       
  1399     QStyleOptionSpinBox opt;
       
  1400     q->initStyleOption(&opt);
       
  1401     opt.subControls = QStyle::SC_SpinBoxEditField;
       
  1402     edit->setGeometry(q->style()->subControlRect(QStyle::CC_SpinBox, &opt,
       
  1403                                                  QStyle::SC_SpinBoxEditField, q));
       
  1404 }
       
  1405 /*!
       
  1406     \internal
       
  1407     Returns true if a specialValueText has been set and the current value is minimum.
       
  1408 */
       
  1409 
       
  1410 bool QAbstractSpinBoxPrivate::specialValue() const
       
  1411 {
       
  1412     return (value == minimum && !specialValueText.isEmpty());
       
  1413 }
       
  1414 
       
  1415 /*!
       
  1416     \internal Virtual function that emits signals when the value
       
  1417     changes. Reimplemented in the different subclasses.
       
  1418 */
       
  1419 
       
  1420 void QAbstractSpinBoxPrivate::emitSignals(EmitPolicy, const QVariant &)
       
  1421 {
       
  1422 }
       
  1423 
       
  1424 /*!
       
  1425     \internal
       
  1426 
       
  1427     Slot connected to the line edit's textChanged(const QString &)
       
  1428     signal.
       
  1429 */
       
  1430 
       
  1431 void QAbstractSpinBoxPrivate::_q_editorTextChanged(const QString &t)
       
  1432 {
       
  1433     Q_Q(QAbstractSpinBox);
       
  1434 
       
  1435     if (keyboardTracking) {
       
  1436         QString tmp = t;
       
  1437         int pos = edit->cursorPosition();
       
  1438         QValidator::State state = q->validate(tmp, pos);
       
  1439         if (state == QValidator::Acceptable) {
       
  1440             const QVariant v = valueFromText(tmp);
       
  1441             setValue(v, EmitIfChanged, tmp != t);
       
  1442             pendingEmit = false;
       
  1443         } else {
       
  1444             pendingEmit = true;
       
  1445         }
       
  1446     } else {
       
  1447         pendingEmit = true;
       
  1448     }
       
  1449 }
       
  1450 
       
  1451 /*!
       
  1452     \internal
       
  1453 
       
  1454     Virtual slot connected to the line edit's
       
  1455     cursorPositionChanged(int, int) signal. Will move the cursor to a
       
  1456     valid position if the new one is invalid. E.g. inside the prefix.
       
  1457     Reimplemented in Q[Date|Time|DateTime]EditPrivate to account for
       
  1458     the different sections etc.
       
  1459 */
       
  1460 
       
  1461 void QAbstractSpinBoxPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
       
  1462 {
       
  1463     if (!edit->hasSelectedText() && !ignoreCursorPositionChanged && !specialValue()) {
       
  1464         ignoreCursorPositionChanged = true;
       
  1465 
       
  1466         bool allowSelection = true;
       
  1467         int pos = -1;
       
  1468         if (newpos < prefix.size() && newpos != 0) {
       
  1469             if (oldpos == 0) {
       
  1470                 allowSelection = false;
       
  1471                 pos = prefix.size();
       
  1472             } else {
       
  1473                 pos = oldpos;
       
  1474             }
       
  1475         } else if (newpos > edit->text().size() - suffix.size()
       
  1476                    && newpos != edit->text().size()) {
       
  1477             if (oldpos == edit->text().size()) {
       
  1478                 pos = edit->text().size() - suffix.size();
       
  1479                 allowSelection = false;
       
  1480             } else {
       
  1481                 pos = edit->text().size();
       
  1482             }
       
  1483         }
       
  1484         if (pos != -1) {
       
  1485             const int selSize = edit->selectionStart() >= 0 && allowSelection
       
  1486                                   ? (edit->selectedText().size()
       
  1487                                      * (newpos < pos ? -1 : 1)) - newpos + pos
       
  1488                                   : 0;
       
  1489 
       
  1490             const bool wasBlocked = edit->blockSignals(true);
       
  1491             if (selSize != 0) {
       
  1492                 edit->setSelection(pos - selSize, selSize);
       
  1493             } else {
       
  1494                 edit->setCursorPosition(pos);
       
  1495             }
       
  1496             edit->blockSignals(wasBlocked);
       
  1497         }
       
  1498         ignoreCursorPositionChanged = false;
       
  1499     }
       
  1500 }
       
  1501 
       
  1502 /*!
       
  1503     \internal
       
  1504 
       
  1505     Initialises the QAbstractSpinBoxPrivate object.
       
  1506 */
       
  1507 
       
  1508 void QAbstractSpinBoxPrivate::init()
       
  1509 {
       
  1510     Q_Q(QAbstractSpinBox);
       
  1511 
       
  1512     q->setLineEdit(new QLineEdit(q));
       
  1513     edit->setObjectName(QLatin1String("qt_spinbox_lineedit"));
       
  1514     validator = new QSpinBoxValidator(q, this);
       
  1515     edit->setValidator(validator);
       
  1516 
       
  1517     QStyleOptionSpinBox opt;
       
  1518     q->initStyleOption(&opt);
       
  1519     spinClickTimerInterval = q->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatRate, &opt, q);
       
  1520     spinClickThresholdTimerInterval = q->style()->styleHint(QStyle::SH_SpinBox_ClickAutoRepeatThreshold, &opt, q);
       
  1521     q->setFocusPolicy(Qt::WheelFocus);
       
  1522     q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::SpinBox));
       
  1523     q->setAttribute(Qt::WA_InputMethodEnabled);
       
  1524 
       
  1525     q->setAttribute(Qt::WA_MacShowFocusRect);
       
  1526 }
       
  1527 
       
  1528 /*!
       
  1529     \internal
       
  1530 
       
  1531     Resets the state of the spinbox. E.g. the state is set to
       
  1532     (Keyboard|Up) if Key up is currently pressed.
       
  1533 */
       
  1534 
       
  1535 void QAbstractSpinBoxPrivate::reset()
       
  1536 {
       
  1537     Q_Q(QAbstractSpinBox);
       
  1538 
       
  1539     buttonState = None;
       
  1540     if (q) {
       
  1541         if (spinClickTimerId != -1)
       
  1542             q->killTimer(spinClickTimerId);
       
  1543         if (spinClickThresholdTimerId != -1)
       
  1544             q->killTimer(spinClickThresholdTimerId);
       
  1545         spinClickTimerId = spinClickThresholdTimerId = -1;
       
  1546         acceleration = 0;
       
  1547         q->update();
       
  1548     }
       
  1549 }
       
  1550 
       
  1551 /*!
       
  1552     \internal
       
  1553 
       
  1554     Updates the state of the spinbox.
       
  1555 */
       
  1556 
       
  1557 void QAbstractSpinBoxPrivate::updateState(bool up)
       
  1558 {
       
  1559     Q_Q(QAbstractSpinBox);
       
  1560     if ((up && (buttonState & Up)) || (!up && (buttonState & Down)))
       
  1561         return;
       
  1562     reset();
       
  1563     if (q && (q->stepEnabled() & (up ? QAbstractSpinBox::StepUpEnabled
       
  1564                                   : QAbstractSpinBox::StepDownEnabled))) {
       
  1565         spinClickThresholdTimerId = q->startTimer(spinClickThresholdTimerInterval);
       
  1566         buttonState = (up ? (Mouse | Up) : (Mouse | Down));
       
  1567         q->stepBy(up ? 1 : -1);
       
  1568 #ifndef QT_NO_ACCESSIBILITY
       
  1569         QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged);
       
  1570 #endif
       
  1571     }
       
  1572 }
       
  1573 
       
  1574 
       
  1575 /*!
       
  1576     Initialize \a option with the values from this QSpinBox. This method
       
  1577     is useful for subclasses when they need a QStyleOptionSpinBox, but don't want
       
  1578     to fill in all the information themselves.
       
  1579 
       
  1580     \sa QStyleOption::initFrom()
       
  1581 */
       
  1582 void QAbstractSpinBox::initStyleOption(QStyleOptionSpinBox *option) const
       
  1583 {
       
  1584     if (!option)
       
  1585         return;
       
  1586 
       
  1587     Q_D(const QAbstractSpinBox);
       
  1588     option->initFrom(this);
       
  1589     option->activeSubControls = QStyle::SC_None;
       
  1590     option->buttonSymbols = d->buttonSymbols;
       
  1591     option->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField;
       
  1592     if (d->buttonSymbols != QAbstractSpinBox::NoButtons) {
       
  1593         option->subControls |= QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown;
       
  1594         if (d->buttonState & Up) {
       
  1595             option->activeSubControls = QStyle::SC_SpinBoxUp;
       
  1596         } else if (d->buttonState & Down) {
       
  1597             option->activeSubControls = QStyle::SC_SpinBoxDown;
       
  1598         }
       
  1599     }
       
  1600 
       
  1601     if (d->buttonState) {
       
  1602         option->state |= QStyle::State_Sunken;
       
  1603     } else {
       
  1604         option->activeSubControls = d->hoverControl;
       
  1605     }
       
  1606 
       
  1607     option->stepEnabled = style()->styleHint(QStyle::SH_SpinControls_DisableOnBounds)
       
  1608                       ? stepEnabled()
       
  1609                       : (QAbstractSpinBox::StepDownEnabled|QAbstractSpinBox::StepUpEnabled);
       
  1610 
       
  1611     option->frame = d->frame;
       
  1612 }
       
  1613 
       
  1614 /*!
       
  1615     \internal
       
  1616 
       
  1617     Bounds \a val to be within minimum and maximum. Also tries to be
       
  1618     clever about setting it at min and max depending on what it was
       
  1619     and what direction it was changed etc.
       
  1620 */
       
  1621 
       
  1622 QVariant QAbstractSpinBoxPrivate::bound(const QVariant &val, const QVariant &old, int steps) const
       
  1623 {
       
  1624     QVariant v = val;
       
  1625     if (!wrapping || steps == 0 || old.isNull()) {
       
  1626         if (variantCompare(v, minimum) < 0) {
       
  1627             v = wrapping ? maximum : minimum;
       
  1628         }
       
  1629         if (variantCompare(v, maximum) > 0) {
       
  1630             v = wrapping ? minimum : maximum;
       
  1631         }
       
  1632     } else {
       
  1633         const bool wasMin = old == minimum;
       
  1634         const bool wasMax = old == maximum;
       
  1635         const int oldcmp = variantCompare(v, old);
       
  1636         const int maxcmp = variantCompare(v, maximum);
       
  1637         const int mincmp = variantCompare(v, minimum);
       
  1638         const bool wrapped = (oldcmp > 0 && steps < 0) || (oldcmp < 0 && steps > 0);
       
  1639         if (maxcmp > 0) {
       
  1640             v = ((wasMax && !wrapped && steps > 0) || (steps < 0 && !wasMin && wrapped))
       
  1641                 ? minimum : maximum;
       
  1642         } else if (wrapped && (maxcmp > 0 || mincmp < 0)) {
       
  1643             v = ((wasMax && steps > 0) || (!wasMin && steps < 0)) ? minimum : maximum;
       
  1644         } else if (mincmp < 0) {
       
  1645             v = (!wasMax && !wasMin ? minimum : maximum);
       
  1646         }
       
  1647     }
       
  1648 
       
  1649     return v;
       
  1650 }
       
  1651 
       
  1652 /*!
       
  1653     \internal
       
  1654 
       
  1655     Sets the value of the spin box to \a val. Depending on the value
       
  1656     of \a ep it will also emit signals.
       
  1657 */
       
  1658 
       
  1659 void QAbstractSpinBoxPrivate::setValue(const QVariant &val, EmitPolicy ep,
       
  1660                                        bool doUpdate)
       
  1661 {
       
  1662     Q_Q(QAbstractSpinBox);
       
  1663     const QVariant old = value;
       
  1664     value = bound(val);
       
  1665     pendingEmit = false;
       
  1666     cleared = false;
       
  1667     if (doUpdate) {
       
  1668         updateEdit();
       
  1669     }
       
  1670     q->update();
       
  1671 
       
  1672     if (ep == AlwaysEmit || (ep == EmitIfChanged && old != value)) {
       
  1673         emitSignals(ep, old);
       
  1674     }
       
  1675 }
       
  1676 
       
  1677 /*!
       
  1678     \internal
       
  1679 
       
  1680     Updates the line edit to reflect the current value of the spin box.
       
  1681 */
       
  1682 
       
  1683 void QAbstractSpinBoxPrivate::updateEdit()
       
  1684 {
       
  1685     Q_Q(QAbstractSpinBox);
       
  1686     if (type == QVariant::Invalid)
       
  1687         return;
       
  1688     const QString newText = specialValue() ? specialValueText : prefix + textFromValue(value) + suffix;
       
  1689     if (newText == edit->displayText() || cleared)
       
  1690         return;
       
  1691 
       
  1692     const bool empty = edit->text().isEmpty();
       
  1693     int cursor = edit->cursorPosition();
       
  1694     int selsize = edit->selectedText().size();
       
  1695     const bool sb = edit->blockSignals(true);
       
  1696     edit->setText(newText);
       
  1697 
       
  1698     if (!specialValue()) {
       
  1699         cursor = qBound(prefix.size(), cursor, edit->displayText().size() - suffix.size());
       
  1700 
       
  1701         if (selsize > 0) {
       
  1702             edit->setSelection(cursor, selsize);
       
  1703         } else {
       
  1704             edit->setCursorPosition(empty ? prefix.size() : cursor);
       
  1705         }
       
  1706     }
       
  1707     edit->blockSignals(sb);
       
  1708     q->update();
       
  1709 }
       
  1710 
       
  1711 /*!
       
  1712     \internal
       
  1713 
       
  1714     Convenience function to set min/max values.
       
  1715 */
       
  1716 
       
  1717 void QAbstractSpinBoxPrivate::setRange(const QVariant &min, const QVariant &max)
       
  1718 {
       
  1719     Q_Q(QAbstractSpinBox);
       
  1720 
       
  1721     clearCache();
       
  1722     minimum = min;
       
  1723     maximum = (variantCompare(min, max) < 0 ? max : min);
       
  1724     cachedSizeHint = QSize(); // minimumSizeHint doesn't care about min/max
       
  1725 
       
  1726     reset();
       
  1727     if (!(bound(value) == value)) {
       
  1728         setValue(bound(value), EmitIfChanged);
       
  1729     } else if (value == minimum && !specialValueText.isEmpty()) {
       
  1730         updateEdit();
       
  1731     }
       
  1732 
       
  1733     q->updateGeometry();
       
  1734 }
       
  1735 
       
  1736 /*!
       
  1737     \internal
       
  1738 
       
  1739     Convenience function to get a variant of the right type.
       
  1740 */
       
  1741 
       
  1742 QVariant QAbstractSpinBoxPrivate::getZeroVariant() const
       
  1743 {
       
  1744     QVariant ret;
       
  1745     switch (type) {
       
  1746     case QVariant::Int: ret = QVariant((int)0); break;
       
  1747     case QVariant::Double: ret = QVariant((double)0.0); break;
       
  1748     default: break;
       
  1749     }
       
  1750     return ret;
       
  1751 }
       
  1752 
       
  1753 /*!
       
  1754     \internal
       
  1755 
       
  1756     Virtual method called that calls the public textFromValue()
       
  1757     functions in the subclasses. Needed to change signature from
       
  1758     QVariant to int/double/QDateTime etc. Used when needing to display
       
  1759     a value textually.
       
  1760 
       
  1761     This method is reimeplemented in the various subclasses.
       
  1762 */
       
  1763 
       
  1764 QString QAbstractSpinBoxPrivate::textFromValue(const QVariant &) const
       
  1765 {
       
  1766     return QString();
       
  1767 }
       
  1768 
       
  1769 /*!
       
  1770     \internal
       
  1771 
       
  1772     Virtual method called that calls the public valueFromText()
       
  1773     functions in the subclasses. Needed to change signature from
       
  1774     QVariant to int/double/QDateTime etc. Used when needing to
       
  1775     interpret a string as another type.
       
  1776 
       
  1777     This method is reimeplemented in the various subclasses.
       
  1778 */
       
  1779 
       
  1780 QVariant QAbstractSpinBoxPrivate::valueFromText(const QString &) const
       
  1781 {
       
  1782     return QVariant();
       
  1783 }
       
  1784 /*!
       
  1785     \internal
       
  1786 
       
  1787     Interprets text and emits signals. Called when the spinbox needs
       
  1788     to interpret the text on the lineedit.
       
  1789 */
       
  1790 
       
  1791 void QAbstractSpinBoxPrivate::interpret(EmitPolicy ep)
       
  1792 {
       
  1793     Q_Q(QAbstractSpinBox);
       
  1794     if (type == QVariant::Invalid || cleared)
       
  1795         return;
       
  1796 
       
  1797     QVariant v = getZeroVariant();
       
  1798     bool doInterpret = true;
       
  1799     QString tmp = edit->displayText();
       
  1800     int pos = edit->cursorPosition();
       
  1801     const int oldpos = pos;
       
  1802 
       
  1803     if (q->validate(tmp, pos) != QValidator::Acceptable) {
       
  1804         const QString copy = tmp;
       
  1805         q->fixup(tmp);
       
  1806         QASBDEBUG() << "QAbstractSpinBoxPrivate::interpret() text '"
       
  1807                     << edit->displayText()
       
  1808                     << "' >> '" << copy << '\''
       
  1809                     << "' >> '" << tmp << '\'';
       
  1810 
       
  1811         doInterpret = tmp != copy && (q->validate(tmp, pos) == QValidator::Acceptable);
       
  1812         if (!doInterpret) {
       
  1813             v = (correctionMode == QAbstractSpinBox::CorrectToNearestValue
       
  1814                  ? variantBound(minimum, v, maximum) : value);
       
  1815         }
       
  1816     }
       
  1817     if (doInterpret) {
       
  1818         v = valueFromText(tmp);
       
  1819     }
       
  1820     clearCache();
       
  1821     setValue(v, ep, true);
       
  1822     if (oldpos != pos)
       
  1823         edit->setCursorPosition(pos);
       
  1824 }
       
  1825 
       
  1826 void QAbstractSpinBoxPrivate::clearCache() const
       
  1827 {
       
  1828     cachedText.clear();
       
  1829     cachedValue.clear();
       
  1830     cachedState = QValidator::Acceptable;
       
  1831 }
       
  1832 
       
  1833 
       
  1834 // --- QSpinBoxValidator ---
       
  1835 
       
  1836 /*!
       
  1837     \internal
       
  1838     Constructs a QSpinBoxValidator object
       
  1839 */
       
  1840 
       
  1841 QSpinBoxValidator::QSpinBoxValidator(QAbstractSpinBox *qp, QAbstractSpinBoxPrivate *dp)
       
  1842     : QValidator(qp), qptr(qp), dptr(dp)
       
  1843 {
       
  1844     setObjectName(QLatin1String("qt_spinboxvalidator"));
       
  1845 }
       
  1846 
       
  1847 /*!
       
  1848     \internal
       
  1849 
       
  1850     Checks for specialValueText, prefix, suffix and calls
       
  1851     the virtual QAbstractSpinBox::validate function.
       
  1852 */
       
  1853 
       
  1854 QValidator::State QSpinBoxValidator::validate(QString &input, int &pos) const
       
  1855 {
       
  1856     if (dptr->specialValueText.size() > 0 && input == dptr->specialValueText)
       
  1857         return QValidator::Acceptable;
       
  1858 
       
  1859     if (!dptr->prefix.isEmpty() && !input.startsWith(dptr->prefix))
       
  1860         input.prepend(dptr->prefix);
       
  1861 
       
  1862     if (!dptr->suffix.isEmpty() && !input.endsWith(dptr->suffix))
       
  1863         input.append(dptr->suffix);
       
  1864 
       
  1865     return qptr->validate(input, pos);
       
  1866 }
       
  1867 /*!
       
  1868     \internal
       
  1869     Calls the virtual QAbstractSpinBox::fixup function.
       
  1870 */
       
  1871 
       
  1872 void QSpinBoxValidator::fixup(QString &input) const
       
  1873 {
       
  1874     qptr->fixup(input);
       
  1875 }
       
  1876 
       
  1877 // --- global ---
       
  1878 
       
  1879 /*!
       
  1880     \internal
       
  1881     Adds two variants together and returns the result.
       
  1882 */
       
  1883 
       
  1884 QVariant operator+(const QVariant &arg1, const QVariant &arg2)
       
  1885 {
       
  1886     QVariant ret;
       
  1887     if (arg1.type() != arg2.type())
       
  1888         qWarning("QAbstractSpinBox: Internal error: Different types (%s vs %s) (%s:%d)",
       
  1889                  arg1.typeName(), arg2.typeName(), __FILE__, __LINE__);
       
  1890     switch (arg1.type()) {
       
  1891     case QVariant::Int: ret = QVariant(arg1.toInt() + arg2.toInt()); break;
       
  1892     case QVariant::Double: ret = QVariant(arg1.toDouble() + arg2.toDouble()); break;
       
  1893     case QVariant::DateTime: {
       
  1894         QDateTime a2 = arg2.toDateTime();
       
  1895         QDateTime a1 = arg1.toDateTime().addDays(QDATETIMEEDIT_DATETIME_MIN.daysTo(a2));
       
  1896         a1.setTime(a1.time().addMSecs(QTime().msecsTo(a2.time())));
       
  1897         ret = QVariant(a1);
       
  1898     }
       
  1899     default: break;
       
  1900     }
       
  1901     return ret;
       
  1902 }
       
  1903 
       
  1904 
       
  1905 /*!
       
  1906     \internal
       
  1907     Subtracts two variants and returns the result.
       
  1908 */
       
  1909 
       
  1910 QVariant operator-(const QVariant &arg1, const QVariant &arg2)
       
  1911 {
       
  1912     QVariant ret;
       
  1913     if (arg1.type() != arg2.type())
       
  1914         qWarning("QAbstractSpinBox: Internal error: Different types (%s vs %s) (%s:%d)",
       
  1915                  arg1.typeName(), arg2.typeName(), __FILE__, __LINE__);
       
  1916     switch (arg1.type()) {
       
  1917     case QVariant::Int: ret = QVariant(arg1.toInt() - arg2.toInt()); break;
       
  1918     case QVariant::Double: ret = QVariant(arg1.toDouble() - arg2.toDouble()); break;
       
  1919     case QVariant::DateTime: {
       
  1920         QDateTime a1 = arg1.toDateTime();
       
  1921         QDateTime a2 = arg2.toDateTime();
       
  1922         int days = a2.daysTo(a1);
       
  1923         int secs = a2.secsTo(a1);
       
  1924         int msecs = qMax(0, a1.time().msec() - a2.time().msec());
       
  1925         if (days < 0 || secs < 0 || msecs < 0) {
       
  1926             ret = arg1;
       
  1927         } else {
       
  1928             QDateTime dt = a2.addDays(days).addSecs(secs);
       
  1929             if (msecs > 0)
       
  1930                 dt.setTime(dt.time().addMSecs(msecs));
       
  1931             ret = QVariant(dt);
       
  1932         }
       
  1933     }
       
  1934     default: break;
       
  1935     }
       
  1936     return ret;
       
  1937 }
       
  1938 
       
  1939 /*!
       
  1940     \internal
       
  1941     Multiplies \a arg1 by \a multiplier and returns the result.
       
  1942 */
       
  1943 
       
  1944 QVariant operator*(const QVariant &arg1, double multiplier)
       
  1945 {
       
  1946     QVariant ret;
       
  1947 
       
  1948     switch (arg1.type()) {
       
  1949     case QVariant::Int: ret = QVariant((int)(arg1.toInt() * multiplier)); break;
       
  1950     case QVariant::Double: ret = QVariant(arg1.toDouble() * multiplier); break;
       
  1951     case QVariant::DateTime: {
       
  1952         double days = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDateTime().date()) * multiplier;
       
  1953         int daysInt = (int)days;
       
  1954         days -= daysInt;
       
  1955         long msecs = (long)((QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) * multiplier)
       
  1956                             + (days * (24 * 3600 * 1000)));
       
  1957         ret = QDateTime(QDate().addDays(int(days)), QTime().addMSecs(msecs));
       
  1958         break;
       
  1959     }
       
  1960     default: ret = arg1; break;
       
  1961     }
       
  1962 
       
  1963     return ret;
       
  1964 }
       
  1965 
       
  1966 
       
  1967 
       
  1968 double operator/(const QVariant &arg1, const QVariant &arg2)
       
  1969 {
       
  1970     double a1 = 0;
       
  1971     double a2 = 0;
       
  1972 
       
  1973     switch (arg1.type()) {
       
  1974     case QVariant::Int:
       
  1975         a1 = (double)arg1.toInt();
       
  1976         a2 = (double)arg2.toInt();
       
  1977         break;
       
  1978     case QVariant::Double:
       
  1979         a1 = arg1.toDouble();
       
  1980         a2 = arg2.toDouble();
       
  1981         break;
       
  1982     case QVariant::DateTime:
       
  1983         a1 = QDATETIMEEDIT_DATE_MIN.daysTo(arg1.toDate());
       
  1984         a2 = QDATETIMEEDIT_DATE_MIN.daysTo(arg2.toDate());
       
  1985         a1 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg1.toDateTime().time()) / (long)(3600 * 24 * 1000);
       
  1986         a2 += (double)QDATETIMEEDIT_TIME_MIN.msecsTo(arg2.toDateTime().time()) / (long)(3600 * 24 * 1000);
       
  1987     default: break;
       
  1988     }
       
  1989 
       
  1990     return (a1 != 0 && a2 != 0) ? (a1 / a2) : 0.0;
       
  1991 }
       
  1992 
       
  1993 int QAbstractSpinBoxPrivate::variantCompare(const QVariant &arg1, const QVariant &arg2)
       
  1994 {
       
  1995     switch (arg2.type()) {
       
  1996     case QVariant::Date:
       
  1997         Q_ASSERT_X(arg1.type() == QVariant::Date, "QAbstractSpinBoxPrivate::variantCompare",
       
  1998                    qPrintable(QString::fromAscii("Internal error 1 (%1)").
       
  1999                               arg(QString::fromAscii(arg1.typeName()))));
       
  2000         if (arg1.toDate() == arg2.toDate()) {
       
  2001             return 0;
       
  2002         } else if (arg1.toDate() < arg2.toDate()) {
       
  2003             return -1;
       
  2004         } else {
       
  2005             return 1;
       
  2006         }
       
  2007     case QVariant::Time:
       
  2008         Q_ASSERT_X(arg1.type() == QVariant::Time, "QAbstractSpinBoxPrivate::variantCompare",
       
  2009                    qPrintable(QString::fromAscii("Internal error 2 (%1)").
       
  2010                               arg(QString::fromAscii(arg1.typeName()))));
       
  2011         if (arg1.toTime() == arg2.toTime()) {
       
  2012             return 0;
       
  2013         } else if (arg1.toTime() < arg2.toTime()) {
       
  2014             return -1;
       
  2015         } else {
       
  2016             return 1;
       
  2017         }
       
  2018 
       
  2019 
       
  2020     case QVariant::DateTime:
       
  2021         if (arg1.toDateTime() == arg2.toDateTime()) {
       
  2022             return 0;
       
  2023         } else if (arg1.toDateTime() < arg2.toDateTime()) {
       
  2024             return -1;
       
  2025         } else {
       
  2026             return 1;
       
  2027         }
       
  2028     case QVariant::Int:
       
  2029         if (arg1.toInt() == arg2.toInt()) {
       
  2030             return 0;
       
  2031         } else if (arg1.toInt() < arg2.toInt()) {
       
  2032             return -1;
       
  2033         } else {
       
  2034             return 1;
       
  2035         }
       
  2036     case QVariant::Double:
       
  2037         if (arg1.toDouble() == arg2.toDouble()) {
       
  2038             return 0;
       
  2039         } else if (arg1.toDouble() < arg2.toDouble()) {
       
  2040             return -1;
       
  2041         } else {
       
  2042             return 1;
       
  2043         }
       
  2044     case QVariant::Invalid:
       
  2045         if (arg2.type() == QVariant::Invalid)
       
  2046             return 0;
       
  2047     default:
       
  2048         Q_ASSERT_X(0, "QAbstractSpinBoxPrivate::variantCompare",
       
  2049                    qPrintable(QString::fromAscii("Internal error 3 (%1 %2)").
       
  2050                               arg(QString::fromAscii(arg1.typeName())).
       
  2051                               arg(QString::fromAscii(arg2.typeName()))));
       
  2052     }
       
  2053     return -2;
       
  2054 }
       
  2055 
       
  2056 QVariant QAbstractSpinBoxPrivate::variantBound(const QVariant &min,
       
  2057                                                const QVariant &value,
       
  2058                                                const QVariant &max)
       
  2059 {
       
  2060     Q_ASSERT(variantCompare(min, max) <= 0);
       
  2061     if (variantCompare(min, value) < 0) {
       
  2062         const int compMax = variantCompare(value, max);
       
  2063         return (compMax < 0 ? value : max);
       
  2064     } else {
       
  2065         return min;
       
  2066     }
       
  2067 }
       
  2068 
       
  2069 
       
  2070 QT_END_NAMESPACE
       
  2071 
       
  2072 #include "moc_qabstractspinbox.cpp"
       
  2073 
       
  2074 #endif // QT_NO_SPINBOX