Add enum values from related types
authorMatthew Vogt <matthew.vogt@nokia.com>
Fri, 22 Jun 2012 05:32:46 +0000 (15:32 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 27 Jun 2012 00:28:40 +0000 (02:28 +0200)
If moc marks a type as being related to another type (by using that
type's enums or properties), then include the enum values exported
by the related type in those exposed by the dependent type.

Task-number: QTBUG-22675
Change-Id: I78e72791a4f470200a9ba986a865ffac6c873725
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
13 files changed:
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmlmetatype.cpp
src/qml/qml/qqmlmetatype_p.h
src/qml/qml/v8/qv8typewrapper.cpp
tests/auto/qml/qqmlecmascript/data/assignBasicTypes.2.qml
tests/auto/qml/qqmlecmascript/data/assignBasicTypes.qml
tests/auto/qml/qqmlecmascript/data/enums.1.qml
tests/auto/qml/qqmlecmascript/data/enums.3.qml
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml
tests/auto/qml/qqmllanguage/testtypes.h
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp

index 13ff9e8..fd42ab8 100644 (file)
@@ -2536,7 +2536,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
         return true;
 
     int value = 0;
-    bool ok;
+    bool ok = false;
 
     if (type && toQmlType(obj) == type) {
         // When these two match, we can short cut the search
@@ -2547,13 +2547,15 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
         }
     } else {
         // Otherwise we have to search the whole type
-        // This matches the logic in QV8TypeWrapper
-        QByteArray enumName = enumValue.toUtf8();
-        const QMetaObject *metaObject = type ? type->baseMetaObject() : StaticQtMetaObject::get();
-        ok = false;
-        for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
-            QMetaEnum e = metaObject->enumerator(ii);
-            value = e.keyToValue(enumName.constData(), &ok);
+        if (type) {
+            value = type->enumValue(QHashedStringRef(enumValue), &ok);
+        } else {
+            QByteArray enumName = enumValue.toUtf8();
+            const QMetaObject *metaObject = StaticQtMetaObject::get();
+            for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
+                QMetaEnum e = metaObject->enumerator(ii);
+                value = e.keyToValue(enumName.constData(), &ok);
+            }
         }
     }
 
@@ -2572,14 +2574,14 @@ int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray&
 {
     Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
     *ok = false;
-    QQmlType *type = 0;
+
     if (scope != QLatin1String("Qt")) {
+        QQmlType *type = 0;
         unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
-        if (!type)
-            return -1;
-
+        return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
     }
-    const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
+
+    const QMetaObject *mo = StaticQtMetaObject::get();
     int i = mo->enumeratorCount();
     while (i--) {
         int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
index 80fb3ed..34c9cce 100644 (file)
@@ -153,6 +153,7 @@ public:
 
     void init() const;
     void initEnums() const;
+    void insertEnums(const QMetaObject *metaObject) const;
 
     bool m_isInterface : 1;
     const char *m_iid;
@@ -487,16 +488,28 @@ void QQmlTypePrivate::initEnums() const
     QWriteLocker lock(metaTypeDataLock());
     if (m_isEnumSetup) return;
 
-    const QMetaObject *metaObject = m_baseMetaObject;
-    for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+    insertEnums(m_baseMetaObject);
 
-        QMetaEnum e = metaObject->enumerator(ii);
+    m_isEnumSetup = true;
+}
 
-        for (int jj = 0; jj < e.keyCount(); ++jj) 
-            m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
+{
+    // Add any enum values defined by 'related' classes
+    if (metaObject->d.relatedMetaObjects) {
+        const QMetaObject **related = metaObject->d.relatedMetaObjects;
+        if (related) {
+            while (*related)
+                insertEnums(*related++);
+        }
     }
 
-    m_isEnumSetup = true;
+    // Add any enum values defined by this class, overwriting any inherited values
+    for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+        QMetaEnum e = metaObject->enumerator(ii);
+        for (int jj = 0; jj < e.keyCount(); ++jj)
+            m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+    }
 }
 
 QByteArray QQmlType::typeName() const
