From: Matthew Vogt Date: Tue, 17 Jul 2012 01:14:43 +0000 (+1000) Subject: Allow QQmlPropertyMap property updates to be controlled X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=884bc89e9fe765a7be245b3009339f999936a761;p=konrad%2Fqtdeclarative.git 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 Reviewed-by: abcd --- diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 221cb3a..4774f7e 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 &getDataRef(int idx) { while (data.count() <= idx) data << QPair(QVariant(), false); - QPair &prop = data[idx]; + return data[idx]; + } + + inline QVariant &getData(int idx) { + QPair &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(), false); - QPair &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(a[0])) { propertyWrite(propId); - d->writeData(propId, *reinterpret_cast(a[0])); + QPair &prop = d->getDataRef(propId); + prop.first = propertyWriteValue(propId, *reinterpret_cast(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 &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 188192e..a45d7d8 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 1571d2d..cdc82fe 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 53254ab..bfd11e5 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 0ae05ce..4e39ad3 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -45,6 +45,7 @@ #include #include #include +#include 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;