Ensure external value types are initialized before write
authorMatthew Vogt <matthew.vogt@nokia.com>
Thu, 26 Apr 2012 01:05:41 +0000 (11:05 +1000)
committerQt by Nokia <qt-info@nokia.com>
Sun, 29 Apr 2012 23:52:57 +0000 (01:52 +0200)
Ensure that the logic used when writing to a property having a value
type provided by an external module matches that used for properties
of internal value types.

Change-Id: I925b8b30a211ef813e2a51134411a162b0b146b5
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
src/qml/qml/qqmlglobal.cpp
src/qml/qml/qqmlglobal_p.h
src/qml/qml/qqmlvmemetaobject.cpp
src/quick/util/qquickglobal.cpp
tests/auto/qml/qqmlvaluetypes/data/initializeByWrite.qml [new file with mode: 0644]
tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp

index 1f8de4f..c5228d0 100644 (file)
@@ -175,6 +175,20 @@ QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString
     return QVariant();
 }
 
+bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const void *rhs)
+{
+    Q_ASSERT(lhs);
+    Q_ASSERT(rhs);
+
+    QQmlValueTypeProvider *p = this;
+    do {
+        if (p->equal(type, lhs, rhs))
+            return true;
+    } while ((p = p->next));
+
+    return false;
+}
+
 bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, size_t n)
 {
     Q_ASSERT(src);
@@ -226,6 +240,7 @@ bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_
 bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; }
 bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; }
 bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; }
+bool QQmlValueTypeProvider::equal(int, const void *, const void *) { return false; }
 bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; }
 bool QQmlValueTypeProvider::read(int, const void *, int, void *) { return false; }
 bool QQmlValueTypeProvider::write(int, const void *, void *, size_t) { return false; }
index 04711ae..e5515b6 100644 (file)
@@ -158,6 +158,7 @@ public:
     QVariant createVariantFromString(const QString &);
     QVariant createVariantFromString(int, const QString &, bool *);
 
+    bool equalValueType(int, const void *, const void *);
     bool storeValueType(int, const void *, void *, size_t);
     bool readValueType(int, const void *, int, void *);
     bool writeValueType(int, const void *, void *, size_t);
@@ -176,6 +177,7 @@ private:
     virtual bool variantFromString(const QString &, QVariant *);
     virtual bool variantFromString(int, const QString &, QVariant *);
 
+    virtual bool equal(int, const void *, const void *);
     virtual bool store(int, const void *, void *, size_t);
     virtual bool read(int, const void *, int, void *);
     virtual bool write(int, const void *, void *, size_t);
index b39ca34..9778161 100644 (file)
@@ -116,6 +116,8 @@ public:
 
     inline void setDataType(int t);
 
+    inline void ensureValueType(int);
+
 private:
     int type;
     void *data[6]; // Large enough to hold all types
@@ -409,6 +411,15 @@ void QQmlVMEVariant::setDataType(int t)
     type = t;
 }
 
+void QQmlVMEVariant::ensureValueType(int t)
+{
+    if (type != t) {
+        cleanup();
+        type = t;
+        QQml_valueTypeProvider()->initValueType(t, dataPtr(), dataSize());
+    }
+}
+
 QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
 {
     callback = &vmecallback;
@@ -645,12 +656,9 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
                             break;
                         default:
-                            if (! data[id].dataType())
-                                QQml_valueTypeProvider()->initValueType(t, data[id].dataPtr(), data[id].dataSize());
-                            needActivate = QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
-                            if (needActivate) {
-                                data[id].setDataType(t);
-                            }
+                            data[id].ensureValueType(t);
+                            needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr());
+                            QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
                             break;
                         }
                     }
index b99cb7a..6869d48 100644 (file)
@@ -178,6 +178,13 @@ private:
 };
 
 
+// Note: The functions in this class provide handling only for the types
+// that the QML engine will currently actually call them for, so many
+// appear incompletely implemented.  For some functions, the implementation
+// would be obvious, but for others (particularly create and createFromString)
+// the exact semantics are unknown.  For this reason unused functionality
+// has been omitted.
+
 class QQuickValueTypeProvider : public QQmlValueTypeProvider
 {
 public:
@@ -404,6 +411,26 @@ public:
         return false;
     }
 
+    template<typename T>
+    bool typedEqual(const void *lhs, const void *rhs)
+    {
+        return (*(reinterpret_cast<const T *>(lhs)) == *(reinterpret_cast<const T *>(rhs)));
+    }
+
+    bool equal(int type, const void *lhs, const void *rhs)
+    {
+        switch (type) {
+        case QMetaType::QColor:
+            return typedEqual<QColor>(lhs, rhs);
+        case QMetaType::QVector3D:
+            return typedEqual<QVector3D>(lhs, rhs);
+        case QMetaType::QVector4D:
+            return typedEqual<QVector4D>(lhs, rhs);
+        }
+
+        return false;
+    }
+
     bool store(int type, const void *src, void *dst, size_t n)
     {
         switch (type) {
diff --git a/tests/auto/qml/qqmlvaluetypes/data/initializeByWrite.qml b/tests/auto/qml/qqmlvaluetypes/data/initializeByWrite.qml
new file mode 100644 (file)
index 0000000..8493dd4
--- /dev/null
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+ListView {
+    property bool test: false
+
+    width: 200
+    height: 200
+    model: 20
+
+    delegate: Text {
+        text: qsTr(props.titleText).arg(index)
+        color: props.titleColor
+        font.pointSize: props.titlePointSize
+    }
+
+    property QtObject props: QtObject {
+        property string titleText: "List Item %1 Title"
+        property color titleColor: Qt.rgba(1, 0, 0, 0)
+        property int titlePointSize: 18
+    }
+
+    Component.onCompleted: {
+        test = (props.titleText == "List Item %1 Title") &&
+               (props.titleColor == Qt.rgba(1, 0, 0, 0)) &&
+               (props.titlePointSize == 18)
+    }
+}
index 359653c..0c890de 100644 (file)
@@ -94,6 +94,7 @@ private slots:
     void varAssignment();
     void bindingsSpliceCorrectly();
     void nonValueTypeComparison();
+    void initializeByWrite();
 
 private:
     QQmlEngine engine;
@@ -1334,6 +1335,17 @@ void tst_qqmlvaluetypes::nonValueTypeComparison()
     delete object;
 }
 
+void tst_qqmlvaluetypes::initializeByWrite()
+{
+    QQmlComponent component(&engine, testFileUrl("initializeByWrite.qml"));
+    QObject *object = component.create();
+    QVERIFY(object != 0);
+
+    QCOMPARE(object->property("test").toBool(), true);
+
+    delete object;
+}
+
 QTEST_MAIN(tst_qqmlvaluetypes)
 
 #include "tst_qqmlvaluetypes.moc"