@@ -671,20 +684,49 @@ int QQmlType::index() const
     return d->m_index;
 }
 
-int QQmlType::enumValue(const QHashedStringRef &name) const
+int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
 {
+    Q_ASSERT(ok);
+    *ok = true;
+
     d->initEnums();
 
     int *rv = d->m_enums.value(name);
-    return rv?*rv:-1;
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
 }
 
-int QQmlType::enumValue(const QHashedV8String &name) const
+int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
 {
+    Q_ASSERT(ok);
+    *ok = true;
+
     d->initEnums();
 
     int *rv = d->m_enums.value(name);
-    return rv?*rv:-1;
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
+}
+
+int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
+{
+    Q_ASSERT(ok);
+    *ok = true;
+
+    d->initEnums();
+
+    int *rv = d->m_enums.value(name);
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
 }
 
 QQmlTypeModule::QQmlTypeModule()
index fbbc410..fbba733 100644 (file)
@@ -143,6 +143,7 @@ private:
     static CompareFunction anchorLineCompareFunction;
 };
 
+class QHashedCStringRef;
 class QHashedV8String;
 class Q_QML_PRIVATE_EXPORT QQmlType
 {
@@ -191,8 +192,9 @@ public:
 
     int index() const;
 
-    int enumValue(const QHashedStringRef &) const;
-    int enumValue(const QHashedV8String &) const;
+    int enumValue(const QHashedStringRef &, bool *ok) const;
+    int enumValue(const QHashedCStringRef &, bool *ok) const;
+    int enumValue(const QHashedV8String &, bool *ok) const;
 private:
     QQmlType *superType() const;
     friend class QQmlTypePrivate;
index dbf369e..ff7e599 100644 (file)
@@ -173,8 +173,9 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
         QQmlType *type = resource->type;
 
         if (QV8Engine::startsWithUpper(property)) {
-            int value = type->enumValue(propertystring);
-            if (-1 != value)
+            bool ok = false;
+            int value = type->enumValue(propertystring, &ok);
+            if (ok)
                 return v8::Integer::New(value);
 
             // Fall through to return empty handle
index 2c79729..ff6d731 100644 (file)
@@ -3,6 +3,7 @@ import Qt.test 1.0
 MyTypeObject {
     flagProperty: if(1) "FlagVal1 | FlagVal3"
     enumProperty: if(1) "EnumVal2"
+    relatedEnumProperty: if(1) "RelatedValue"
     stringProperty: if(1) "Hello World!"
     uintProperty: if(1) 10
     intProperty: if(1) -19
index 86ff6b6..ce3511f 100644 (file)
@@ -5,6 +5,7 @@ MyTypeObject {
     Component.onCompleted: {
         flagProperty = "FlagVal1 | FlagVal3"
         enumProperty = "EnumVal2"
+        relatedEnumProperty = "RelatedValue"
         stringProperty = "Hello World!"
         uintProperty = 10
         intProperty = -19
index 6351823..b9295c5 100644 (file)
@@ -2,6 +2,18 @@ import Qt.test 1.0
 import Qt.test 1.0 as Namespace
 
 MyQmlObject {
+    // Enum property type
+    enumProperty: MyQmlObject.EnumValue2
+
+    // Enum property whose value is from a related type
+    relatedEnumProperty: MyQmlObject.RelatedValue
+
+    // Enum property whose value is defined in an unrelated type
+    unrelatedEnumProperty: MyTypeObject.RelatedValue
+
+    // Enum property whose value is defined in the Qt namespace
+    qtEnumProperty: Qt.CaseInsensitive
+
     // Enums from non-namespaced type
     property int a: MyQmlObject.EnumValue1
     property int b: MyQmlObject.EnumValue2
@@ -17,4 +29,10 @@ MyQmlObject {
     // Test that enums don't mask attached properties
     property int i: MyQmlObject.value
     property int j: Namespace.MyQmlObject.value
+
+    // Enums from a related type
+    property int k: MyQmlObject.RelatedValue
+
+    // Enum values defined both in a type and a related type
+    property int l: MyQmlObject.MultiplyDefined
 }
index fd3432f..aaa6a33 100644 (file)
@@ -22,6 +22,9 @@ Item {
     // -1 enum
     property int j: MyQmlObject.EnumValue5
 
+    // Enums from a related type
+    property int k: MyQmlObject.RelatedValue
+
     // Count the onChanged signals to see whether
     // they're assigned as literals or via bindings
     property int ac: 0
@@ -33,6 +36,7 @@ Item {
     property int hc: 0
     property int ic: 0
     property int jc: 0
+    property int kc: 0
 
     onAChanged: ac++
     onBChanged: bc++
@@ -43,4 +47,5 @@ Item {
     onHChanged: hc++
     onIChanged: ic++
     onJChanged: jc++
+    onKChanged: kc++
 }
index ab44d59..06e54ea 100644 (file)
@@ -86,11 +86,22 @@ private:
     int m_value2;
 };
 
+class MyEnumContainer : public QObject
+{
+    Q_OBJECT
+    Q_ENUMS(RelatedEnum)
+
+public:
+    enum RelatedEnum { RelatedInvalid = -1, RelatedValue = 42, MultiplyDefined = 666 };
+};
+
 class MyQmlObject : public QObject
 {
     Q_OBJECT
     Q_ENUMS(MyEnum)
     Q_ENUMS(MyEnum2)
+    Q_ENUMS(MyEnum3)
+    Q_ENUMS(MyEnumContainer::RelatedEnum)
     Q_PROPERTY(int deleteOnSet READ deleteOnSet WRITE setDeleteOnSet)
     Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT)
     Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT)
@@ -106,12 +117,17 @@ class MyQmlObject : public QObject
     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged)
     Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
     Q_PROPERTY(QJSValue qjsvalueWithReset READ qjsvalue WRITE setQJSValue RESET resetQJSValue NOTIFY qjsvalueChanged)
+    Q_PROPERTY(MyEnum enumProperty READ enumProperty WRITE setEnumProperty)
+    Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty)
+    Q_PROPERTY(MyEnumContainer::RelatedEnum unrelatedEnumProperty READ unrelatedEnumProperty WRITE setUnrelatedEnumProperty)
+    Q_PROPERTY(MyEnum qtEnumProperty READ qtEnumProperty WRITE setQtEnumProperty)
 
 public:
     MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13), m_intProperty(0), m_buttons(0) {}
 
     enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 };
     enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3, EnumValue5 = -1 };
+    enum MyEnum3 { MultiplyDefined = 333 };
 
     bool trueProperty() const { return true; }
     bool falseProperty() const { return false; }
@@ -189,6 +205,38 @@ public:
     
     Q_INVOKABLE MyEnum2 getEnumValue() const { return EnumValue4; }
 
+    MyEnum enumPropertyValue;
+    MyEnum enumProperty() const {
+        return enumPropertyValue;
+    }
+    void setEnumProperty(MyEnum v) {
+        enumPropertyValue = v;
+    }
+
+    MyEnumContainer::RelatedEnum relatedEnumPropertyValue;
+    MyEnumContainer::RelatedEnum relatedEnumProperty() const {
+        return relatedEnumPropertyValue;
+    }
+    void setRelatedEnumProperty(MyEnumContainer::RelatedEnum v) {
+        relatedEnumPropertyValue = v;
+    }
+
+    MyEnumContainer::RelatedEnum unrelatedEnumPropertyValue;
+    MyEnumContainer::RelatedEnum unrelatedEnumProperty() const {
+        return unrelatedEnumPropertyValue;
+    }
+    void setUnrelatedEnumProperty(MyEnumContainer::RelatedEnum v) {
+        unrelatedEnumPropertyValue = v;
+    }
+
+    MyEnum qtEnumPropertyValue;
+    MyEnum qtEnumProperty() const {
+        return qtEnumPropertyValue;
+    }
+    void setQtEnumProperty(MyEnum v) {
+        qtEnumPropertyValue = v;
+    }
+
 signals:
     void basicSignal();
     void argumentSignal(int a, QString b, qreal c, MyEnum2 d, Qt::MouseButtons e);
@@ -354,6 +402,7 @@ class MyTypeObject : public QObject
 {
     Q_OBJECT
     Q_ENUMS(MyEnum)
+    Q_ENUMS(MyEnumContainer::RelatedEnum)
     Q_FLAGS(MyFlags)
 
     Q_PROPERTY(QString id READ id WRITE setId)
@@ -361,6 +410,7 @@ class MyTypeObject : public QObject
     Q_PROPERTY(QQmlComponent *componentProperty READ componentProperty WRITE setComponentProperty)
     Q_PROPERTY(MyFlags flagProperty READ flagProperty WRITE setFlagProperty)
     Q_PROPERTY(MyEnum enumProperty READ enumProperty WRITE setEnumProperty)
+    Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty)
     Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
     Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty)
     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
