From 4ba9a1b0c2fb9e5566210f751e983e5d55b85799 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Tue, 6 Apr 2010 15:40:47 +0200
Subject: [PATCH] Fixed qualified-enum handling.

Done-with: ckamm
---
 src/libs/qmljs/qmljsinterpreter.cpp           | 13 ++++
 src/libs/qmljs/qmljsinterpreter.h             |  1 +
 .../core/model/texttomodelmerger.cpp          | 78 ++++++++++++++++++-
 3 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 514c734c23c..a7f8d916a1e 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -876,6 +876,19 @@ bool QmlObjectValue::isEnum(const QString &typeName) const
     return _metaObject->enumeratorIndex(typeName) != -1;
 }
 
+bool QmlObjectValue::enumContainsKey(const QString &enumName, const QString &enumKeyName) const
+{
+    int idx = _metaObject->enumeratorIndex(enumName);
+    if (idx == -1)
+        return false;
+    const FakeMetaEnum &fme = _metaObject->enumerator(idx);
+    for (int i = 0; i < fme.keyCount(); ++i) {
+        if (fme.key(i) == enumKeyName)
+            return true;
+    }
+    return false;
+}
+
 bool QmlObjectValue::isDerivedFrom(const FakeMetaObject *base) const
 {
     for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 97800977b7b..fc95e3f7deb 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -420,6 +420,7 @@ public:
     QString propertyType(const QString &propertyName) const;
     bool isListProperty(const QString &name) const;
     bool isEnum(const QString &typeName) const;
+    bool enumContainsKey(const QString &enumName, const QString &enumKeyName) const;
 
 protected:
     const Value *findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const;
diff --git a/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp
index 5a827cc5a78..92148dc0566 100644
--- a/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp
@@ -38,6 +38,7 @@
 #include "rewriterview.h"
 #include "variantproperty.h"
 
+#include <qmljs/qmljsevaluate.h>
 #include <qmljs/qmljsinterpreter.h>
 #include <qmljs/qmljslink.h>
 #include <qmljs/qmljsscopebuilder.h>
@@ -371,6 +372,65 @@ public:
         return v;
     }
 
+    QVariant convertToEnum(Statement *rhs, UiQualifiedId *propertyId)
+    {
+        ExpressionStatement *eStmt = cast<ExpressionStatement *>(rhs);
+        if (!eStmt || !eStmt->expression)
+            return QVariant();
+
+        const Interpreter::ObjectValue *containingObject = 0;
+        QString name;
+        if (!lookupProperty(propertyId, 0, &containingObject, &name)) {
+            return QVariant();
+        }
+
+        for (const Interpreter::ObjectValue *iter = containingObject; iter; iter = iter->prototype(m_context)) {
+            if (iter->lookupMember(name, m_context, false)) {
+                containingObject = iter;
+                break;
+            }
+        }
+        const Interpreter::QmlObjectValue * lhsQmlObject = dynamic_cast<const Interpreter::QmlObjectValue *>(containingObject);
+        if (!lhsQmlObject)
+            return QVariant();
+        const QString lhsPropertyTypeName = lhsQmlObject->propertyType(name);
+
+        const Interpreter::ObjectValue *rhsValueObject = 0;
+        QString rhsValueName;
+        if (IdentifierExpression *idExp = cast<IdentifierExpression *>(eStmt->expression)) {
+            if (!m_context->scopeChain().qmlScopeObjects.isEmpty())
+                rhsValueObject = m_context->scopeChain().qmlScopeObjects.last();
+            if (idExp->name)
+                rhsValueName = idExp->name->asString();
+        } else if (FieldMemberExpression *memberExp = cast<FieldMemberExpression *>(eStmt->expression)) {
+            Evaluate evaluate(m_context);
+            const Interpreter::Value *result = evaluate(memberExp->base);
+            rhsValueObject = result->asObjectValue();
+
+            if (memberExp->name)
+                rhsValueName = memberExp->name->asString();
+        }
+
+        if (!rhsValueObject)
+            return QVariant();
+
+        for (const Interpreter::ObjectValue *iter = rhsValueObject; iter; iter = iter->prototype(m_context)) {
+            if (iter->lookupMember(rhsValueName, m_context, false)) {
+                rhsValueObject = iter;
+                break;
+            }
+        }
+
+        const Interpreter::QmlObjectValue *rhsQmlObjectValue = dynamic_cast<const Interpreter::QmlObjectValue *>(rhsValueObject);
+        if (!rhsQmlObjectValue)
+            return QVariant();
+
+        if (rhsQmlObjectValue->enumContainsKey(lhsPropertyTypeName, rhsValueName))
+            return QVariant(rhsValueName);
+        else
+            return QVariant();
+    }
+
 private:
     Snapshot m_snapshot;
     Document::Ptr m_doc;
@@ -639,13 +699,23 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
                     }
                 }
             } else {
-                if (typeName == QLatin1String("Qt/PropertyChanges") || context->lookupProperty(script->qualifiedId)) {
+                // First see if it is a qualified enum:
+                const QVariant enumValue = context->convertToEnum(script->statement, script->qualifiedId);
+                if (enumValue.isValid()) {
+                    const QString astPropertyName = flatten(script->qualifiedId);
                     AbstractProperty modelProperty = modelNode.property(astPropertyName);
-                    syncExpressionProperty(modelProperty, astValue, differenceHandler);
+                    syncVariantProperty(modelProperty, enumValue, QString(), differenceHandler);
                     modelPropertyNames.remove(astPropertyName);
                 } else {
-                    qWarning() << "Skipping invalid expression property" << astPropertyName
-                               << "for node type" << modelNode.type();
+                    // apparently not, so:
+                    if (typeName == QLatin1String("Qt/PropertyChanges") || context->lookupProperty(script->qualifiedId)) {
+                        AbstractProperty modelProperty = modelNode.property(astPropertyName);
+                        syncExpressionProperty(modelProperty, astValue, differenceHandler);
+                        modelPropertyNames.remove(astPropertyName);
+                    } else {
+                        qWarning() << "Skipping invalid expression property" << astPropertyName
+                                << "for node type" << modelNode.type();
+                    }
                 }
             }
         } else if (UiPublicMember *property = cast<UiPublicMember *>(member)) {
-- 
GitLab