summaryrefslogtreecommitdiff
path: root/src/gui/widgets/qspinbox.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:34:13 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:34:13 +0100
commit67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch)
tree1dbf50b3dff8d5ca7e9344733968c72704eb15ff /src/gui/widgets/qspinbox.cpp
downloadqt4-tools-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz
Long live Qt!
Diffstat (limited to 'src/gui/widgets/qspinbox.cpp')
-rw-r--r--src/gui/widgets/qspinbox.cpp1536
1 files changed, 1536 insertions, 0 deletions
diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp
new file mode 100644
index 0000000000..c691eaf434
--- /dev/null
+++ b/src/gui/widgets/qspinbox.cpp
@@ -0,0 +1,1536 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qabstractspinbox_p.h>
+#include <qspinbox.h>
+
+#ifndef QT_NO_SPINBOX
+
+#include <qlineedit.h>
+#include <qlocale.h>
+#include <qvalidator.h>
+#include <qdebug.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define QSPINBOX_QSBDEBUG
+#ifdef QSPINBOX_QSBDEBUG
+# define QSBDEBUG qDebug
+#else
+# define QSBDEBUG if (false) qDebug
+#endif
+
+static bool isIntermediateValueHelper(qint64 num, qint64 minimum, qint64 maximum, qint64 *match = 0);
+
+class QSpinBoxPrivate : public QAbstractSpinBoxPrivate
+{
+ Q_DECLARE_PUBLIC(QSpinBox)
+public:
+ QSpinBoxPrivate(QWidget *parent = 0);
+ void emitSignals(EmitPolicy ep, const QVariant &);
+
+ virtual QVariant valueFromText(const QString &n) const;
+ virtual QString textFromValue(const QVariant &n) const;
+ QVariant validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const;
+ bool isIntermediateValue(const QString &str) const;
+ QChar thousand;
+
+ inline void init() {
+ setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
+ }
+};
+
+class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate
+{
+ Q_DECLARE_PUBLIC(QDoubleSpinBox)
+public:
+ QDoubleSpinBoxPrivate(QWidget *parent = 0);
+ void emitSignals(EmitPolicy ep, const QVariant &);
+ bool isIntermediateValue(const QString &str) const;
+
+ virtual QVariant valueFromText(const QString &n) const;
+ virtual QString textFromValue(const QVariant &n) const;
+ QVariant validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const;
+ double round(double input) const;
+ // variables
+ int decimals;
+ QChar delimiter, thousand;
+};
+
+
+/*!
+ \class QSpinBox
+ \brief The QSpinBox class provides a spin box widget.
+
+ \ingroup basicwidgets
+ \mainclass
+
+ QSpinBox is designed to handle integers and discrete sets of
+ values (e.g., month names); use QDoubleSpinBox for floating point
+ values.
+
+ QSpinBox allows the user to choose a value by clicking the up/down
+ buttons or pressing up/down on the keyboard to increase/decrease
+ the value currently displayed. The user can also type the value in
+ manually. The spin box supports integer values but can be extended to
+ use different strings with validate(), textFromValue() and valueFromText().
+
+ Every time the value changes QSpinBox emits the valueChanged()
+ signals. The current value can be fetched with value() and set
+ with setValue().
+
+ Clicking the up/down buttons or using the keyboard accelerator's
+ up and down arrows will increase or decrease the current value in
+ steps of size singleStep(). If you want to change this behaviour you
+ can reimplement the virtual function stepBy(). The minimum and
+ maximum value and the step size can be set using one of the
+ constructors, and can be changed later with setMinimum(),
+ setMaximum() and setSingleStep().
+
+ Most spin boxes are directional, but QSpinBox can also operate as
+ a circular spin box, i.e. if the range is 0-99 and the current
+ value is 99, clicking "up" will give 0 if wrapping() is set to
+ true. Use setWrapping() if you want circular behavior.
+
+ The displayed value can be prepended and appended with arbitrary
+ strings indicating, for example, currency or the unit of
+ measurement. See setPrefix() and setSuffix(). The text in the spin
+ box is retrieved with text() (which includes any prefix() and
+ suffix()), or with cleanText() (which has no prefix(), no suffix()
+ and no leading or trailing whitespace).
+
+ It is often desirable to give the user a special (often default)
+ choice in addition to the range of numeric values. See
+ setSpecialValueText() for how to do this with QSpinBox.
+
+ \table 100%
+ \row \o \inlineimage windowsxp-spinbox.png Screenshot of a Windows XP spin box
+ \o A spin box shown in the \l{Windows XP Style Widget Gallery}{Windows XP widget style}.
+ \row \o \inlineimage plastique-spinbox.png Screenshot of a Plastique spin box
+ \o A spin box shown in the \l{Plastique Style Widget Gallery}{Plastique widget style}.
+ \row \o \inlineimage macintosh-spinbox.png Screenshot of a Macintosh spin box
+ \o A spin box shown in the \l{Macintosh Style Widget Gallery}{Macintosh widget style}.
+ \endtable
+
+ \section1 Subclassing QSpinBox
+
+ If using prefix(), suffix(), and specialValueText() don't provide
+ enough control, you subclass QSpinBox and reimplement
+ valueFromText() and textFromValue(). For example, here's the code
+ for a custom spin box that allows the user to enter icon sizes
+ (e.g., "32 x 32"):
+
+ \snippet examples/widgets/icons/iconsizespinbox.cpp 1
+ \codeline
+ \snippet examples/widgets/icons/iconsizespinbox.cpp 2
+
+ See the \l{widgets/icons}{Icons} example for the full source
+ code.
+
+ \sa QDoubleSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
+*/
+
+/*!
+ \fn void QSpinBox::valueChanged(int i)
+
+ This signal is emitted whenever the spin box's value is changed.
+ The new value's integer value is passed in \a i.
+*/
+
+/*!
+ \fn void QSpinBox::valueChanged(const QString &text)
+
+ \overload
+
+ The new value is passed literally in \a text with no prefix() or
+ suffix().
+*/
+
+/*!
+ Constructs a spin box with 0 as minimum value and 99 as maximum value, a
+ step value of 1. The value is initially set to 0. It is parented to \a
+ parent.
+
+ \sa setMinimum(), setMaximum(), setSingleStep()
+*/
+
+QSpinBox::QSpinBox(QWidget *parent)
+ : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
+{
+ Q_D(QSpinBox);
+ d->init();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QSpinBox::QSpinBox(QWidget *parent, const char *name)
+ : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
+{
+ Q_D(QSpinBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Use one of the constructors that doesn't take the \a name
+ argument and then use setObjectName() instead.
+*/
+QSpinBox::QSpinBox(int minimum, int maximum, int step, QWidget *parent, const char *name)
+ : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
+{
+ Q_D(QSpinBox);
+ d->minimum = QVariant(qMin<int>(minimum, maximum));
+ d->maximum = QVariant(qMax<int>(minimum, maximum));
+ d->singleStep = QVariant(step);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+#endif
+
+/*!
+ \property QSpinBox::value
+ \brief the value of the spin box
+
+ setValue() will emit valueChanged() if the new value is different
+ from the old one.
+*/
+
+int QSpinBox::value() const
+{
+ Q_D(const QSpinBox);
+ return d->value.toInt();
+}
+
+void QSpinBox::setValue(int value)
+{
+ Q_D(QSpinBox);
+ d->setValue(QVariant(value), EmitIfChanged);
+}
+
+/*!
+ \property QSpinBox::prefix
+ \brief the spin box's prefix
+
+ The prefix is prepended to the start of the displayed value.
+ Typical use is to display a unit of measurement or a currency
+ symbol. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 0
+
+ To turn off the prefix display, set this property to an empty
+ string. The default is no prefix. The prefix is not displayed when
+ value() == minimum() and specialValueText() is set.
+
+ If no prefix is set, prefix() returns an empty string.
+
+ \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QSpinBox::prefix() const
+{
+ Q_D(const QSpinBox);
+ return d->prefix;
+}
+
+void QSpinBox::setPrefix(const QString &prefix)
+{
+ Q_D(QSpinBox);
+
+ d->prefix = prefix;
+ d->updateEdit();
+}
+
+/*!
+ \property QSpinBox::suffix
+ \brief the suffix of the spin box
+
+ The suffix is appended to the end of the displayed value. Typical
+ use is to display a unit of measurement or a currency symbol. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 1
+
+ To turn off the suffix display, set this property to an empty
+ string. The default is no suffix. The suffix is not displayed for
+ the minimum() if specialValueText() is set.
+
+ If no suffix is set, suffix() returns an empty string.
+
+ \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QSpinBox::suffix() const
+{
+ Q_D(const QSpinBox);
+
+ return d->suffix;
+}
+
+void QSpinBox::setSuffix(const QString &suffix)
+{
+ Q_D(QSpinBox);
+
+ d->suffix = suffix;
+ d->updateEdit();
+}
+
+/*!
+ \property QSpinBox::cleanText
+
+ \brief the text of the spin box excluding any prefix, suffix,
+ or leading or trailing whitespace.
+
+ \sa text, QSpinBox::prefix, QSpinBox::suffix
+*/
+
+QString QSpinBox::cleanText() const
+{
+ Q_D(const QSpinBox);
+
+ return d->stripped(d->edit->displayText());
+}
+
+
+/*!
+ \property QSpinBox::singleStep
+ \brief the step value
+
+ When the user uses the arrows to change the spin box's value the
+ value will be incremented/decremented by the amount of the
+ singleStep. The default value is 1. Setting a singleStep value of
+ less than 0 does nothing.
+*/
+
+int QSpinBox::singleStep() const
+{
+ Q_D(const QSpinBox);
+
+ return d->singleStep.toInt();
+}
+
+void QSpinBox::setSingleStep(int value)
+{
+ Q_D(QSpinBox);
+ if (value >= 0) {
+ d->singleStep = QVariant(value);
+ d->updateEdit();
+ }
+}
+
+/*!
+ \property QSpinBox::minimum
+
+ \brief the minimum value of the spin box
+
+ When setting this property the \l maximum is adjusted
+ if necessary to ensure that the range remains valid.
+
+ The default minimum value is 0.
+
+ \sa setRange() specialValueText
+*/
+
+int QSpinBox::minimum() const
+{
+ Q_D(const QSpinBox);
+
+ return d->minimum.toInt();
+}
+
+void QSpinBox::setMinimum(int minimum)
+{
+ Q_D(QSpinBox);
+ const QVariant m(minimum);
+ d->setRange(m, (d->variantCompare(d->maximum, m) > 0 ? d->maximum : m));
+}
+
+/*!
+ \property QSpinBox::maximum
+
+ \brief the maximum value of the spin box
+
+ When setting this property the \l minimum is adjusted
+ if necessary, to ensure that the range remains valid.
+
+ The default maximum value is 99.
+
+ \sa setRange() specialValueText
+
+*/
+
+int QSpinBox::maximum() const
+{
+ Q_D(const QSpinBox);
+
+ return d->maximum.toInt();
+}
+
+void QSpinBox::setMaximum(int maximum)
+{
+ Q_D(QSpinBox);
+ const QVariant m(maximum);
+ d->setRange((d->variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
+}
+
+/*!
+ Convenience function to set the \a minimum, and \a maximum values
+ with a single function call.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 2
+ is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 3
+
+ \sa minimum maximum
+*/
+
+void QSpinBox::setRange(int minimum, int maximum)
+{
+ Q_D(QSpinBox);
+ d->setRange(QVariant(minimum), QVariant(maximum));
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs
+ to display the given \a value. The default implementation returns
+ a string containing \a value printed in the standard way using
+ QWidget::locale().toString(). Reimplementations may return anything. (See
+ the example in the detailed description.)
+
+ Note: QSpinBox does not call this function for specialValueText()
+ and that neither prefix() nor suffix() should be included in the
+ return value.
+
+ If you reimplement this, you may also need to reimplement
+ valueFromText() and validate()
+
+ \sa valueFromText(), validate()
+*/
+
+QString QSpinBox::textFromValue(int value) const
+{
+ Q_D(const QSpinBox);
+ QString str = locale().toString(value);
+ if (qAbs(value) >= 1000 || value == INT_MIN) {
+ str.remove(d->thousand);
+ }
+
+ return str;
+}
+
+/*!
+ \fn int QSpinBox::valueFromText(const QString &text) const
+
+ This virtual function is used by the spin box whenever it needs to
+ interpret \a text entered by the user as a value.
+
+ Subclasses that need to display spin box values in a non-numeric
+ way need to reimplement this function.
+
+ Note: QSpinBox handles specialValueText() separately; this
+ function is only concerned with the other values.
+
+ \sa textFromValue(), validate()
+*/
+
+int QSpinBox::valueFromText(const QString &text) const
+{
+ Q_D(const QSpinBox);
+
+ QString copy = text;
+ int pos = d->edit->cursorPosition();
+ QValidator::State state = QValidator::Acceptable;
+ return d->validateAndInterpret(copy, pos, state).toInt();
+}
+
+/*!
+ \reimp
+*/
+QValidator::State QSpinBox::validate(QString &text, int &pos) const
+{
+ Q_D(const QSpinBox);
+
+ QValidator::State state;
+ d->validateAndInterpret(text, pos, state);
+ return state;
+}
+
+
+/*!
+ \reimp
+*/
+void QSpinBox::fixup(QString &input) const
+{
+ Q_D(const QSpinBox);
+
+ input.remove(d->thousand);
+}
+
+
+// --- QDoubleSpinBox ---
+
+/*!
+ \class QDoubleSpinBox
+ \brief The QDoubleSpinBox class provides a spin box widget that
+ takes doubles.
+
+ \ingroup basicwidgets
+ \mainclass
+
+ QDoubleSpinBox allows the user to choose a value by clicking the
+ up and down buttons or by pressing Up or Down on the keyboard to
+ increase or decrease the value currently displayed. The user can
+ also type the value in manually. The spin box supports double
+ values but can be extended to use different strings with
+ validate(), textFromValue() and valueFromText().
+
+ Every time the value changes QDoubleSpinBox emits the
+ valueChanged() signal. The current value can be fetched with
+ value() and set with setValue().
+
+ Note: QDoubleSpinBox will round numbers so they can be displayed
+ with the current precision. In a QDoubleSpinBox with decimals set
+ to 2, calling setValue(2.555) will cause value() to return 2.56.
+
+ Clicking the up and down buttons or using the keyboard accelerator's
+ Up and Down arrows will increase or decrease the current value in
+ steps of size singleStep(). If you want to change this behavior you
+ can reimplement the virtual function stepBy(). The minimum and
+ maximum value and the step size can be set using one of the
+ constructors, and can be changed later with setMinimum(),
+ setMaximum() and setSingleStep(). The spinbox has a default
+ precision of 2 decimal places but this can be changed using
+ setDecimals().
+
+ Most spin boxes are directional, but QDoubleSpinBox can also
+ operate as a circular spin box, i.e. if the range is 0.0-99.9 and
+ the current value is 99.9, clicking "up" will give 0 if wrapping()
+ is set to true. Use setWrapping() if you want circular behavior.
+
+ The displayed value can be prepended and appended with arbitrary
+ strings indicating, for example, currency or the unit of
+ measurement. See setPrefix() and setSuffix(). The text in the spin
+ box is retrieved with text() (which includes any prefix() and
+ suffix()), or with cleanText() (which has no prefix(), no suffix()
+ and no leading or trailing whitespace).
+
+ It is often desirable to give the user a special (often default)
+ choice in addition to the range of numeric values. See
+ setSpecialValueText() for how to do this with QDoubleSpinBox.
+
+ \sa QSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
+*/
+
+/*!
+ \fn void QDoubleSpinBox::valueChanged(double d);
+
+ This signal is emitted whenever the spin box's value is changed.
+ The new value is passed in \a d.
+*/
+
+/*!
+ \fn void QDoubleSpinBox::valueChanged(const QString &text);
+
+ \overload
+
+ The new value is passed literally in \a text with no prefix() or
+ suffix().
+*/
+
+/*!
+ Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
+ a step value of 1.0 and a precision of 2 decimal places. The value is
+ initially set to 0.00. The spin box has the given \a parent.
+
+ \sa setMinimum(), setMaximum(), setSingleStep()
+*/
+QDoubleSpinBox::QDoubleSpinBox(QWidget *parent)
+ : QAbstractSpinBox(*new QDoubleSpinBoxPrivate(parent), parent)
+{
+}
+
+/*!
+ \property QDoubleSpinBox::value
+ \brief the value of the spin box
+
+ setValue() will emit valueChanged() if the new value is different
+ from the old one.
+
+ Note: The value will be rounded so it can be displayed with the
+ current setting of decimals.
+
+ \sa decimals
+*/
+double QDoubleSpinBox::value() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->value.toDouble();
+}
+
+void QDoubleSpinBox::setValue(double value)
+{
+ Q_D(QDoubleSpinBox);
+ QVariant v(d->round(value));
+ d->setValue(v, EmitIfChanged);
+}
+/*!
+ \property QDoubleSpinBox::prefix
+ \brief the spin box's prefix
+
+ The prefix is prepended to the start of the displayed value.
+ Typical use is to display a unit of measurement or a currency
+ symbol. For example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 4
+
+ To turn off the prefix display, set this property to an empty
+ string. The default is no prefix. The prefix is not displayed when
+ value() == minimum() and specialValueText() is set.
+
+ If no prefix is set, prefix() returns an empty string.
+
+ \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QDoubleSpinBox::prefix() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->prefix;
+}
+
+void QDoubleSpinBox::setPrefix(const QString &prefix)
+{
+ Q_D(QDoubleSpinBox);
+
+ d->prefix = prefix;
+ d->updateEdit();
+}
+
+/*!
+ \property QDoubleSpinBox::suffix
+ \brief the suffix of the spin box
+
+ The suffix is appended to the end of the displayed value. Typical
+ use is to display a unit of measurement or a currency symbol. For
+ example:
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 5
+
+ To turn off the suffix display, set this property to an empty
+ string. The default is no suffix. The suffix is not displayed for
+ the minimum() if specialValueText() is set.
+
+ If no suffix is set, suffix() returns an empty string.
+
+ \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
+*/
+
+QString QDoubleSpinBox::suffix() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->suffix;
+}
+
+void QDoubleSpinBox::setSuffix(const QString &suffix)
+{
+ Q_D(QDoubleSpinBox);
+
+ d->suffix = suffix;
+ d->updateEdit();
+}
+
+/*!
+ \property QDoubleSpinBox::cleanText
+
+ \brief the text of the spin box excluding any prefix, suffix,
+ or leading or trailing whitespace.
+
+ \sa text, QDoubleSpinBox::prefix, QDoubleSpinBox::suffix
+*/
+
+QString QDoubleSpinBox::cleanText() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->stripped(d->edit->displayText());
+}
+
+/*!
+ \property QDoubleSpinBox::singleStep
+ \brief the step value
+
+ When the user uses the arrows to change the spin box's value the
+ value will be incremented/decremented by the amount of the
+ singleStep. The default value is 1.0. Setting a singleStep value
+ of less than 0 does nothing.
+*/
+double QDoubleSpinBox::singleStep() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->singleStep.toDouble();
+}
+
+void QDoubleSpinBox::setSingleStep(double value)
+{
+ Q_D(QDoubleSpinBox);
+
+ if (value >= 0) {
+ d->singleStep = value;
+ d->updateEdit();
+ }
+}
+
+/*!
+ \property QDoubleSpinBox::minimum
+
+ \brief the minimum value of the spin box
+
+ When setting this property the \l maximum is adjusted
+ if necessary to ensure that the range remains valid.
+
+ The default minimum value is 0.0.
+
+ Note: The minimum value will be rounded to match the decimals
+ property.
+
+ \sa decimals, setRange() specialValueText
+*/
+
+double QDoubleSpinBox::minimum() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->minimum.toDouble();
+}
+
+void QDoubleSpinBox::setMinimum(double minimum)
+{
+ Q_D(QDoubleSpinBox);
+ const QVariant m(d->round(minimum));
+ d->setRange(m, (d->variantCompare(d->maximum, m) > 0 ? d->maximum : m));
+}
+
+/*!
+ \property QDoubleSpinBox::maximum
+
+ \brief the maximum value of the spin box
+
+ When setting this property the \l minimum is adjusted
+ if necessary, to ensure that the range remains valid.
+
+ The default maximum value is 99.99.
+
+ Note: The maximum value will be rounded to match the decimals
+ property.
+
+ \sa decimals, setRange()
+*/
+
+double QDoubleSpinBox::maximum() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->maximum.toDouble();
+}
+
+void QDoubleSpinBox::setMaximum(double maximum)
+{
+ Q_D(QDoubleSpinBox);
+ const QVariant m(d->round(maximum));
+ d->setRange((d->variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
+}
+
+/*!
+ Convenience function to set the \a minimum and \a maximum values
+ with a single function call.
+
+ Note: The maximum and minimum values will be rounded to match the
+ decimals property.
+
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 6
+ is equivalent to:
+ \snippet doc/src/snippets/code/src_gui_widgets_qspinbox.cpp 7
+
+ \sa minimum maximum
+*/
+
+void QDoubleSpinBox::setRange(double minimum, double maximum)
+{
+ Q_D(QDoubleSpinBox);
+ d->setRange(QVariant(d->round(minimum)), QVariant(d->round(maximum)));
+}
+
+/*!
+ \property QDoubleSpinBox::decimals
+
+ \brief the precision of the spin box, in decimals
+
+ Sets how many decimals the spinbox will use for displaying and
+ interpreting doubles.
+
+ \warning The results might not be reliable with very high values
+ for \a decimals.
+
+ Note: The maximum, minimum and value might change as a result of
+ changing this property.
+*/
+
+int QDoubleSpinBox::decimals() const
+{
+ Q_D(const QDoubleSpinBox);
+
+ return d->decimals;
+}
+
+void QDoubleSpinBox::setDecimals(int decimals)
+{
+ Q_D(QDoubleSpinBox);
+ d->decimals = qMax(0, decimals);
+
+ setRange(minimum(), maximum()); // make sure values are rounded
+ setValue(value());
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ display the given \a value. The default implementation returns a string
+ containing \a value printed using QWidget::locale().toString(\a value,
+ QLatin1Char('f'), decimals()) and will remove the thousand
+ separator. Reimplementations may return anything.
+
+ Note: QDoubleSpinBox does not call this function for
+ specialValueText() and that neither prefix() nor suffix() should
+ be included in the return value.
+
+ If you reimplement this, you may also need to reimplement
+ valueFromText().
+
+ \sa valueFromText()
+*/
+
+
+QString QDoubleSpinBox::textFromValue(double value) const
+{
+ Q_D(const QDoubleSpinBox);
+ QString str = locale().toString(value, 'f', d->decimals);
+ if (qAbs(value) >= 1000.0) {
+ str.remove(d->thousand);
+ }
+ return str;
+}
+
+/*!
+ This virtual function is used by the spin box whenever it needs to
+ interpret \a text entered by the user as a value.
+
+ Subclasses that need to display spin box values in a non-numeric
+ way need to reimplement this function.
+
+ Note: QDoubleSpinBox handles specialValueText() separately; this
+ function is only concerned with the other values.
+
+ \sa textFromValue(), validate()
+*/
+double QDoubleSpinBox::valueFromText(const QString &text) const
+{
+ Q_D(const QDoubleSpinBox);
+
+ QString copy = text;
+ int pos = d->edit->cursorPosition();
+ QValidator::State state = QValidator::Acceptable;
+ return d->validateAndInterpret(copy, pos, state).toDouble();
+}
+
+/*!
+ \reimp
+*/
+QValidator::State QDoubleSpinBox::validate(QString &text, int &pos) const
+{
+ Q_D(const QDoubleSpinBox);
+
+ QValidator::State state;
+ d->validateAndInterpret(text, pos, state);
+ return state;
+}
+
+
+/*!
+ \reimp
+*/
+void QDoubleSpinBox::fixup(QString &input) const
+{
+ Q_D(const QDoubleSpinBox);
+
+ input.remove(d->thousand);
+}
+
+// --- QSpinBoxPrivate ---
+
+/*!
+ \internal
+ Constructs a QSpinBoxPrivate object
+*/
+
+QSpinBoxPrivate::QSpinBoxPrivate(QWidget *parent)
+{
+ minimum = QVariant((int)0);
+ maximum = QVariant((int)99);
+ value = minimum;
+ singleStep = QVariant((int)1);
+ type = QVariant::Int;
+ const QString str = (parent ? parent->locale() : QLocale()).toString(4567);
+ if (str.size() == 5) {
+ thousand = QChar(str.at(1));
+ }
+
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+void QSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
+{
+ Q_Q(QSpinBox);
+ if (ep != NeverEmit) {
+ pendingEmit = false;
+ if (ep == AlwaysEmit || value != old) {
+ emit q->valueChanged(edit->displayText());
+ emit q->valueChanged(value.toInt());
+ }
+ }
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+QString QSpinBoxPrivate::textFromValue(const QVariant &value) const
+{
+ Q_Q(const QSpinBox);
+ return q->textFromValue(value.toInt());
+}
+/*!
+ \internal
+ \reimp
+*/
+
+QVariant QSpinBoxPrivate::valueFromText(const QString &text) const
+{
+ Q_Q(const QSpinBox);
+
+ return QVariant(q->valueFromText(text));
+}
+
+
+/*!
+ \internal
+
+ Return true if str can become a number which is between minimum and
+ maximum or false if this is not possible.
+*/
+
+bool QSpinBoxPrivate::isIntermediateValue(const QString &str) const
+{
+ const int num = q_func()->locale().toInt(str, 0, 10);
+ const int min = minimum.toInt();
+ const int max = maximum.toInt();
+
+ int numDigits = 0;
+ int digits[10];
+ int tmp = num;
+ if (tmp == 0) {
+ numDigits = 1;
+ digits[0] = 0;
+ } else {
+ tmp = num;
+ for (int i=0; tmp != 0; ++i) {
+ digits[numDigits++] = qAbs(tmp % 10);
+ tmp /= 10;
+ }
+ }
+
+ int failures = 0;
+ for (int number=min; /*number<=max*/; ++number) {
+ tmp = number;
+ for (int i=0; tmp != 0;) {
+ if (digits[i] == qAbs(tmp % 10)) {
+ if (++i == numDigits)
+ return true;
+ }
+ tmp /= 10;
+ }
+ if (failures++ == 500000) //upper bound
+ return true;
+ if (number == max) // needed for INT_MAX
+ break;
+ }
+ return false;
+}
+
+/*!
+ \internal Multi purpose function that parses input, sets state to
+ the appropriate state and returns the value it will be interpreted
+ as.
+*/
+
+QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const
+{
+ if (cachedText == input && !input.isEmpty()) {
+ state = cachedState;
+ QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was "
+ << state << " and value was " << cachedValue;
+
+ return cachedValue;
+ }
+ const int max = maximum.toInt();
+ const int min = minimum.toInt();
+
+ QString copy = stripped(input, &pos);
+ QSBDEBUG() << "input" << input << "copy" << copy;
+ state = QValidator::Acceptable;
+ int num = min;
+
+ if (max != min && (copy.isEmpty()
+ || (min < 0 && copy == QLatin1String("-"))
+ || (min >= 0 && copy == QLatin1String("+")))) {
+ state = QValidator::Intermediate;
+ QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
+ } else if (copy.startsWith(QLatin1String("-")) && min >= 0) {
+ state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100
+ } else {
+ bool ok = false;
+ bool removedThousand = false;
+ num = q_func()->locale().toInt(copy, &ok, 10);
+ if (!ok && copy.contains(thousand) && (max >= 1000 || min <= -1000)) {
+ const int s = copy.size();
+ copy.remove(thousand);
+ pos = qMax(0, pos - (s - copy.size()));
+ removedThousand = true;
+ num = q_func()->locale().toInt(copy, &ok, 10);
+ }
+ QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
+ if (!ok) {
+ state = QValidator::Invalid;
+ } else if (num >= min && num <= max) {
+ state = removedThousand ? QValidator::Intermediate : QValidator::Acceptable;
+ } else if (max == min) {
+ state = QValidator::Invalid;
+ } else {
+ if ((num >= 0 && num > max) || (num < 0 && num < min)) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to "
+ << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable");
+ }
+ }
+ }
+ if (state != QValidator::Acceptable)
+ num = max > 0 ? min : max;
+ input = prefix + copy + suffix;
+ cachedText = input;
+ cachedState = state;
+ cachedValue = QVariant((int)num);
+
+ QSBDEBUG() << "cachedText is set to '" << cachedText << "' state is set to "
+ << state << " and value is set to " << cachedValue;
+ return cachedValue;
+}
+
+// --- QDoubleSpinBoxPrivate ---
+
+/*!
+ \internal
+ Constructs a QSpinBoxPrivate object
+*/
+
+QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate(QWidget *parent)
+{
+ minimum = QVariant(0.0);
+ maximum = QVariant(99.99);
+ value = minimum;
+ singleStep = QVariant(1.0);
+ decimals = 2;
+ type = QVariant::Double;
+ const QString str = (parent ? parent->locale() : QLocale()).toString(4567.1);
+ if (str.size() == 6) {
+ delimiter = str.at(4);
+ thousand = QChar((ushort)0);
+ } else if (str.size() == 7) {
+ thousand = str.at(1);
+ delimiter = str.at(5);
+ }
+ Q_ASSERT(!delimiter.isNull());
+}
+
+/*!
+ \internal
+ \reimp
+*/
+
+void QDoubleSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
+{
+ Q_Q(QDoubleSpinBox);
+ if (ep != NeverEmit) {
+ pendingEmit = false;
+ if (ep == AlwaysEmit || value != old) {
+ emit q->valueChanged(edit->displayText());
+ emit q->valueChanged(value.toDouble());
+ }
+ }
+}
+
+
+bool QDoubleSpinBoxPrivate::isIntermediateValue(const QString &str) const
+{
+ QSBDEBUG() << "input is" << str << minimum << maximum;
+ qint64 dec = 1;
+ for (int i=0; i<decimals; ++i)
+ dec *= 10;
+
+ const QLatin1Char dot('.');
+
+ // I know QString::number() uses CLocale so I use dot
+ const QString minstr = QString::number(minimum.toDouble(), 'f', decimals);
+ bool ok;
+ qint64 min_left = minstr.left(minstr.indexOf(dot)).toLongLong(&ok);
+ if (!ok)
+ return false;
+ qint64 min_right = minstr.mid(minstr.indexOf(dot) + 1).toLongLong();
+
+ const QString maxstr = QString::number(maximum.toDouble(), 'f', decimals);
+ qint64 max_left = maxstr.left(maxstr.indexOf(dot)).toLongLong(&ok);
+ if (!ok)
+ return true;
+ qint64 max_right = maxstr.mid(maxstr.indexOf(dot) + 1).toLongLong();
+
+ const int dotindex = str.indexOf(delimiter);
+ const bool negative = maximum.toDouble() < 0;
+ qint64 left = 0, right = 0;
+ bool doleft = true;
+ bool doright = true;
+ if (dotindex == -1) {
+ left = str.toLongLong();
+ doright = false;
+ } else if (dotindex == 0 || (dotindex == 1 && str.at(0) == QLatin1Char('+'))) {
+ if (negative) {
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns false";
+ return false;
+ }
+ doleft = false;
+ right = str.mid(dotindex + 1).toLongLong();
+ } else if (dotindex == 1 && str.at(0) == QLatin1Char('-')) {
+ if (!negative) {
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns false";
+ return false;
+ }
+ doleft = false;
+ right = str.mid(dotindex + 1).toLongLong();
+ } else {
+ left = str.left(dotindex).toLongLong();
+ if (dotindex == str.size() - 1) {
+ doright = false;
+ } else {
+ right = str.mid(dotindex + 1).toLongLong();
+ }
+ }
+ if ((left >= 0 && max_left < 0 && !str.startsWith(QLatin1Char('-'))) || (left < 0 && min_left >= 0)) {
+ QSBDEBUG("returns false 0");
+ return false;
+ }
+
+ qint64 match = min_left;
+ if (doleft && !isIntermediateValueHelper(left, min_left, max_left, &match)) {
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns false";
+ return false;
+ }
+ if (doright) {
+ QSBDEBUG("match %lld min_left %lld max_left %lld", match, min_left, max_left);
+ if (!doleft) {
+ if (min_left == max_left) {
+ const bool ret = isIntermediateValueHelper(qAbs(left),
+ negative ? max_right : min_right,
+ negative ? min_right : max_right);
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret;
+ return ret;
+ } else if (qAbs(max_left - min_left) == 1) {
+ const bool ret = isIntermediateValueHelper(qAbs(left), min_right, negative ? 0 : dec)
+ || isIntermediateValueHelper(qAbs(left), negative ? dec : 0, max_right);
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret;
+ return ret;
+ } else {
+ const bool ret = isIntermediateValueHelper(qAbs(left), 0, dec);
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret;
+ return ret;
+ }
+ }
+ if (match != min_left) {
+ min_right = negative ? dec : 0;
+ }
+ if (match != max_left) {
+ max_right = negative ? 0 : dec;
+ }
+ qint64 tmpl = negative ? max_right : min_right;
+ qint64 tmpr = negative ? min_right : max_right;
+ const bool ret = isIntermediateValueHelper(right, tmpl, tmpr);
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret;
+ return ret;
+ }
+ QSBDEBUG() << __FILE__ << __LINE__ << "returns true";
+ return true;
+}
+
+/*!
+ \internal
+ \reimp
+*/
+QVariant QDoubleSpinBoxPrivate::valueFromText(const QString &f) const
+{
+ Q_Q(const QDoubleSpinBox);
+ return QVariant(q->valueFromText(f));
+}
+
+/*!
+ \internal
+ Rounds to a double value that is restricted to decimals.
+ E.g. // decimals = 2
+
+ round(5.555) => 5.56
+ */
+
+double QDoubleSpinBoxPrivate::round(double value) const
+{
+ Q_Q(const QDoubleSpinBox);
+ const QString strDbl = q->locale().toString(value, 'f', decimals);
+ return q->locale().toDouble(strDbl);
+}
+
+
+/*!
+ \internal Multi purpose function that parses input, sets state to
+ the appropriate state and returns the value it will be interpreted
+ as.
+*/
+
+QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
+ QValidator::State &state) const
+{
+ if (cachedText == input && !input.isEmpty()) {
+ state = cachedState;
+ QSBDEBUG() << "cachedText was" << "'" << cachedText << "'" << "state was "
+ << state << " and value was " << cachedValue;
+ return cachedValue;
+ }
+ const double max = maximum.toDouble();
+ const double min = minimum.toDouble();
+
+ QString copy = stripped(input, &pos);
+ QSBDEBUG() << "input" << input << "copy" << copy;
+ int len = copy.size();
+ double num = min;
+ const bool plus = max >= 0;
+ const bool minus = min <= 0;
+
+ switch (len) {
+ case 0:
+ state = max != min ? QValidator::Intermediate : QValidator::Invalid;
+ goto end;
+ case 1:
+ if (copy.at(0) == delimiter
+ || (plus && copy.at(0) == QLatin1Char('+'))
+ || (minus && copy.at(0) == QLatin1Char('-'))) {
+ state = QValidator::Intermediate;
+ goto end;
+ }
+ break;
+ case 2:
+ if (copy.at(1) == delimiter
+ && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) {
+ state = QValidator::Intermediate;
+ goto end;
+ }
+ break;
+ default: break;
+ }
+
+ if (copy.at(0) == thousand) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ } else if (len > 1) {
+ const int dec = copy.indexOf(delimiter);
+ if (dec != -1) {
+ if (dec + 1 < copy.size() && copy.at(dec + 1) == delimiter && pos == dec + 1) {
+ copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter
+ } // should be treated as typing right arrow
+
+ if (copy.size() - dec > decimals + 1) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ for (int i=dec + 1; i<copy.size(); ++i) {
+ if (copy.at(i).isSpace() || copy.at(i) == thousand) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ }
+ } else {
+ const QChar &last = copy.at(len - 1);
+ const QChar &secondLast = copy.at(len - 2);
+ if ((last == thousand || last.isSpace())
+ && (secondLast == thousand || secondLast.isSpace())) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ } else if (last.isSpace() && (!thousand.isSpace() || secondLast.isSpace())) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+ }
+ }
+
+ {
+ bool ok = false;
+ QLocale loc(q_func()->locale());
+ num = loc.toDouble(copy, &ok);
+ QSBDEBUG() << __FILE__ << __LINE__ << loc << copy << num << ok;
+ bool notAcceptable = false;
+
+ if (!ok) {
+ if (thousand.isPrint()) {
+ if (max < 1000 && min > -1000 && copy.contains(thousand)) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+
+ const int len = copy.size();
+ for (int i=0; i<len- 1; ++i) {
+ if (copy.at(i) == thousand && copy.at(i + 1) == thousand) {
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ state = QValidator::Invalid;
+ goto end;
+ }
+ }
+
+ const int s = copy.size();
+ copy.remove(thousand);
+ pos = qMax(0, pos - (s - copy.size()));
+
+
+ num = loc.toDouble(copy, &ok);
+ QSBDEBUG() << thousand << num << copy << ok;
+
+ if (!ok) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ goto end;
+ }
+ notAcceptable = true;
+ }
+ }
+
+ if (!ok) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else if (num >= min && num <= max) {
+ state = notAcceptable ? QValidator::Intermediate : QValidator::Acceptable;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to "
+ << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable");
+ } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ if ((num >= 0 && num > max) || (num < 0 && num < min)) {
+ state = QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
+ } else {
+ state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid;
+ QSBDEBUG() << __FILE__ << __LINE__<< "state is set to "
+ << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable");
+ }
+ }
+ }
+
+end:
+ if (state != QValidator::Acceptable) {
+ num = max > 0 ? min : max;
+ }
+
+ input = prefix + copy + suffix;
+ cachedText = input;
+ cachedState = state;
+ cachedValue = QVariant(num);
+ return QVariant(num);
+}
+
+/*
+ \internal
+ \reimp
+*/
+
+QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const
+{
+ Q_Q(const QDoubleSpinBox);
+ return q->textFromValue(f.toDouble());
+}
+
+/*!
+ \fn void QSpinBox::setLineStep(int step)
+
+ Use setSingleStep() instead.
+*/
+
+/*!
+ \fn void QSpinBox::setMaxValue(int value)
+
+ Use setMaximum() instead.
+*/
+
+/*!
+ \fn void QSpinBox::setMinValue(int value)
+
+ Use setMinimum() instead.
+*/
+
+/*!
+ \fn int QSpinBox::maxValue() const
+
+ Use maximum() instead.
+*/
+
+/*!
+ \fn int QSpinBox::minValue() const
+
+ Use minimum() instead.
+*/
+
+/*!
+ \internal Returns whether \a str is a string which value cannot be
+ parsed but still might turn into something valid.
+*/
+
+static bool isIntermediateValueHelper(qint64 num, qint64 min, qint64 max, qint64 *match)
+{
+ QSBDEBUG("%lld %lld %lld", num, min, max);
+
+ if (num >= min && num <= max) {
+ if (match)
+ *match = num;
+ QSBDEBUG("returns true 0");
+ return true;
+ }
+ qint64 tmp = num;
+
+ int numDigits = 0;
+ int digits[10];
+ if (tmp == 0) {
+ numDigits = 1;
+ digits[0] = 0;
+ } else {
+ tmp = qAbs(num);
+ for (int i=0; tmp > 0; ++i) {
+ digits[numDigits++] = tmp % 10;
+ tmp /= 10;
+ }
+ }
+
+ int failures = 0;
+ qint64 number;
+ for (number=max; number>=min; --number) {
+ tmp = qAbs(number);
+ for (int i=0; tmp > 0;) {
+ if (digits[i] == (tmp % 10)) {
+ if (++i == numDigits) {
+ if (match)
+ *match = number;
+ QSBDEBUG("returns true 1");
+ return true;
+ }
+ }
+ tmp /= 10;
+ }
+ if (failures++ == 500000) { //upper bound
+ if (match)
+ *match = num;
+ QSBDEBUG("returns true 2");
+ return true;
+ }
+ }
+ QSBDEBUG("returns false");
+ return false;
+}
+
+/*! \reimp */
+bool QSpinBox::event(QEvent *event)
+{
+ Q_D(QSpinBox);
+ if (event->type() == QEvent::StyleChange
+#ifdef Q_WS_MAC
+ || event->type() == QEvent::MacSizeChange
+#endif
+ )
+ d->setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
+ return QAbstractSpinBox::event(event);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_SPINBOX