From 491bf79d5f49eef35d34749644272d4203a4c060 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen <erik.verbruggen@nokia.com> Date: Tue, 6 Apr 2010 11:44:55 +0200 Subject: [PATCH] Changed QML reading in QML designer to use the interpreter for property types. --- src/libs/qmljs/qmljscheck.cpp | 6 + src/libs/qmljs/qmljsinterpreter.cpp | 46 +- src/libs/qmljs/qmljsinterpreter.h | 5 +- .../core/model/texttomodelmerger.cpp | 426 ++++++++++++------ .../core/model/texttomodelmerger.h | 9 +- 5 files changed, 327 insertions(+), 165 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index f6eb31a3239..4e0fd13abe8 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -302,6 +302,9 @@ bool Check::visit(UiArrayBinding *ast) return true; } +/// When something is changed here, also change ReadingContext::lookupProperty in +/// texttomodelmerger.cpp +/// ### Maybe put this into the context as a helper method. const Value *Check::checkScopeObjectMember(const UiQualifiedId *id) { QList<const ObjectValue *> scopeObjects = _context.scopeChain().qmlScopeObjects; @@ -311,6 +314,9 @@ const Value *Check::checkScopeObjectMember(const UiQualifiedId *id) if (! id) return 0; // ### error? + if (! id->name) // possible after error recovery + return 0; + QString propertyName = id->name->asString(); if (propertyName == QLatin1String("id") && ! id->next) diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index dea04577a90..db26ca7fb1b 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -111,6 +111,9 @@ public: : m_name(name) {} + QString name() const + { return m_name; } + void addKey(const QString &key, int value) { m_keys.append(key); m_values.append(value); } @@ -197,7 +200,9 @@ class FakeMetaObject { const FakeMetaObject *m_super; QString m_superName; QList<FakeMetaEnum> m_enums; + QHash<QString, int> m_enumNameToIndex; QList<FakeMetaProperty> m_props; + QHash<QString, int> m_propNameToIdx; QList<FakeMetaMethod> m_methods; QString m_defaultPropertyName; @@ -221,22 +226,26 @@ public: { return m_package; } void addEnum(const FakeMetaEnum &fakeEnum) - { m_enums.append(fakeEnum); } + { m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); } int enumeratorCount() const { return m_enums.size(); } int enumeratorOffset() const { return 0; } FakeMetaEnum enumerator(int index) const { return m_enums.at(index); } + int enumeratorIndex(const QString &name) const + { return m_enumNameToIndex.value(name, -1); } void addProperty(const FakeMetaProperty &property) - { m_props.append(property); } + { m_propNameToIdx.insert(property.name(), m_props.size()); m_props.append(property); } int propertyCount() const { return m_props.size(); } int propertyOffset() const { return 0; } FakeMetaProperty property(int index) const { return m_props.at(index); } + int propertyIndex(const QString &name) const + { return m_propNameToIdx.value(name, -1); } void addMethod(const FakeMetaMethod &method) { m_methods.append(method); } @@ -686,11 +695,6 @@ QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine) QmlObjectValue::~QmlObjectValue() {} -const Value *QmlObjectValue::lookupMember(const QString &name, Context *context) const -{ - return ObjectValue::lookupMember(name, context); -} - const Value *QmlObjectValue::findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const { *methodName = method.methodName(); @@ -844,6 +848,22 @@ int QmlObjectValue::minorVersion() const QString QmlObjectValue::defaultPropertyName() const { return _metaObject->defaultPropertyName(); } +QString QmlObjectValue::propertyType(const QString &propertyName) const +{ + for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) { + int propIdx = _metaObject->propertyIndex(propertyName); + if (propIdx != -1) { + return _metaObject->property(propIdx).typeName(); + } + } + return QString(); +} + +bool QmlObjectValue::isEnum(const QString &typeName) const +{ + return _metaObject->enumeratorIndex(typeName) != -1; +} + bool QmlObjectValue::isDerivedFrom(const FakeMetaObject *base) const { for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) { @@ -1646,7 +1666,7 @@ void ObjectValue::processMembers(MemberProcessor *processor) const } } -const Value *ObjectValue::lookupMember(const QString &name, Context *context) const +const Value *ObjectValue::lookupMember(const QString &name, Context *context, bool examinePrototypes) const { if (const Value *m = _members.value(name)) return m; @@ -1657,10 +1677,12 @@ const Value *ObjectValue::lookupMember(const QString &name, Context *context) co return slowLookup.value(); } - const ObjectValue *prototypeObject = prototype(context); - if (prototypeObject) { - if (const Value *m = prototypeObject->lookupMember(name, context)) - return m; + if (examinePrototypes) { + const ObjectValue *prototypeObject = prototype(context); + if (prototypeObject) { + if (const Value *m = prototypeObject->lookupMember(name, context)) + return m; + } } return 0; diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 76b779a7735..461e6a718fe 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -385,7 +385,7 @@ public: virtual void setProperty(const QString &name, const Value *value); virtual void removeProperty(const QString &name); - virtual const Value *lookupMember(const QString &name, Context *context) const; + virtual const Value *lookupMember(const QString &name, Context *context, bool examinePrototypes = true) const; // Value interface virtual const ObjectValue *asObjectValue() const; @@ -410,7 +410,6 @@ public: QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine); virtual ~QmlObjectValue(); - virtual const Value *lookupMember(const QString &name, Context *context) const; virtual void processMembers(MemberProcessor *processor) const; const Value *propertyValue(const FakeMetaProperty &prop) const; @@ -418,6 +417,8 @@ public: int majorVersion() const; int minorVersion() const; QString defaultPropertyName() const; + QString propertyType(const QString &propertyName) const; + bool isEnum(const QString &typeName) 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 af77acafe8e..82e4c01f0ae 100644 --- a/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/core/model/texttomodelmerger.cpp @@ -31,16 +31,16 @@ #include "bindingproperty.h" #include "filemanager/firstdefinitionfinder.h" #include "filemanager/objectlengthcalculator.h" -#include "metainfo.h" -#include "nodemetainfo.h" #include "nodeproperty.h" -#include "propertymetainfo.h" #include "propertyparser.h" #include "textmodifier.h" #include "texttomodelmerger.h" #include "rewriterview.h" #include "variantproperty.h" + #include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljslink.h> +#include <qmljs/qmljsscopebuilder.h> #include <qmljs/parser/qmljsast_p.h> #include <QtDeclarative/QDeclarativeComponent> @@ -50,51 +50,6 @@ using namespace QmlJS; using namespace QmlJS::AST; -namespace QmlDesigner { -namespace Internal { - -struct ReadingContext { - ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc, - const QStringList importPaths) - : snapshot(snapshot) - , doc(doc) - , engine(new Interpreter::Engine) - , ctxt(new Interpreter::Context(engine)) - { - ctxt->build(QList<Node *>(), doc, snapshot, importPaths); - } - - ~ReadingContext() - { delete ctxt; delete engine; } - - void lookup(UiQualifiedId *astTypeNode, QString &typeName, int &majorVersion, int &minorVersion) - { - const Interpreter::ObjectValue *value = ctxt->lookupType(doc.data(), astTypeNode); - if (const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(value)) { - typeName = qmlValue->packageName() + QLatin1String("/") + qmlValue->className(); - majorVersion = qmlValue->majorVersion(); - minorVersion = qmlValue->minorVersion(); - } else if (value) { - for (UiQualifiedId *iter = astTypeNode; iter; iter = iter->next) - if (!iter->next && iter->name) - typeName = iter->name->asString(); - majorVersion = Interpreter::QmlObjectValue::NoVersion; - minorVersion = Interpreter::QmlObjectValue::NoVersion; - } - } - - Snapshot snapshot; - Document::Ptr doc; - Interpreter::Engine *engine; - Interpreter::Context *ctxt; -}; - -} // namespace Internal -} // namespace QmlDesigner - -using namespace QmlDesigner; -using namespace QmlDesigner::Internal; - namespace { static inline QString stripQuotes(const QString &str) @@ -160,13 +115,6 @@ static inline bool isLiteralValue(UiScriptBinding *script) return false; } -static inline bool isValidPropertyForNode(const ModelNode &modelNode, - const QString &propertyName) -{ - return modelNode.metaInfo().hasProperty(propertyName, true) - || modelNode.type() == QLatin1String("Qt/PropertyChanges"); -} - static inline int propertyType(const QString &typeName) { if (typeName == QLatin1String("bool")) @@ -191,8 +139,245 @@ static inline int propertyType(const QString &typeName) return -1; } +static inline QVariant convertDynamicPropertyValueToVariant(const QString &astValue, + const QString &astType) +{ + const QString cleanedValue = stripQuotes(astValue.trimmed()); + + if (astType.isEmpty()) + return QString(); + + const int type = propertyType(astType); + if (type == QMetaType::type("QVariant")) { + if (cleanedValue.isNull()) // Explicitly isNull, NOT isEmpty! + return QVariant(static_cast<QVariant::Type>(type)); + else + return QVariant(cleanedValue); + } else { + QVariant value = QVariant(cleanedValue); + value.convert(static_cast<QVariant::Type>(type)); + return value; + } +} + } // anonymous namespace +namespace QmlDesigner { +namespace Internal { + +class ReadingContext +{ +public: + ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc, + const QStringList importPaths) + : m_snapshot(snapshot) + , m_doc(doc) + , m_engine(new Interpreter::Engine) + , m_context(new Interpreter::Context(m_engine)) + , m_link(m_context, doc, snapshot, importPaths) + , m_scopeBuilder(doc, m_context) + { + m_context->build(QList<Node *>(), doc, snapshot, importPaths); + m_link.scopeChainAt(doc); + } + + ~ReadingContext() + { delete m_context; delete m_engine; } + + Document::Ptr doc() const + { return m_doc; } + + void enterScope(Node *node) + { m_scopeBuilder.push(node); } + + void leaveScope() + { m_scopeBuilder.pop(); } + + void lookup(UiQualifiedId *astTypeNode, QString &typeName, int &majorVersion, + int &minorVersion, QString &defaultPropertyName) + { + const Interpreter::ObjectValue *value = m_context->lookupType(m_doc.data(), astTypeNode); + const Interpreter::QmlObjectValue * qmlValue = dynamic_cast<const Interpreter::QmlObjectValue *>(value); + if (qmlValue) { + typeName = qmlValue->packageName() + QLatin1String("/") + qmlValue->className(); + majorVersion = qmlValue->majorVersion(); + minorVersion = qmlValue->minorVersion(); + defaultPropertyName = qmlValue->defaultPropertyName(); + } else if (value) { + for (UiQualifiedId *iter = astTypeNode; iter; iter = iter->next) + if (!iter->next && iter->name) + typeName = iter->name->asString(); + majorVersion = Interpreter::QmlObjectValue::NoVersion; + minorVersion = Interpreter::QmlObjectValue::NoVersion; + } + } + + /// When something is changed here, also change Check::checkScopeObjectMember in + /// qmljscheck.cpp + /// ### Maybe put this into the context as a helper method. + bool lookupProperty(const UiQualifiedId *id, const Interpreter::Value **property = 0, const Interpreter::ObjectValue **parentObject = 0, QString *name = 0) + { + QList<const Interpreter::ObjectValue *> scopeObjects = m_context->scopeChain().qmlScopeObjects; + if (scopeObjects.isEmpty()) + return false; + + if (! id) + return false; // ### error? + + if (! id->name) // possible after error recovery + return false; + + QString propertyName = id->name->asString(); + if (name) + *name = propertyName; + + if (propertyName == QLatin1String("id") && ! id->next) + return false; // ### should probably be a special value + + // attached properties + bool isAttachedProperty = false; + if (! propertyName.isEmpty() && propertyName[0].isUpper()) { + isAttachedProperty = true; + scopeObjects += m_context->scopeChain().qmlTypes; + } + + if (scopeObjects.isEmpty()) + return false; + + // global lookup for first part of id + const Interpreter::ObjectValue *objectValue = 0; + const Interpreter::Value *value = 0; + for (int i = scopeObjects.size() - 1; i >= 0; --i) { + objectValue = scopeObjects[i]; + value = objectValue->lookupMember(propertyName, m_context); + if (value) + break; + } + if (parentObject) + *parentObject = objectValue; + if (!value) { + qWarning() << "Skipping invalid property name" << propertyName; + return false; + } + + // can't look up members for attached properties + if (isAttachedProperty) + return false; + + // member lookup + const UiQualifiedId *idPart = id; + while (idPart->next) { + objectValue = Interpreter::value_cast<const Interpreter::ObjectValue *>(value); + if (! objectValue) { +// if (idPart->name) +// qDebug() << idPart->name->asString() << "has no property named" +// << propertyName; + return false; + } + if (parentObject) + *parentObject = objectValue; + + if (! idPart->next->name) { + // somebody typed "id." and error recovery still gave us a valid tree, + // so just bail out here. + return false; + } + + idPart = idPart->next; + propertyName = idPart->name->asString(); + if (name) + *name = propertyName; + + value = objectValue->lookupMember(propertyName, m_context); + if (! value) { +// if (idPart->name) +// qDebug() << "In" << idPart->name->asString() << ":" +// << objectValue->className() << "has no property named" +// << propertyName; + return false; + } + } + + if (property) + *property = value; + return true; + } + + bool isArrayProperty(const Interpreter::Value *value) + { + if (!value) + return false; + const Interpreter::ObjectValue *objectValue = value->asObjectValue(); + if (!objectValue) + return false; + + return objectValue->prototype(m_context) == m_engine->arrayPrototype(); + } + + QVariant convertToVariant(const QString &astValue, UiQualifiedId *propertyId) + { + const QString cleanedValue = stripQuotes(astValue.trimmed()); + const Interpreter::Value *property = 0; + const Interpreter::ObjectValue *containingObject = 0; + QString name; + if (!lookupProperty(propertyId, &property, &containingObject, &name)) { + qWarning() << "Unknown property" << flatten(propertyId) + << "on line" << propertyId->identifierToken.startLine + << "column" << propertyId->identifierToken.startColumn; + return QVariant(cleanedValue); + } + + for (const Interpreter::ObjectValue *iter = containingObject; iter; iter = iter->prototype(m_context)) { + if (iter->lookupMember(name, m_context, false)) { + containingObject = iter; + break; + } + } + + if (const Interpreter::QmlObjectValue * qmlObject = dynamic_cast<const Interpreter::QmlObjectValue *>(containingObject)) { + const QString typeName = qmlObject->propertyType(name); + if (qmlObject->isEnum(typeName)) { + return QVariant(cleanedValue); + } else { + int type = QMetaType::type(typeName.toUtf8().constData()); + QVariant result; + if (type) + result = PropertyParser::read(type, cleanedValue); + if (result.isValid()) + return result; + } + } + + QVariant v(cleanedValue); + if (property->asBooleanValue()) { + v.convert(QVariant::Bool); + } else if (property->asColorValue()) { + v.convert(QVariant::Color); + } else if (property->asNumberValue()) { + v.convert(QVariant::Double); + } else if (property->asStringValue()) { + // nothing to do + } else if (property->asEasingCurveNameValue()) { + // nothing to do + } + return v; + } + +private: + Snapshot m_snapshot; + Document::Ptr m_doc; + Interpreter::Engine *m_engine; + Interpreter::Context *m_context; + Link m_link; + ScopeBuilder m_scopeBuilder; +}; + +} // namespace Internal +} // namespace QmlDesigner + +using namespace QmlDesigner; +using namespace QmlDesigner::Internal; + static inline bool equals(const QVariant &a, const QVariant &b) { if (a.type() == QVariant::Double && b.type() == QVariant::Double) @@ -237,14 +422,14 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc, if (import->fileName) { const QString strippedFileName = stripQuotes(import->fileName->asString()); - Import newImport(Import::createFileImport(strippedFileName, - version, as)); + const Import newImport = Import::createFileImport(strippedFileName, + version, as); if (!existingImports.remove(newImport)) differenceHandler.modelMissesImport(newImport); } else { - Import newImport(Import::createLibraryImport(flatten(import->importUri), - as, version)); + const Import newImport = + Import::createLibraryImport(flatten(import->importUri), as, version); if (!existingImports.remove(newImport)) differenceHandler.modelMissesImport(newImport); @@ -342,10 +527,10 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, m_rewriterView->positionStorage()->setNodeOffset(modelNode, astObjectType->identifierToken.offset); - QString typeName; + QString typeName, defaultPropertyName; int majorVersion; int minorVersion; - context->lookup(astObjectType, typeName, majorVersion, minorVersion); + context->lookup(astObjectType, typeName, majorVersion, minorVersion, defaultPropertyName); if (typeName.isEmpty()) { qWarning() << "Skipping node with unknown type" << flatten(astObjectType); @@ -363,6 +548,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, return; // the difference handler will create a new node, so we're done. } + context->enterScope(astNode); + QSet<QString> modelPropertyNames = QSet<QString>::fromList(modelNode.propertyNames()); QList<UiObjectMember *> defaultPropertyItems; @@ -373,7 +560,7 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, if (UiArrayBinding *array = cast<UiArrayBinding *>(member)) { const QString astPropertyName = flatten(array->qualifiedId); - if (isValidPropertyForNode(modelNode, astPropertyName)) { + if (typeName == QLatin1String("Qt/PropertyChanges") || context->lookupProperty(array->qualifiedId)) { AbstractProperty modelProperty = modelNode.property(astPropertyName); QList<UiObjectMember *> arrayMembers; for (UiArrayMemberList *iter = array->members; iter; iter = iter->next) @@ -393,10 +580,10 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, if (binding->hasOnToken) { // skip value sources } else { - if (isValidPropertyForNode(modelNode, astPropertyName)) { + const Interpreter::Value *propertyType; + if (context->lookupProperty(binding->qualifiedId, &propertyType) || typeName == QLatin1String("Qt/PropertyChanges")) { AbstractProperty modelProperty = modelNode.property(astPropertyName); - if (modelProperty.metaInfo().isValid() - && modelProperty.metaInfo().isListProperty()) { + if (context->isArrayProperty(propertyType)) { syncArrayProperty(modelProperty, QList<QmlJS::AST::UiObjectMember*>() << member, context, differenceHandler); } else { syncNodeProperty(modelProperty, binding, context, differenceHandler); @@ -411,7 +598,7 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, const QString astPropertyName = flatten(script->qualifiedId); QString astValue; if (script->statement) { - astValue = textAt(context->doc, + astValue = textAt(context->doc(), script->statement->firstSourceLocation(), script->statement->lastSourceLocation()); astValue = astValue.trimmed(); @@ -425,16 +612,24 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, } else if (isSignalPropertyName(astPropertyName)) { // skip signals } else if (isLiteralValue(script)) { - if (isValidPropertyForNode(modelNode, astPropertyName)) { + if (typeName == QLatin1String("Qt/PropertyChanges")) { AbstractProperty modelProperty = modelNode.property(astPropertyName); - syncVariantProperty(modelProperty, astPropertyName, astValue, QString(), differenceHandler); + const QVariant variantValue(astValue); + syncVariantProperty(modelProperty, variantValue, QString(), differenceHandler); modelPropertyNames.remove(astPropertyName); } else { - qWarning() << "Skipping invalid variant property" << astPropertyName - << "for node type" << modelNode.type(); + const QVariant variantValue = context->convertToVariant(astValue, script->qualifiedId); + if (variantValue.isValid()) { + AbstractProperty modelProperty = modelNode.property(astPropertyName); + syncVariantProperty(modelProperty, variantValue, QString(), differenceHandler); + modelPropertyNames.remove(astPropertyName); + } else { + qWarning() << "Skipping invalid variant property" << astPropertyName + << "for node type" << modelNode.type(); + } } } else { - if (isValidPropertyForNode(modelNode, astPropertyName)) { + if (typeName == QLatin1String("Qt/PropertyChanges") || context->lookupProperty(script->qualifiedId)) { AbstractProperty modelProperty = modelNode.property(astPropertyName); syncExpressionProperty(modelProperty, astValue, differenceHandler); modelPropertyNames.remove(astPropertyName); @@ -453,15 +648,17 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, const QString astName = property->name->asString(); QString astValue; if (property->expression) - astValue = textAt(context->doc, + astValue = textAt(context->doc(), property->expression->firstSourceLocation(), property->expression->lastSourceLocation()); const QString astType = property->memberType->asString(); AbstractProperty modelProperty = modelNode.property(astName); - if (!property->expression || isLiteralValue(property->expression)) - syncVariantProperty(modelProperty, astName, astValue, astType, differenceHandler); - else + if (!property->expression || isLiteralValue(property->expression)) { + const QVariant variantValue = convertDynamicPropertyValueToVariant(astValue, astType); + syncVariantProperty(modelProperty, variantValue, astType, differenceHandler); + } else { syncExpressionProperty(modelProperty, astValue, differenceHandler); + } modelPropertyNames.remove(astName); } else { qWarning() << "Found an unknown QML value."; @@ -469,7 +666,6 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, } if (!defaultPropertyItems.isEmpty()) { - QString defaultPropertyName = modelNode.metaInfo().defaultProperty(); if (defaultPropertyName.isEmpty()) { if (modelNode.type() != QLatin1String("Qt/Component")) qWarning() << "No default property for node type" << modelNode.type() << ", ignoring child items."; @@ -494,6 +690,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, // property deleted. differenceHandler.propertyAbsentFromQml(modelProperty); } + + context->leaveScope(); } void TextToModelMerger::syncNodeId(ModelNode &modelNode, const QString &astObjectId, @@ -521,10 +719,10 @@ void TextToModelMerger::syncNodeProperty(AbstractProperty &modelProperty, ReadingContext *context, DifferenceHandler &differenceHandler) { - QString typeName; + QString typeName, dummy; int majorVersion; int minorVersion; - context->lookup(binding->qualifiedTypeNameId, typeName, majorVersion, minorVersion); + context->lookup(binding->qualifiedTypeNameId, typeName, majorVersion, minorVersion, dummy); if (typeName.isEmpty()) { qWarning() << "Skipping node with unknown type" << flatten(binding->qualifiedTypeNameId); @@ -573,29 +771,23 @@ void TextToModelMerger::syncArrayProperty(AbstractProperty &modelProperty, } void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty, - const QString &astName, - const QString &astValue, + const QVariant &astValue, const QString &astType, DifferenceHandler &differenceHandler) { - const QVariant astVariantValue = convertToVariant(modelProperty.parentModelNode(), - astName, - astValue, - astType); - if (modelProperty.isVariantProperty()) { VariantProperty modelVariantProperty = modelProperty.toVariantProperty(); - if (!equals(modelVariantProperty.value(), astVariantValue) + if (!equals(modelVariantProperty.value(), astValue) || !astType.isEmpty() != modelVariantProperty.isDynamic() || astType != modelVariantProperty.dynamicTypeName()) { differenceHandler.variantValuesDiffer(modelVariantProperty, - astVariantValue, + astValue, astType); } } else { differenceHandler.shouldBeVariantProperty(modelProperty, - astVariantValue, + astValue, astType); } } @@ -644,60 +836,6 @@ ModelNode TextToModelMerger::createModelNode(const QString &typeName, return newNode; } -QVariant TextToModelMerger::convertToVariant(const ModelNode &node, - const QString &astName, - const QString &astValue, - const QString &astType) -{ - const QString cleanedValue = stripQuotes(astValue.trimmed()); - const NodeMetaInfo nodeMetaInfo = node.metaInfo(); - - if (!astType.isEmpty()) { - const int type = propertyType(astType); - if (type == QMetaType::type("QVariant")) { - if (cleanedValue.isNull()) // Explicitly isNull, NOT isEmpty! - return QVariant(static_cast<QVariant::Type>(type)); - else - return QVariant(cleanedValue); - } else { - QVariant value = QVariant(cleanedValue); - value.convert(static_cast<QVariant::Type>(type)); - return value; - } - - const QString typeName = QMetaType::typeName(type); - return Internal::PropertyParser::read(typeName, astValue, nodeMetaInfo.metaInfo()); - } - - if (nodeMetaInfo.isValid()) { - const PropertyMetaInfo propertyMetaInfo = nodeMetaInfo.property(astName, true); - - if (propertyMetaInfo.isValid()) { - QVariant::Type type = propertyMetaInfo.variantTypeId(); - if (type == QVariant::Invalid) { - const QString propType = propertyMetaInfo.type(); -// qDebug() << "converting" << cleanedValue << "to" << propType; - return Internal::PropertyParser::read(propType, cleanedValue, node.metaInfo().metaInfo()); - } else { - return Internal::PropertyParser::read(type, cleanedValue); - } - } else if (node.type() == QLatin1String("Qt/PropertyChanges")) { - // In the future, we should do the type resolving in a second pass, or delay setting properties until the full file has been parsed. - return QVariant(cleanedValue); - } else { - qWarning() << "Unknown property" << astName - << "in node" << node.type() - << "with value" << cleanedValue; - return QVariant(); - } - } else { - qWarning() << "Unknown property" << astName - << "in node" << node.type() - << "with value" << cleanedValue; - return QVariant::fromValue(cleanedValue); - } -} - void ModelValidator::modelMissesImport(const Import &import) { Q_ASSERT(m_merger->view()->model()->imports().contains(import)); @@ -896,10 +1034,10 @@ ModelNode ModelAmender::listPropertyMissingModelNode(NodeListProperty &modelProp if (!astObjectType || !astInitializer) return ModelNode(); - QString typeName; + QString typeName, dummy; int majorVersion; int minorVersion; - context->lookup(astObjectType, typeName, majorVersion, minorVersion); + context->lookup(astObjectType, typeName, majorVersion, minorVersion, dummy); if (typeName.isEmpty()) { qWarning() << "Skipping node with unknown type" << flatten(astObjectType); diff --git a/src/plugins/qmldesigner/core/model/texttomodelmerger.h b/src/plugins/qmldesigner/core/model/texttomodelmerger.h index f57dead67fb..14fdf03b67d 100644 --- a/src/plugins/qmldesigner/core/model/texttomodelmerger.h +++ b/src/plugins/qmldesigner/core/model/texttomodelmerger.h @@ -42,8 +42,8 @@ class CORESHARED_EXPORT RewriterView; namespace Internal { -struct ReadingContext; class DifferenceHandler; +class ReadingContext; class TextToModelMerger { @@ -82,8 +82,7 @@ public: ReadingContext *context, DifferenceHandler &differenceHandler); void syncVariantProperty(AbstractProperty &modelProperty, - const QString &astName, - const QString &astValue, + const QVariant &astValue, const QString &astType, DifferenceHandler &differenceHandler); void syncNodeListProperty(NodeListProperty &modelListProperty, @@ -96,10 +95,6 @@ public: QmlJS::AST::UiObjectMember *astNode, ReadingContext *context, DifferenceHandler &differenceHandler); - static QVariant convertToVariant(const ModelNode &node, - const QString &astName, - const QString &astValue, - const QString &astType); private: void setupComponent(const ModelNode &node); -- GitLab