aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/controls/SpinBox.qml15
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox-textual.pngbin0 -> 1894 bytes
-rw-r--r--src/templates/qquickspinbox.cpp138
-rw-r--r--src/templates/qquickspinbox_p.h18
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox-textual.qml28
5 files changed, 191 insertions, 8 deletions
diff --git a/src/imports/controls/SpinBox.qml b/src/imports/controls/SpinBox.qml
index 3607a701..5aeebe78 100644
--- a/src/imports/controls/SpinBox.qml
+++ b/src/imports/controls/SpinBox.qml
@@ -54,9 +54,17 @@ T.SpinBox {
leftPadding: 6 + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
rightPadding: 6 + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+ //! [validator]
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+ //! [validator]
+
//! [contentItem]
contentItem: TextInput {
- text: Number(control.value).toLocaleString(control.locale, 'f', 0)
+ text: control.textFromValue(control.value, control.locale)
font: control.font
color: control.Theme.textColor
@@ -65,10 +73,7 @@ T.SpinBox {
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
- validator: IntValidator {
- bottom: Math.min(control.from, control.to)
- top: Math.max(control.from, control.to)
- }
+ validator: control.validator
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
//! [contentItem]
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox-textual.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox-textual.png
new file mode 100644
index 00000000..abf4c7f2
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox-textual.png
Binary files differ
diff --git a/src/templates/qquickspinbox.cpp b/src/templates/qquickspinbox.cpp
index e1596e3a..9bb908e9 100644
--- a/src/templates/qquickspinbox.cpp
+++ b/src/templates/qquickspinbox.cpp
@@ -40,6 +40,10 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmllocale_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+
QT_BEGIN_NAMESPACE
// copied from qabstractbutton.cpp
@@ -65,6 +69,17 @@ static const int AUTO_REPEAT_INTERVAL = 100;
\snippet qtlabscontrols-spinbox.qml 1
+ \section2 Custom Values
+
+ \image qtlabscontrols-spinbox-textual.png
+
+ Even though SpinBox works on integer values, it can be customized to
+ accept arbitrary input values. The following snippet demonstrates how
+ \l validator, \l textFromValue and \l valueFromText can be used to
+ customize the default behavior.
+
+ \snippet qtlabscontrols-spinbox-textual.qml 1
+
\sa Tumbler, {Customizing SpinBox}
*/
@@ -74,7 +89,7 @@ class QQuickSpinBoxPrivate : public QQuickControlPrivate
public:
QQuickSpinBoxPrivate() : from(0), to(99), value(0), stepSize(1),
- delayTimer(0), repeatTimer(0), up(Q_NULLPTR), down(Q_NULLPTR) { }
+ delayTimer(0), repeatTimer(0), up(Q_NULLPTR), down(Q_NULLPTR), validator(Q_NULLPTR) { }
int boundValue(int value) const;
void updateValue();
@@ -99,6 +114,9 @@ public:
QQuickSpinner *up;
QQuickSpinner *down;
QLocale locale;
+ QValidator *validator;
+ QJSValue textFromValue;
+ QJSValue valueFromText;
};
int QQuickSpinBoxPrivate::boundValue(int value) const
@@ -111,8 +129,12 @@ void QQuickSpinBoxPrivate::updateValue()
Q_Q(QQuickSpinBox);
if (contentItem) {
QVariant text = contentItem->property("text");
- if (text.isValid())
- q->setValue(locale.toInt(text.toString()));
+ if (text.isValid()) {
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(qmlEngine(q));
+ QJSValue loc(v4, QQmlLocale::wrap(v4, locale));
+ QJSValue val = valueFromText.call(QJSValueList() << text.toString() << loc);
+ q->setValue(val.toInt());
+ }
}
}
@@ -335,6 +357,103 @@ void QQuickSpinBox::setLocale(const QLocale &locale)
}
/*!
+ \qmlproperty Validator Qt.labs.controls::SpinBox::validator
+
+ This property holds the input text validator. By default, SpinBox uses
+ \l IntValidator to accept input of integer numbers.
+
+ \snippet SpinBox.qml validator
+
+ \sa textFromValue, valueFromText, locale
+*/
+QValidator *QQuickSpinBox::validator() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->validator;
+}
+
+void QQuickSpinBox::setValidator(QValidator *validator)
+{
+ Q_D(QQuickSpinBox);
+ if (d->validator != validator) {
+ d->validator = validator;
+ emit validatorChanged();
+ }
+}
+
+/*!
+ \qmlproperty function Qt.labs.controls::SpinBox::textFromValue
+
+ This property holds a callback function that is called whenever
+ an integer value needs to be converted to display text.
+
+ The callback function signature is \c {string function(value, locale)}.
+ The function can have one or two arguments, where the first argument
+ is the value to be converted, and the optional second argument is the
+ locale that should be used for the conversion, if applicable.
+
+ The default implementation does the conversion using \l {QtQml::Locale}{Number.toLocaleString()}:
+
+ \code
+ textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }
+ \endcode
+
+ \sa valueFromText, validator, locale
+*/
+QJSValue QQuickSpinBox::textFromValue() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->textFromValue;
+}
+
+void QQuickSpinBox::setTextFromValue(const QJSValue &callback)
+{
+ Q_D(QQuickSpinBox);
+ if (!callback.isCallable()) {
+ qmlInfo(this) << "textFromValue must be a callable function";
+ return;
+ }
+ d->textFromValue = callback;
+ emit textFromValueChanged();
+}
+
+/*!
+ \qmlproperty function Qt.labs.controls::SpinBox::valueFromText
+
+ This property holds a callback function that is called whenever
+ input text needs to be converted to an integer value.
+
+ The callback function signature is \c {int function(text, locale)}.
+ The function can have one or two arguments, where the first argument
+ is the text to be converted, and the optional second argument is the
+ locale that should be used for the conversion, if applicable.
+
+ The default implementation does the conversion using \l {QtQml::Locale}{Number.fromLocaleString()}:
+
+ \code
+ valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); }
+ \endcode
+
+ \sa textFromValue, validator, locale
+*/
+QJSValue QQuickSpinBox::valueFromText() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->valueFromText;
+}
+
+void QQuickSpinBox::setValueFromText(const QJSValue &callback)
+{
+ Q_D(QQuickSpinBox);
+ if (!callback.isCallable()) {
+ qmlInfo(this) << "valueFromText must be a callable function";
+ return;
+ }
+ d->valueFromText = callback;
+ emit valueFromTextChanged();
+}
+
+/*!
\qmlpropertygroup Qt.labs.controls::SpinBox::up
\qmlproperty bool Qt.labs.controls::SpinBox::up.pressed
\qmlproperty Item Qt.labs.controls::SpinBox::up.indicator
@@ -459,6 +578,19 @@ void QQuickSpinBox::timerEvent(QTimerEvent *event)
}
}
+void QQuickSpinBox::componentComplete()
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::componentComplete();
+ QQmlEngine *engine = qmlEngine(this);
+ if (engine) {
+ if (!d->textFromValue.isCallable())
+ setTextFromValue(engine->evaluate(QStringLiteral("function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }")));
+ if (!d->valueFromText.isCallable())
+ setValueFromText(engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }")));
+ }
+}
+
void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value)
{
Q_D(QQuickSpinBox);
diff --git a/src/templates/qquickspinbox_p.h b/src/templates/qquickspinbox_p.h
index e78979f9..047364a2 100644
--- a/src/templates/qquickspinbox_p.h
+++ b/src/templates/qquickspinbox_p.h
@@ -49,9 +49,11 @@
//
#include <QtLabsTemplates/private/qquickcontrol_p.h>
+#include <QtQml/qjsvalue.h>
QT_BEGIN_NAMESPACE
+class QValidator;
class QQuickSpinner;
class QQuickSpinnerPrivate;
class QQuickSpinBoxPrivate;
@@ -64,6 +66,9 @@ class Q_LABSTEMPLATES_EXPORT QQuickSpinBox : public QQuickControl
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
Q_PROPERTY(int stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
Q_PROPERTY(QLocale locale READ locale WRITE setLocale NOTIFY localeChanged FINAL)
+ Q_PROPERTY(QValidator *validator READ validator WRITE setValidator NOTIFY validatorChanged FINAL)
+ Q_PROPERTY(QJSValue textFromValue READ textFromValue WRITE setTextFromValue NOTIFY textFromValueChanged FINAL)
+ Q_PROPERTY(QJSValue valueFromText READ valueFromText WRITE setValueFromText NOTIFY valueFromTextChanged FINAL)
Q_PROPERTY(QQuickSpinner *up READ up CONSTANT FINAL)
Q_PROPERTY(QQuickSpinner *down READ down CONSTANT FINAL)
@@ -85,6 +90,15 @@ public:
QLocale locale() const;
void setLocale(const QLocale &locale);
+ QValidator *validator() const;
+ void setValidator(QValidator *validator);
+
+ QJSValue textFromValue() const;
+ void setTextFromValue(const QJSValue &callback);
+
+ QJSValue valueFromText() const;
+ void setValueFromText(const QJSValue &callback);
+
QQuickSpinner *up() const;
QQuickSpinner *down() const;
@@ -98,6 +112,9 @@ Q_SIGNALS:
void valueChanged();
void stepSizeChanged();
void localeChanged();
+ void validatorChanged();
+ void textFromValueChanged();
+ void valueFromTextChanged();
protected:
bool childMouseEventFilter(QQuickItem *child, QEvent *event) Q_DECL_OVERRIDE;
@@ -105,6 +122,7 @@ protected:
void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
+ void componentComplete() Q_DECL_OVERRIDE;
void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) Q_DECL_OVERRIDE;
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox-textual.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox-textual.qml
new file mode 100644
index 00000000..cdcbc1bc
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox-textual.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+//! [1]
+SpinBox {
+ from: 0
+ to: items.length - 1
+ value: 1 // "Medium"
+
+ property var items: ["Small", "Medium", "Large"]
+
+ validator: RegExpValidator {
+ regExp: new RegExp("(Small|Medium|Large)", "i")
+ }
+
+ textFromValue: function(value) {
+ return items[value];
+ }
+
+ valueFromText: function(text) {
+ for (var i = 0; i < items.length; ++i) {
+ if (items[i].toLowerCase().indexOf(text.toLowerCase()) === 0)
+ return i
+ }
+ return sb.value
+ }
+}
+//! [1]