/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtGui module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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.1, 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. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $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> | |
#include <float.h> | |
QT_BEGIN_NAMESPACE | |
//#define QSPINBOX_QSBDEBUG | |
#ifdef QSPINBOX_QSBDEBUG | |
# define QSBDEBUG qDebug | |
#else | |
# define QSBDEBUG if (false) qDebug | |
#endif | |
class QSpinBoxPrivate : public QAbstractSpinBoxPrivate | |
{ | |
Q_DECLARE_PUBLIC(QSpinBox) | |
public: | |
QSpinBoxPrivate(); | |
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; | |
inline void init() { | |
Q_Q(QSpinBox); | |
q->setInputMethodHints(Qt::ImhDigitsOnly); | |
setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); | |
} | |
}; | |
class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate | |
{ | |
Q_DECLARE_PUBLIC(QDoubleSpinBox) | |
public: | |
QDoubleSpinBoxPrivate(); | |
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; | |
double round(double input) const; | |
// variables | |
int decimals; | |
inline void init() { | |
Q_Q(QDoubleSpinBox); | |
q->setInputMethodHints(Qt::ImhFormattedNumbersOnly); | |
} | |
// When fiddling with the decimals property, we may lose precision in these properties. | |
double actualMin; | |
double actualMax; | |
}; | |
/*! | |
\class QSpinBox | |
\brief The QSpinBox class provides a spin box widget. | |
\ingroup basicwidgets | |
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) | |
{ | |
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) | |
{ | |
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) | |
{ | |
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(); | |
d->cachedSizeHint = QSize(); | |
updateGeometry(); | |
} | |
/*! | |
\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(); | |
d->cachedSizeHint = QSize(); | |
updateGeometry(); | |
} | |
/*! | |
\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(), but with the thousand separator | |
removed. 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(), QLocale::groupSeparator() | |
*/ | |
QString QSpinBox::textFromValue(int value) const | |
{ | |
QString str = locale().toString(value); | |
if (qAbs(value) >= 1000 || value == INT_MIN) { | |
str.remove(locale().groupSeparator()); | |
} | |
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 | |
{ | |
input.remove(locale().groupSeparator()); | |
} | |
// --- QDoubleSpinBox --- | |
/*! | |
\class QDoubleSpinBox | |
\brief The QDoubleSpinBox class provides a spin box widget that | |
takes doubles. | |
\ingroup basicwidgets | |
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) | |
{ | |
Q_D(QDoubleSpinBox); | |
d->init(); | |
} | |
/*! | |
\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); | |
d->actualMin = minimum; | |
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); | |
d->actualMax = maximum; | |
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->actualMin = minimum; | |
d->actualMax = maximum; | |
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 maximum value for \a decimals is DBL_MAX_10_EXP + | |
DBL_DIG (ie. 323) because of the limitations of the double type. | |
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 = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG); | |
setRange(d->actualMin, d->actualMax); // 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(), QLocale::groupSeparator() | |
*/ | |
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(locale().groupSeparator()); | |
} | |
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 | |
{ | |
input.remove(locale().groupSeparator()); | |
} | |
// --- QSpinBoxPrivate --- | |
/*! | |
\internal | |
Constructs a QSpinBoxPrivate object | |
*/ | |
QSpinBoxPrivate::QSpinBoxPrivate() | |
{ | |
minimum = QVariant((int)0); | |
maximum = QVariant((int)99); | |
value = minimum; | |
singleStep = QVariant((int)1); | |
type = QVariant::Int; | |
} | |
/*! | |
\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 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(QLatin1Char('-')) && 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; | |
num = locale.toInt(copy, &ok, 10); | |
if (!ok && copy.contains(locale.groupSeparator()) && (max >= 1000 || min <= -1000)) { | |
QString copy2 = copy; | |
copy2.remove(locale.groupSeparator()); | |
num = locale.toInt(copy2, &ok, 10); | |
} | |
QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; | |
if (!ok) { | |
state = QValidator::Invalid; | |
} else if (num >= min && num <= max) { | |
state = 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 = QValidator::Intermediate; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; | |
} | |
} | |
} | |
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() | |
{ | |
actualMin = 0.0; | |
actualMax = 99.99; | |
minimum = QVariant(actualMin); | |
maximum = QVariant(actualMax); | |
value = minimum; | |
singleStep = QVariant(1.0); | |
decimals = 2; | |
type = QVariant::Double; | |
} | |
/*! | |
\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()); | |
} | |
} | |
} | |
/*! | |
\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 | |
{ | |
return QString::number(value, 'f', decimals).toDouble(); | |
} | |
/*! | |
\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) == locale.decimalPoint() | |
|| (plus && copy.at(0) == QLatin1Char('+')) | |
|| (minus && copy.at(0) == QLatin1Char('-'))) { | |
state = QValidator::Intermediate; | |
goto end; | |
} | |
break; | |
case 2: | |
if (copy.at(1) == locale.decimalPoint() | |
&& ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) { | |
state = QValidator::Intermediate; | |
goto end; | |
} | |
break; | |
default: break; | |
} | |
if (copy.at(0) == locale.groupSeparator()) { | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
state = QValidator::Invalid; | |
goto end; | |
} else if (len > 1) { | |
const int dec = copy.indexOf(locale.decimalPoint()); | |
if (dec != -1) { | |
if (dec + 1 < copy.size() && copy.at(dec + 1) == locale.decimalPoint() && 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) == locale.groupSeparator()) { | |
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 == locale.groupSeparator() || last.isSpace()) | |
&& (secondLast == locale.groupSeparator() || secondLast.isSpace())) { | |
state = QValidator::Invalid; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
goto end; | |
} else if (last.isSpace() && (!locale.groupSeparator().isSpace() || secondLast.isSpace())) { | |
state = QValidator::Invalid; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
goto end; | |
} | |
} | |
} | |
{ | |
bool ok = false; | |
num = locale.toDouble(copy, &ok); | |
QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok; | |
if (!ok) { | |
if (locale.groupSeparator().isPrint()) { | |
if (max < 1000 && min > -1000 && copy.contains(locale.groupSeparator())) { | |
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) == locale.groupSeparator() && copy.at(i + 1) == locale.groupSeparator()) { | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
state = QValidator::Invalid; | |
goto end; | |
} | |
} | |
QString copy2 = copy; | |
copy2.remove(locale.groupSeparator()); | |
num = locale.toDouble(copy2, &ok); | |
QSBDEBUG() << locale.groupSeparator() << num << copy2 << ok; | |
if (!ok) { | |
state = QValidator::Invalid; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
goto end; | |
} | |
} | |
} | |
if (!ok) { | |
state = QValidator::Invalid; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; | |
} else if (num >= min && num <= max) { | |
state = QValidator::Acceptable; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to 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 = QValidator::Intermediate; | |
QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; | |
} | |
} | |
} | |
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. | |
*/ | |
/*! \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 |