Fallback to QMetaObject for properties not in QQmlPropertyCache
authorAlberto Mardegan <alberto.mardegan@canonical.com>
Fri, 24 May 2013 07:46:39 +0000 (10:46 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 31 May 2013 13:09:46 +0000 (15:09 +0200)
QQmlOpenMetaObject does not update the QQmlPropertyCache when new
properties are added, meaning that the QQmlPropertyCache might not
contain all of the dynamic properties of an object. Therefore, make
QQmlPropertyCache fallback to reading the QMetaObject when a property is
not found.

Task-number: QTBUG-31226
Change-Id: I760aaa155b1952f6f52ab9ce173fb9547f8e34a6
Reviewed-by: Alan Alpert <aalpert@blackberry.com>
src/qml/qml/qqmlpropertycache.cpp
src/qml/qml/v8/qv8qobjectwrapper.cpp
tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp

index b1ffc9a..dee9f26 100644 (file)
@@ -1328,8 +1328,14 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS
                     rv.load(p);
                     return rv;
                 } else {
-                    while (cmo && cmo->propertyOffset() >= idx)
+                    bool changed = false;
+                    while (cmo && cmo->propertyOffset() >= idx) {
                         cmo = cmo->superClass();
+                        changed = true;
+                    }
+                    /* If the "cmo" variable didn't change, set it to 0 to
+                     * avoid running into an infinite loop */
+                    if (!changed) cmo = 0;
                 }
             } else {
                 cmo = 0;
@@ -1395,7 +1401,8 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
 
     if (cache) {
         rv = cache->property(name, obj, context);
-    } else {
+    }
+    if (!rv) {
         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
         if (local.isValid())
             rv = &local;
index 0336457..53f70ad 100644 (file)
@@ -524,7 +524,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
         QQmlData *ddata = QQmlData::get(object, false);
         if (ddata && ddata->propertyCache)
             result = ddata->propertyCache->property(property, object, context);
-        else
+        if (!result)
             result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
     }
 
index 327716f..2b772ba 100644 (file)
@@ -66,6 +66,7 @@ private slots:
     void crashBug();
     void QTBUG_17868();
     void metaObjectAccessibility();
+    void QTBUG_31226();
 };
 
 void tst_QQmlPropertyMap::insert()
@@ -312,6 +313,34 @@ void tst_QQmlPropertyMap::metaObjectAccessibility()
     QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
 }
 
+void tst_QQmlPropertyMap::QTBUG_31226()
+{
+    /* Instantiate a property map from QML, and verify that property changes
+     * made from C++ are visible from QML */
+    QQmlEngine engine;
+    QQmlContext context(&engine);
+    qmlRegisterType<QQmlPropertyMap>("QTBUG_31226", 1, 0, "PropertyMap");
+    QQmlComponent c(&engine);
+    c.setData("import QtQuick 2.0\nimport QTBUG_31226 1.0\n"
+              "Item {\n"
+              "  property string myProp\n"
+              "  PropertyMap { id: qmlPropertyMap; objectName: \"qmlPropertyMap\" }\n"
+              "  Timer { interval: 5; running: true; onTriggered: { myProp = qmlPropertyMap.greeting; } }\n"
+              "}",
+              QUrl());
+    QObject *obj = c.create(&context);
+    QVERIFY(obj);
+
+    QQmlPropertyMap *qmlPropertyMap = obj->findChild<QQmlPropertyMap*>(QString("qmlPropertyMap"));
+    QVERIFY(qmlPropertyMap);
+
+    qmlPropertyMap->insert("greeting", QString("Hello world!"));
+    QTRY_COMPARE(obj->property("myProp").toString(), QString("Hello world!"));
+
+    delete obj;
+
+}
+
 QTEST_MAIN(tst_QQmlPropertyMap)
 
 #include "tst_qqmlpropertymap.moc"