@@ -433,6 +483,14 @@ public:
         enumPropertyValue = v;
     }
 
+    MyEnumContainer::RelatedEnum relatedEnumPropertyValue;
+    MyEnumContainer::RelatedEnum relatedEnumProperty() const {
+        return relatedEnumPropertyValue;
+    }
+    void setRelatedEnumProperty(MyEnumContainer::RelatedEnum v) {
+        relatedEnumPropertyValue = v;
+    }
+
     QString stringPropertyValue;
     QString stringProperty() const {
        return stringPropertyValue;
index c429ffa..e2f818c 100644 (file)
@@ -295,6 +295,7 @@ void tst_qqmlecmascript::assignBasicTypes()
     QVERIFY(object != 0);
     QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
     QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
+    QCOMPARE(object->relatedEnumProperty(), MyEnumContainer::RelatedValue);
     QCOMPARE(object->stringProperty(), QString("Hello World!"));
     QCOMPARE(object->uintProperty(), uint(10));
     QCOMPARE(object->intProperty(), -19);
@@ -323,6 +324,7 @@ void tst_qqmlecmascript::assignBasicTypes()
     QVERIFY(object != 0);
     QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
     QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
+    QCOMPARE(object->relatedEnumProperty(), MyEnumContainer::RelatedValue);
     QCOMPARE(object->stringProperty(), QString("Hello World!"));
     QCOMPARE(object->uintProperty(), uint(10));
     QCOMPARE(object->intProperty(), -19);
@@ -910,6 +912,10 @@ void tst_qqmlecmascript::enums()
     QObject *object = component.create();
     QVERIFY(object != 0);
 
+    QCOMPARE(object->property("enumProperty").toInt(), (int)MyQmlObject::EnumValue2);
+    QCOMPARE(object->property("relatedEnumProperty").toInt(), (int)MyEnumContainer::RelatedValue);
+    QCOMPARE(object->property("unrelatedEnumProperty").toInt(), (int)MyEnumContainer::RelatedValue);
+    QCOMPARE(object->property("qtEnumProperty").toInt(), (int)Qt::CaseInsensitive);
     QCOMPARE(object->property("a").toInt(), 0);
     QCOMPARE(object->property("b").toInt(), 1);
     QCOMPARE(object->property("c").toInt(), 2);
@@ -920,6 +926,8 @@ void tst_qqmlecmascript::enums()
     QCOMPARE(object->property("h").toInt(), 3);
     QCOMPARE(object->property("i").toInt(), 19);
     QCOMPARE(object->property("j").toInt(), 19);
+    QCOMPARE(object->property("k").toInt(), 42);
+    QCOMPARE(object->property("l").toInt(), 333);
 
     delete object;
     }
