aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Vogt <matthew.vogt@nokia.com>2012-07-17 11:14:43 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-18 05:48:43 +0200
commit884bc89e9fe765a7be245b3009339f999936a761 (patch)
treea8ecc8df740a3e93a8ab30de96f7a4e4a2e091e9
parent1ce3a17ef51e10c03627842b9cdd0bb543ee8c83 (diff)
Allow QQmlPropertyMap property updates to be controlled
Allow clients to control updates made from QML to types derived from QQmlPropertyMap, by overriding the updateValue() function. Task-number: QTBUG-23183 Change-Id: I0169093779ebfe50dc9349f5aaac08ed85c80a8f Reviewed-by: Michael Brasser <michael.brasser@nokia.com> Reviewed-by: abcd <amos.choy@nokia.com>
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp29
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h1
-rw-r--r--src/qml/util/qqmlpropertymap.cpp39
-rw-r--r--src/qml/util/qqmlpropertymap.h3
-rw-r--r--tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp44
5 files changed, 103 insertions, 13 deletions
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index 221cb3a314..4774f7e126 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -145,10 +145,14 @@ public:
QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q)
: q(_q), parent(0), type(0), cacheProperties(false) {}
- inline QVariant &getData(int idx) {
+ inline QPair<QVariant, bool> &getDataRef(int idx) {
while (data.count() <= idx)
data << QPair<QVariant, bool>(QVariant(), false);
- QPair<QVariant, bool> &prop = data[idx];
+ return data[idx];
+ }
+
+ inline QVariant &getData(int idx) {
+ QPair<QVariant, bool> &prop = getDataRef(idx);
if (!prop.second) {
prop.first = q->initialValue(idx);
prop.second = true;
@@ -156,14 +160,6 @@ public:
return prop.first;
}
- inline void writeData(int idx, const QVariant &value) {
- while (data.count() <= idx)
- data << QPair<QVariant, bool>(QVariant(), false);
- QPair<QVariant, bool> &prop = data[idx];
- prop.first = value;
- prop.second = true;
- }
-
inline bool hasData(int idx) const {
if (idx >= data.count())
return false;
@@ -235,7 +231,9 @@ int QQmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
} else if (c == QMetaObject::WriteProperty) {
if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
- d->writeData(propId, *reinterpret_cast<QVariant *>(a[0]));
+ QPair<QVariant, bool> &prop = d->getDataRef(propId);
+ prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0]));
+ prop.second = true;
propertyWritten(propId);
activate(d->object, d->type->d->signalOffset + propId, 0);
}
@@ -261,7 +259,9 @@ QVariant QQmlOpenMetaObject::value(int id) const
void QQmlOpenMetaObject::setValue(int id, const QVariant &value)
{
- d->writeData(id, value);
+ QPair<QVariant, bool> &prop = d->getDataRef(id);
+ prop.first = propertyWriteValue(id, value);
+ prop.second = true;
activate(d->object, id + d->type->d->signalOffset, 0);
}
@@ -354,6 +354,11 @@ void QQmlOpenMetaObject::propertyWrite(int)
{
}
+QVariant QQmlOpenMetaObject::propertyWriteValue(int, const QVariant &value)
+{
+ return value;
+}
+
void QQmlOpenMetaObject::propertyWritten(int)
{
}
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
index 188192edc1..a45d7d8259 100644
--- a/src/qml/qml/qqmlopenmetaobject_p.h
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -113,6 +113,7 @@ protected:
virtual void propertyRead(int);
virtual void propertyWrite(int);
+ virtual QVariant propertyWriteValue(int, const QVariant &);
virtual void propertyWritten(int);
virtual void propertyCreated(int, QMetaPropertyBuilder &);
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 1571d2dfc9..cdc82fe86e 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -56,9 +56,13 @@ public:
QQmlPropertyMapMetaObject(QQmlPropertyMap *obj, QQmlPropertyMapPrivate *objPriv);
protected:
+ virtual QVariant propertyWriteValue(int, const QVariant &);
virtual void propertyWritten(int index);
virtual void propertyCreated(int, QMetaPropertyBuilder &);
virtual int createProperty(const char *, const char *);
+
+ const QString &propertyName(int index);
+
private:
QQmlPropertyMap *map;
QQmlPropertyMapPrivate *priv;
@@ -70,8 +74,12 @@ class QQmlPropertyMapPrivate : public QObjectPrivate
public:
QQmlPropertyMapMetaObject *mo;
QStringList keys;
+
+ QVariant updateValue(const QString &key, const QVariant &input);
void emitChanged(const QString &key, const QVariant &value);
bool validKeyName(const QString& name);
+
+ const QString &propertyName(int index) const;
};
bool QQmlPropertyMapPrivate::validKeyName(const QString& name)
@@ -84,21 +92,38 @@ bool QQmlPropertyMapPrivate::validKeyName(const QString& name)
&& name != QLatin1String("deleteLater");
}
+QVariant QQmlPropertyMapPrivate::updateValue(const QString &key, const QVariant &input)
+{
+ Q_Q(QQmlPropertyMap);
+ return q->updateValue(key, input);
+}
+
void QQmlPropertyMapPrivate::emitChanged(const QString &key, const QVariant &value)
{
Q_Q(QQmlPropertyMap);
emit q->valueChanged(key, value);
}
+const QString &QQmlPropertyMapPrivate::propertyName(int index) const
+{
+ Q_ASSERT(index < keys.size());
+ return keys[index];
+}
+
QQmlPropertyMapMetaObject::QQmlPropertyMapMetaObject(QQmlPropertyMap *obj, QQmlPropertyMapPrivate *objPriv) : QQmlOpenMetaObject(obj)
{
map = obj;
priv = objPriv;
}
+QVariant QQmlPropertyMapMetaObject::propertyWriteValue(int index, const QVariant &input)
+{
+ return priv->updateValue(priv->propertyName(index), input);
+}
+
void QQmlPropertyMapMetaObject::propertyWritten(int index)
{
- priv->emitChanged(QString::fromUtf8(name(index)), operator[](index));
+ priv->emitChanged(priv->propertyName(index), operator[](index));
}
void QQmlPropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
@@ -298,6 +323,18 @@ QVariant QQmlPropertyMap::operator[](const QString &key) const
}
/*!
+ Returns the new value to be stored for the key \a key. This function is provided
+ to intercept updates to a property from QML, where the value provided from QML is \a input.
+
+ Override this function to manipulate the property value as it is updated. Note that
+ this function is only invoked when the value is updated from QML.
+*/
+QVariant QQmlPropertyMap::updateValue(const QString &key, const QVariant &input)
+{
+ return input;
+}
+
+/*!
\fn void QQmlPropertyMap::valueChanged(const QString &key, const QVariant &value)
This signal is emitted whenever one of the values in the map is changed. \a key
is the key corresponding to the \a value that was changed.
diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h
index 53254ab672..bfd11e5c80 100644
--- a/src/qml/util/qqmlpropertymap.h
+++ b/src/qml/util/qqmlpropertymap.h
@@ -79,6 +79,9 @@ public:
Q_SIGNALS:
void valueChanged(const QString &key, const QVariant &value);
+protected:
+ virtual QVariant updateValue(const QString &key, const QVariant &input);
+
private:
Q_DECLARE_PRIVATE(QQmlPropertyMap)
Q_DISABLE_COPY(QQmlPropertyMap)
diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
index 0ae05ce138..4e39ad3a41 100644
--- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
+++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
@@ -45,6 +45,7 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QSignalSpy>
+#include <QDebug>
class tst_QQmlPropertyMap : public QObject
{
@@ -59,6 +60,7 @@ private slots:
void clear();
void changed();
void count();
+ void controlledWrite();
void crashBug();
void QTBUG_17868();
@@ -205,6 +207,48 @@ void tst_QQmlPropertyMap::count()
QCOMPARE(map.size(), map.count());
}
+class MyPropertyMap : public QQmlPropertyMap
+{
+ Q_OBJECT
+protected:
+ virtual QVariant updateValue(const QString &key, const QVariant &src)
+ {
+ if (key == QLatin1String("key1")) {
+ // 'key1' must be all uppercase
+ const QString original(src.toString());
+ return QVariant(original.toUpper());
+ }
+
+ return src;
+ }
+};
+
+void tst_QQmlPropertyMap::controlledWrite()
+{
+ MyPropertyMap map;
+ QCOMPARE(map.isEmpty(), true);
+
+ //make changes in QML
+ QQmlEngine engine;
+ QQmlContext *ctxt = engine.rootContext();
+ ctxt->setContextProperty(QLatin1String("testdata"), &map);
+
+ const char *qmlSource =
+ "import QtQuick 2.0\n"
+ "Item { Component.onCompleted: { testdata.key1 = 'Hello World'; testdata.key2 = 'Goodbye' } }";
+
+ QQmlComponent component(&engine);
+ component.setData(qmlSource, QUrl::fromLocalFile(""));
+ QVERIFY(component.isReady());
+
+ QObject *obj = component.create();
+ QVERIFY(obj);
+ delete obj;
+
+ QCOMPARE(map.value(QLatin1String("key1")), QVariant("HELLO WORLD"));
+ QCOMPARE(map.value(QLatin1String("key2")), QVariant("Goodbye"));
+}
+
void tst_QQmlPropertyMap::crashBug()
{
QQmlPropertyMap map;