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