@@ -984,6 +992,7 @@ void tst_qqmlecmascript::enums()
     QCOMPARE(object->property("h").toInt(), 2);
     QCOMPARE(object->property("i").toInt(), 3);
     QCOMPARE(object->property("j").toInt(), -1);
+    QCOMPARE(object->property("k").toInt(), 42);
 
     // count of change signals
     QCOMPARE(object->property("ac").toInt(), 0);
@@ -995,6 +1004,7 @@ void tst_qqmlecmascript::enums()
     QCOMPARE(object->property("hc").toInt(), 1); // namespace -> binding
     QCOMPARE(object->property("ic").toInt(), 1); // namespace -> binding
     QCOMPARE(object->property("jc").toInt(), 0);
+    QCOMPARE(object->property("kc").toInt(), 0);
 
     delete object;
     }
index 697278e..4d54bc8 100644 (file)
@@ -1,9 +1,12 @@
 import Test 1.0
+import QtQuick 2.0
+
 MyTypeObject {
     flagProperty: "FlagVal1 | FlagVal3"
     enumProperty: "EnumVal2"
     qtEnumProperty: Qt.RichText
     mirroredEnumProperty: Qt.AlignHCenter
+    relatedEnumProperty: "RelatedValue"
     stringProperty: "Hello World!"
     uintProperty: 10
     intProperty: -19
index 50b6089..01f26c7 100644 (file)
@@ -205,11 +205,21 @@ private:
 };
 
 
+class MyEnumContainer : public QObject
+{
+    Q_OBJECT
+    Q_ENUMS(RelatedEnum)
+
+public:
+    enum RelatedEnum { RelatedInvalid = -1, RelatedValue = 42 };
+};
+
 class MyTypeObject : public QObject
 {
     Q_OBJECT
     Q_ENUMS(MyEnum)
     Q_ENUMS(MyMirroredEnum)
+    Q_ENUMS(MyEnumContainer::RelatedEnum)
     Q_FLAGS(MyFlags)
 
     Q_PROPERTY(QString id READ id WRITE setId)
@@ -220,6 +230,7 @@ class MyTypeObject : public QObject
     Q_PROPERTY(MyEnum readOnlyEnumProperty READ readOnlyEnumProperty)
     Q_PROPERTY(Qt::TextFormat qtEnumProperty READ qtEnumProperty WRITE setQtEnumProperty NOTIFY qtEnumPropertyChanged)
     Q_PROPERTY(MyMirroredEnum mirroredEnumProperty READ mirroredEnumProperty WRITE setMirroredEnumProperty NOTIFY mirroredEnumPropertyChanged)
+    Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty)
     Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged)
     Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty NOTIFY uintPropertyChanged)
     Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged)
@@ -323,6 +334,14 @@ public:
         emit mirroredEnumPropertyChanged();
     }
 
+    MyEnumContainer::RelatedEnum relatedEnumPropertyValue;
+    MyEnumContainer::RelatedEnum relatedEnumProperty() const {
+        return relatedEnumPropertyValue;
+    }
+    void setRelatedEnumProperty(MyEnumContainer::RelatedEnum v) {
+        relatedEnumPropertyValue = v;
+    }
+
     QString stringPropertyValue;
     QString stringProperty() const {
        return stringPropertyValue;
index 2f2f0a7..ed94eff 100644 (file)
@@ -587,6 +587,7 @@ void tst_qqmllanguage::assignBasicTypes()
     QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
     QCOMPARE(object->qtEnumProperty(), Qt::RichText);
     QCOMPARE(object->mirroredEnumProperty(), MyTypeObject::MirroredEnumVal3);
+    QCOMPARE(object->relatedEnumProperty(), MyEnumContainer::RelatedValue);
     QCOMPARE(object->stringProperty(), QString("Hello World!"));
     QCOMPARE(object->uintProperty(), uint(10));
     QCOMPARE(object->intProperty(), -19);