Switched QML designer to use the ast for loading.

This commit is contained in:
Erik Verbruggen
2010-03-16 13:10:18 +01:00
parent 8b7eacc19f
commit 68a463cf36
7 changed files with 694 additions and 256 deletions

View File

@@ -401,7 +401,7 @@ private:
QString _className; QString _className;
}; };
class QmlObjectValue: public ObjectValue class QMLJS_EXPORT QmlObjectValue: public ObjectValue
{ {
public: public:
static const int NoVersion; static const int NoVersion;

View File

@@ -22,5 +22,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
<dependencyList> <dependencyList>
<dependency name="Core" version="1.3.82"/> <dependency name="Core" version="1.3.82"/>
<dependency name="TextEditor" version="1.3.82"/> <dependency name="TextEditor" version="1.3.82"/>
<dependency name="QmlJSEditor" version="1.3.82"/>
</dependencyList> </dependencyList>
</plugin> </plugin>

View File

@@ -36,6 +36,10 @@
#include <texteditor/basetexteditor.h> #include <texteditor/basetexteditor.h>
namespace QmlJS {
class Snapshot;
} // namespace QmlJS
namespace QmlDesigner { namespace QmlDesigner {
class CORESHARED_EXPORT BaseTextEditModifier: public PlainTextEditModifier class CORESHARED_EXPORT BaseTextEditModifier: public PlainTextEditModifier
@@ -46,6 +50,8 @@ public:
virtual void indent(int offset, int length); virtual void indent(int offset, int length);
virtual int indentDepth() const; virtual int indentDepth() const;
static QmlJS::Snapshot getSnapshot();
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -29,9 +29,13 @@
#include "basetexteditmodifier.h" #include "basetexteditmodifier.h"
#include <extensionsystem/pluginmanager.h>
#include <qmljs/qmljsdocument.h>
#include <qmljseditor/qmljsmodelmanagerinterface.h>
#include <texteditor/tabsettings.h> #include <texteditor/tabsettings.h>
using namespace QmlDesigner; using namespace QmlDesigner;
using namespace QmlJSEditor;
BaseTextEditModifier::BaseTextEditModifier(TextEditor::BaseTextEditor *textEdit): BaseTextEditModifier::BaseTextEditModifier(TextEditor::BaseTextEditor *textEdit):
PlainTextEditModifier(textEdit) PlainTextEditModifier(textEdit)
@@ -63,3 +67,13 @@ int BaseTextEditModifier::indentDepth() const
return 0; return 0;
} }
} }
QmlJS::Snapshot BaseTextEditModifier::getSnapshot()
{
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
QmlJSEditor::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJSEditor::ModelManagerInterface>();
if (modelManager)
return modelManager->snapshot();
else
return QmlJS::Snapshot();
}

View File

@@ -34,17 +34,151 @@
#include "nodemetainfo.h" #include "nodemetainfo.h"
#include "nodeproperty.h" #include "nodeproperty.h"
#include "propertymetainfo.h" #include "propertymetainfo.h"
#include "basetexteditmodifier.h"
#include "texttomodelmerger.h" #include "texttomodelmerger.h"
#include "rewriterview.h" #include "rewriterview.h"
#include "variantproperty.h" #include "variantproperty.h"
#include <qmljseditor/qmljseditor.h>
#include <qmljs/qmljsinterpreter.h>
#include <qmljs/parser/qmljsast_p.h>
#include <QDeclarativeEngine> #include <QDeclarativeEngine>
#include <QSet> #include <QSet>
#include <private/qdeclarativedom_p.h> #include <private/qdeclarativedom_p.h>
using namespace QmlJS;
using namespace QmlJS::AST;
namespace QmlDesigner {
namespace Internal {
struct ReadingContext {
ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc)
: snapshot(snapshot)
, doc(doc)
, engine(new Interpreter::Engine)
, ctxt(new Interpreter::Context(engine))
{
ctxt->build(QList<Node *>(), doc, snapshot);
}
~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();
}
}
Snapshot snapshot;
Document::Ptr doc;
Interpreter::Engine *engine;
Interpreter::Context *ctxt;
};
} // namespace Internal
} // namespace QmlDesigner
using namespace QmlDesigner; using namespace QmlDesigner;
using namespace QmlDesigner::Internal; using namespace QmlDesigner::Internal;
namespace {
static inline QString stripQuotes(const QString &str)
{
if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
|| (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
return str.mid(1, str.length() - 2);
return str;
}
static inline bool isSignalPropertyName(const QString &signalName)
{
// see QmlCompiler::isSignalPropertyName
return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
signalName.at(2).isLetter();
}
static QString flatten(UiQualifiedId *qualifiedId)
{
QString result;
for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
if (!iter->name)
continue;
if (!result.isEmpty())
result.append(QLatin1Char('.'));
result.append(iter->name->asString());
}
return result;
}
static bool isLiteralValue(ExpressionNode *expr)
{
if (cast<NumericLiteral*>(expr))
return true;
else if (cast<StringLiteral*>(expr))
return true;
else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr))
return isLiteralValue(plusExpr->expression);
else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr))
return isLiteralValue(minusExpr->expression);
else if (cast<TrueLiteral*>(expr))
return true;
else if (cast<FalseLiteral*>(expr))
return true;
else
return false;
}
static inline bool isLiteralValue(UiScriptBinding *script)
{
if (!script || !script->statement)
return false;
return isLiteralValue((cast<ExpressionStatement *>(script->statement))->expression);
}
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"))
return QMetaType::type("bool");
else if (typeName == QLatin1String("color"))
return QMetaType::type("QColor");
else if (typeName == QLatin1String("date"))
return QMetaType::type("QDate");
else if (typeName == QLatin1String("int"))
return QMetaType::type("int");
else if (typeName == QLatin1String("real"))
return QMetaType::type("double");
else if (typeName == QLatin1String("string"))
return QMetaType::type("QString");
else if (typeName == QLatin1String("url"))
return QMetaType::type("QUrl");
else if (typeName == QLatin1String("var") || typeName == QLatin1String("variant"))
return QMetaType::type("QVariant");
else
return -1;
}
} // anonymous namespace
static inline bool equals(const QVariant &a, const QVariant &b) static inline bool equals(const QVariant &a, const QVariant &b)
{ {
if (a.type() == QVariant::Double && b.type() == QVariant::Double) if (a.type() == QVariant::Double && b.type() == QVariant::Double)
@@ -70,26 +204,36 @@ bool TextToModelMerger::isActive() const
return m_isActive; return m_isActive;
} }
void TextToModelMerger::setupImports(QDeclarativeDomDocument &doc, void TextToModelMerger::setupImports(const Document::Ptr &doc,
DifferenceHandler &differenceHandler) DifferenceHandler &differenceHandler)
{ {
QSet<Import> existingImports = m_rewriterView->model()->imports(); QSet<Import> existingImports = m_rewriterView->model()->imports();
foreach (const QDeclarativeDomImport &qmlImport, doc.imports()) { for (UiImportList *iter = doc->qmlProgram()->imports; iter; iter = iter->next) {
if (qmlImport.type() == QDeclarativeDomImport::Library) { UiImport *import = iter->import;
Import import(Import::createLibraryImport(qmlImport.uri(), if (!import)
qmlImport.version(), continue;
qmlImport.qualifier()));
if (!existingImports.remove(import)) QString version;
differenceHandler.modelMissesImport(import); if (import->versionToken.isValid())
} else if (qmlImport.type() == QDeclarativeDomImport::File) { version = textAt(doc, import->versionToken);
Import import(Import:: createFileImport(qmlImport.uri(), QString as;
qmlImport.version(), if (import->importId)
qmlImport.qualifier())); as = import->importId->asString();
if (!existingImports.remove(import)) if (import->fileName) {
differenceHandler.modelMissesImport(import); const QString strippedFileName = stripQuotes(import->fileName->asString());
Import newImport(Import::createFileImport(strippedFileName,
version, as));
if (!existingImports.remove(newImport))
differenceHandler.modelMissesImport(newImport);
} else {
Import newImport(Import::createLibraryImport(flatten(import->importUri),
as, version));
if (!existingImports.remove(newImport))
differenceHandler.modelMissesImport(newImport);
} }
} }
@@ -99,25 +243,37 @@ void TextToModelMerger::setupImports(QDeclarativeDomDocument &doc,
bool TextToModelMerger::load(const QByteArray &data, DifferenceHandler &differenceHandler) bool TextToModelMerger::load(const QByteArray &data, DifferenceHandler &differenceHandler)
{ {
qDebug() << "**** Starting to load the file...";
setActive(true); setActive(true);
try { try {
QDeclarativeEngine engine; QDeclarativeEngine engine;
QDeclarativeDomDocument doc; QDeclarativeDomDocument domDoc;
const QUrl url = m_rewriterView->model()->fileUrl(); const QUrl url = m_rewriterView->model()->fileUrl();
const bool success = doc.load(&engine, data, url); const bool success = domDoc.load(&engine, data, url);
if (success) { if (success) {
Snapshot snapshot = BaseTextEditModifier::getSnapshot();
const QString fileName = url.toLocalFile();
Document::Ptr doc = Document::create(fileName);
doc->setSource(QString::fromUtf8(data.constData()));
doc->parseQml();
snapshot.insert(doc);
ReadingContext ctxt(snapshot, doc);
setupImports(doc, differenceHandler); setupImports(doc, differenceHandler);
const QDeclarativeDomObject rootDomObject = doc.rootObject(); UiObjectMember *astRootNode = 0;
if (UiProgram *program = doc->qmlProgram())
if (program->members)
astRootNode = program->members->member;
ModelNode modelRootNode = m_rewriterView->rootModelNode(); ModelNode modelRootNode = m_rewriterView->rootModelNode();
syncNode(modelRootNode, rootDomObject, differenceHandler); syncNode(modelRootNode, astRootNode, &ctxt, differenceHandler);
m_rewriterView->positionStorage()->cleanupInvalidOffsets(); m_rewriterView->positionStorage()->cleanupInvalidOffsets();
m_rewriterView->clearErrors(); m_rewriterView->clearErrors();
} else { } else {
QList<RewriterView::Error> errors; QList<RewriterView::Error> errors;
foreach (const QDeclarativeError &qmlError, doc.errors()) foreach (const QDeclarativeError &qmlError, domDoc.errors())
errors.append(RewriterView::Error(qmlError)); errors.append(RewriterView::Error(qmlError));
m_rewriterView->setErrors(errors); m_rewriterView->setErrors(errors);
} }
@@ -139,207 +295,289 @@ bool TextToModelMerger::load(const QByteArray &data, DifferenceHandler &differen
} }
void TextToModelMerger::syncNode(ModelNode &modelNode, void TextToModelMerger::syncNode(ModelNode &modelNode,
const QDeclarativeDomObject &domObject, UiObjectMember *astNode,
ReadingContext *context,
DifferenceHandler &differenceHandler) DifferenceHandler &differenceHandler)
{ {
m_rewriterView->positionStorage()->setNodeOffset(modelNode, domObject.position()); UiQualifiedId *astObjectType = 0;
UiObjectInitializer *astInitializer = 0;
if (UiObjectDefinition *def = cast<UiObjectDefinition *>(astNode)) {
astObjectType = def->qualifiedTypeNameId;
astInitializer = def->initializer;
} else if (UiObjectBinding *bin = cast<UiObjectBinding *>(astNode)) {
astObjectType = bin->qualifiedTypeNameId;
astInitializer = bin->initializer;
}
if (modelNode.type() != domObject.objectType() if (!astObjectType || !astInitializer)
|| modelNode.majorVersion() != domObject.objectTypeMajorVersion() return;
|| modelNode.minorVersion() != domObject.objectTypeMinorVersion()) {
m_rewriterView->positionStorage()->setNodeOffset(modelNode, astNode->firstSourceLocation().offset);
QString typeName;
int majorVersion;
int minorVersion;
context->lookup(astObjectType, typeName, majorVersion, minorVersion);
if (typeName.isEmpty()) {
qWarning() << "Skipping node with unknown type" << flatten(astObjectType);
return;
}
if (modelNode.type() != typeName
/*|| modelNode.majorVersion() != domObject.objectTypeMajorVersion()
|| modelNode.minorVersion() != domObject.objectTypeMinorVersion()*/) {
const bool isRootNode = m_rewriterView->rootModelNode() == modelNode; const bool isRootNode = m_rewriterView->rootModelNode() == modelNode;
differenceHandler.typeDiffers(isRootNode, modelNode, domObject); differenceHandler.typeDiffers(isRootNode, modelNode, typeName,
majorVersion, minorVersion,
astNode, context);
if (!isRootNode) if (!isRootNode)
return; // the difference handler will create a new node, so we're done. return; // the difference handler will create a new node, so we're done.
} }
{
QString domObjectId = domObject.objectId();
const QDeclarativeDomProperty domIdProperty = domObject.property("id");
if (domObjectId.isEmpty() && domIdProperty.value().isLiteral())
domObjectId = domIdProperty.value().toLiteral().literal();
if (domObjectId.isEmpty()) {
if (!modelNode.id().isEmpty()) {
ModelNode existingNodeWithId = m_rewriterView->modelNodeForId(domObjectId);
if (existingNodeWithId.isValid())
existingNodeWithId.setId(QString());
differenceHandler.idsDiffer(modelNode, domObjectId);
}
} else {
if (modelNode.id() != domObjectId) {
ModelNode existingNodeWithId = m_rewriterView->modelNodeForId(domObjectId);
if (existingNodeWithId.isValid())
existingNodeWithId.setId(QString());
differenceHandler.idsDiffer(modelNode, domObjectId);
}
}
}
QSet<QString> modelPropertyNames = QSet<QString>::fromList(modelNode.propertyNames()); QSet<QString> modelPropertyNames = QSet<QString>::fromList(modelNode.propertyNames());
QList<UiObjectMember *> defaultPropertyItems;
foreach (const QDeclarativeDomProperty &domProperty, domObject.properties()) { for (UiObjectMemberList *iter = astInitializer->members; iter; iter = iter->next) {
const QString domPropertyName = domProperty.propertyName(); UiObjectMember *member = iter->member;
if (!member)
if (isSignalPropertyName(domPropertyName.toUtf8()))
continue; continue;
if (domPropertyName == QLatin1String("id")) { if (UiArrayBinding *array = cast<UiArrayBinding *>(member)) {
// already done before const QString astPropertyName = flatten(array->qualifiedId);
continue; if (isValidPropertyForNode(modelNode, astPropertyName)) {
} else if (domPropertyName.isEmpty()) { AbstractProperty modelProperty = modelNode.property(astPropertyName);
qWarning() << "QML DOM returned an empty property name"; syncArrayProperty(modelProperty, array, context, differenceHandler);
continue; modelPropertyNames.remove(astPropertyName);
} else if (domPropertyName.at(0).isUpper() && domPropertyName.contains('.')) { } else {
// An attached property, which we currently don't handle. qWarning() << "Skipping invalid array property" << astPropertyName
// So, skipping it. << "for node type" << modelNode.type();
modelPropertyNames.remove(domPropertyName);
continue;
} else {
const QDeclarativeDomDynamicProperty dynamicProperty = domObject.dynamicProperty(domProperty.propertyName());
if (dynamicProperty.isValid() || modelNode.metaInfo().hasProperty(domPropertyName, true) || modelNode.type() == QLatin1String("Qt/PropertyChanges")) {
AbstractProperty modelProperty = modelNode.property(domPropertyName);
syncProperty(modelProperty, domProperty, dynamicProperty, differenceHandler);
modelPropertyNames.remove(domPropertyName);
} }
} else if (cast<UiObjectDefinition *>(member)) {
defaultPropertyItems.append(member);
} else if (UiObjectBinding *binding = cast<UiObjectBinding *>(member)) {
const QString astPropertyName = flatten(binding->qualifiedId);
if (binding->hasOnToken) {
// skip value sources
} else {
if (isValidPropertyForNode(modelNode, astPropertyName)) {
AbstractProperty modelProperty = modelNode.property(astPropertyName);
syncNodeProperty(modelProperty, binding, context, differenceHandler);
modelPropertyNames.remove(astPropertyName);
} else {
qWarning() << "Skipping invalid node property" << astPropertyName
<< "for node type" << modelNode.type();
}
}
} else if (UiScriptBinding *script = cast<UiScriptBinding *>(member)) {
const QString astPropertyName = flatten(script->qualifiedId);
QString astValue;
if (script->statement)
astValue = textAt(context->doc,
script->statement->firstSourceLocation(),
script->statement->lastSourceLocation());
if (astPropertyName == QLatin1String("id")) {
syncNodeId(modelNode, astValue, differenceHandler);
} else if (isSignalPropertyName(astPropertyName)) {
// skip signals
} else if (isLiteralValue(script)) {
if (isValidPropertyForNode(modelNode, astPropertyName)) {
AbstractProperty modelProperty = modelNode.property(astPropertyName);
syncVariantProperty(modelProperty, astPropertyName, astValue, QString(), differenceHandler);
modelPropertyNames.remove(astPropertyName);
} else {
qWarning() << "Skipping invalid variant property" << astPropertyName
<< "for node type" << modelNode.type();
}
} else {
if (isValidPropertyForNode(modelNode, astPropertyName)) {
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)) {
const QString astName = property->name->asString();
QString astValue;
if (property->expression)
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
syncExpressionProperty(modelProperty, astValue, differenceHandler);
modelPropertyNames.remove(astName);
} else {
qWarning() << "Found an unknown QML value of type"
<< typeid(*member).name();
} }
} }
{ // for new dynamic properties which have no property definitions: if (!defaultPropertyItems.isEmpty()) {
foreach (const QDeclarativeDomDynamicProperty &dynamicDomProperty, domObject.dynamicProperties()) { QString defaultPropertyName = modelNode.metaInfo().defaultProperty();
const QByteArray propertyName = dynamicDomProperty.propertyName(); if (defaultPropertyName.isEmpty()) {
if (domObject.property(propertyName).isValid()) qWarning() << "No default property for node type" << modelNode.type() << ", ignoring child items.";
continue; } else {
AbstractProperty modelProperty = modelNode.property(defaultPropertyName);
if (dynamicDomProperty.isAlias()) if (modelProperty.isNodeListProperty()) {
continue; // we don't handle alias properties yet. NodeListProperty nodeListProperty = modelProperty.toNodeListProperty();
syncNodeListProperty(nodeListProperty, defaultPropertyItems, context,
AbstractProperty modelProperty = modelNode.property(propertyName); differenceHandler);
const QString dynamicTypeName = QMetaType::typeName(dynamicDomProperty.propertyType());
// a dynamic property definition without a value
if (modelProperty.isValid() && modelProperty.isVariantProperty()) {
VariantProperty modelVariantProperty = modelProperty.toVariantProperty();
if (modelVariantProperty.value() != QVariant())
differenceHandler.variantValuesDiffer(modelVariantProperty, QVariant(), dynamicTypeName);
} else { } else {
differenceHandler.shouldBeVariantProperty(modelProperty, QVariant(), dynamicTypeName); differenceHandler.shouldBeNodeListProperty(modelProperty,
defaultPropertyItems,
context);
} }
modelPropertyNames.remove(defaultPropertyName);
} }
} }
foreach (const QString &modelPropertyName, modelPropertyNames) { foreach (const QString &modelPropertyName, modelPropertyNames) {
AbstractProperty modelProperty = modelNode.property(modelPropertyName); AbstractProperty modelProperty = modelNode.property(modelPropertyName);
const QDeclarativeDomDynamicProperty dynamicDomProperty = domObject.dynamicProperty(modelPropertyName.toUtf8());
if (dynamicDomProperty.isValid()) { // property deleted.
const QString dynamicTypeName = QMetaType::typeName(dynamicDomProperty.propertyType()); differenceHandler.propertyAbsentFromQml(modelProperty);
// a dynamic property definition without a value
if (modelProperty.isValid() && modelProperty.isVariantProperty()) {
VariantProperty modelVariantProperty = modelProperty.toVariantProperty();
if (modelVariantProperty.value() != QVariant())
differenceHandler.variantValuesDiffer(modelVariantProperty, QVariant(), dynamicTypeName);
} else {
differenceHandler.shouldBeVariantProperty(modelProperty, QVariant(), dynamicTypeName);
}
} else {
// property deleted.
differenceHandler.propertyAbsentFromQml(modelProperty);
}
} }
} }
void TextToModelMerger::syncProperty(AbstractProperty &modelProperty, void TextToModelMerger::syncNodeId(ModelNode &modelNode, const QString &astObjectId,
const QDeclarativeDomProperty &qmlProperty, DifferenceHandler &differenceHandler)
const QDeclarativeDomDynamicProperty &qmlDynamicProperty,
DifferenceHandler &differenceHandler)
{ {
Q_ASSERT(modelProperty.name() == qmlProperty.propertyName()); if (astObjectId.isEmpty()) {
if (!modelNode.id().isEmpty()) {
const QDeclarativeDomValue qmlValue = qmlProperty.value(); ModelNode existingNodeWithId = m_rewriterView->modelNodeForId(astObjectId);
if (existingNodeWithId.isValid())
if (qmlValue.isBinding()) { existingNodeWithId.setId(QString());
const QString QDeclarativeBinding = qmlValue.toBinding().binding(); differenceHandler.idsDiffer(modelNode, astObjectId);
if (modelProperty.isBindingProperty()) {
BindingProperty bindingProperty = modelProperty.toBindingProperty();
if (bindingProperty.expression() != QDeclarativeBinding) {
differenceHandler.bindingExpressionsDiffer(bindingProperty, QDeclarativeBinding);
}
} else {
differenceHandler.shouldBeBindingProperty(modelProperty, QDeclarativeBinding);
} }
} else if (qmlValue.isList()) {
if (modelProperty.isNodeListProperty()) {
NodeListProperty nodeListProperty = modelProperty.toNodeListProperty();
syncNodeListProperty(nodeListProperty, qmlValue.toList(), differenceHandler);
} else {
differenceHandler.shouldBeNodeListProperty(modelProperty, qmlValue.toList());
}
} else if (qmlValue.isLiteral()) {
const QVariant qmlVariantValue = convertToVariant(modelProperty.parentModelNode(), qmlProperty, qmlDynamicProperty);
QString dynamicTypeName;
if (qmlDynamicProperty.isValid())
dynamicTypeName = QMetaType::typeName(qmlDynamicProperty.propertyType());
if (modelProperty.isVariantProperty()) {
VariantProperty modelVariantProperty = modelProperty.toVariantProperty();
if (!equals(modelVariantProperty.value(), qmlVariantValue)
|| qmlDynamicProperty.isValid() != modelVariantProperty.isDynamic()
|| dynamicTypeName != modelVariantProperty.dynamicTypeName()) {
differenceHandler.variantValuesDiffer(modelVariantProperty, qmlVariantValue, dynamicTypeName);
}
} else {
differenceHandler.shouldBeVariantProperty(modelProperty, qmlVariantValue, dynamicTypeName);
}
} else if (qmlValue.isObject()) {
if (modelProperty.isNodeProperty()) {
ModelNode nodePropertyNode = modelProperty.toNodeProperty().modelNode();
syncNode(nodePropertyNode, qmlValue.toObject(), differenceHandler);
} else {
differenceHandler.shouldBeNodeProperty(modelProperty, qmlValue.toObject());
}
} else if (qmlValue.isValueSource()) {
if (modelProperty.isNodeProperty()) {
ModelNode nodePropertyNode = modelProperty.toNodeProperty().modelNode();
syncNode(nodePropertyNode, qmlValue.toValueSource().object(), differenceHandler);
} else {
differenceHandler.shouldBeNodeProperty(modelProperty, qmlValue.toValueSource().object());
}
} else if (qmlValue.isInvalid()) {
// skip these nodes
} else { } else {
qWarning() << "Found an unknown qml value!"; if (modelNode.id() != astObjectId) {
ModelNode existingNodeWithId = m_rewriterView->modelNodeForId(astObjectId);
if (existingNodeWithId.isValid())
existingNodeWithId.setId(QString());
differenceHandler.idsDiffer(modelNode, astObjectId);
}
} }
} }
void TextToModelMerger::syncNodeListProperty(NodeListProperty &modelListProperty, const QDeclarativeDomList &domList, DifferenceHandler &differenceHandler) void TextToModelMerger::syncNodeProperty(AbstractProperty &modelProperty,
UiObjectBinding *binding,
ReadingContext *context,
DifferenceHandler &differenceHandler)
{
QString typeName;
int majorVersion;
int minorVersion;
context->lookup(binding->qualifiedTypeNameId, typeName, majorVersion, minorVersion);
if (typeName.isEmpty()) {
qWarning() << "Skipping node with unknown type" << flatten(binding->qualifiedTypeNameId);
return;
}
if (modelProperty.isNodeProperty()) {
ModelNode nodePropertyNode = modelProperty.toNodeProperty().modelNode();
syncNode(nodePropertyNode, binding, context, differenceHandler);
} else {
differenceHandler.shouldBeNodeProperty(modelProperty,
typeName,
majorVersion,
minorVersion,
binding, context);
}
}
void TextToModelMerger::syncExpressionProperty(AbstractProperty &modelProperty,
const QString &javascript,
DifferenceHandler &differenceHandler)
{
if (modelProperty.isBindingProperty()) {
BindingProperty bindingProperty = modelProperty.toBindingProperty();
if (bindingProperty.expression() != javascript) {
differenceHandler.bindingExpressionsDiffer(bindingProperty, javascript);
}
} else {
differenceHandler.shouldBeBindingProperty(modelProperty, javascript);
}
}
void TextToModelMerger::syncArrayProperty(AbstractProperty &modelProperty,
UiArrayBinding *array,
ReadingContext *context,
DifferenceHandler &differenceHandler)
{
QList<UiObjectMember *> arrayMembers;
for (UiArrayMemberList *iter = array->members; iter; iter = iter->next)
if (UiObjectMember *member = iter->member)
arrayMembers.append(member);
if (modelProperty.isNodeListProperty()) {
NodeListProperty nodeListProperty = modelProperty.toNodeListProperty();
syncNodeListProperty(nodeListProperty, arrayMembers, context, differenceHandler);
} else {
differenceHandler.shouldBeNodeListProperty(modelProperty,
arrayMembers,
context);
}
}
void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty,
const QString &astName,
const QString &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)
|| !astType.isEmpty() != modelVariantProperty.isDynamic()
|| astType != modelVariantProperty.dynamicTypeName()) {
differenceHandler.variantValuesDiffer(modelVariantProperty,
astVariantValue,
astType);
}
} else {
differenceHandler.shouldBeVariantProperty(modelProperty,
astVariantValue,
astType);
}
}
void TextToModelMerger::syncNodeListProperty(NodeListProperty &modelListProperty,
const QList<UiObjectMember *> arrayMembers,
ReadingContext *context,
DifferenceHandler &differenceHandler)
{ {
QList<ModelNode> modelNodes = modelListProperty.toModelNodeList(); QList<ModelNode> modelNodes = modelListProperty.toModelNodeList();
QList<QDeclarativeDomValue> domValues = domList.values();
int i = 0; int i = 0;
for (; i < modelNodes.size() && i < domValues.size(); ++i) { for (; i < modelNodes.size() && i < arrayMembers.size(); ++i) {
QDeclarativeDomValue value = domValues.at(i); ModelNode modelNode = modelNodes.at(i);
if (value.isObject()) { syncNode(modelNode, arrayMembers.at(i), context, differenceHandler);
ModelNode modelNode = modelNodes.at(i);
syncNode(modelNode, value.toObject(), differenceHandler);
} else {
qDebug() << "*** Oops, we got a non-object item in the list!";
}
} }
for (int j = i; j < domValues.size(); ++j) { for (int j = i; j < arrayMembers.size(); ++j) {
// more elements in the dom-list, so add them to the model // more elements in the dom-list, so add them to the model
QDeclarativeDomValue value = domValues.at(j); UiObjectMember *arrayMember = arrayMembers.at(j);
if (value.isObject()) { const ModelNode newNode = differenceHandler.listPropertyMissingModelNode(modelListProperty, context, arrayMember);
const QDeclarativeDomObject qmlObject = value.toObject(); QString name;
const ModelNode newNode = differenceHandler.listPropertyMissingModelNode(modelListProperty, qmlObject); if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(arrayMember))
if (QString::fromUtf8(qmlObject.objectType()) == QLatin1String("Qt/Component")) name = flatten(definition->qualifiedTypeNameId);
setupComponent(newNode); // TODO: resolve name here!
} else { if (name == QLatin1String("Qt/Component"))
qDebug() << "*** Oops, we got a non-object item in the list!"; setupComponent(newNode);
}
} }
for (int j = i; j < modelNodes.size(); ++j) { for (int j = i; j < modelNodes.size(); ++j) {
@@ -349,20 +587,31 @@ void TextToModelMerger::syncNodeListProperty(NodeListProperty &modelListProperty
} }
} }
ModelNode TextToModelMerger::createModelNode(const QDeclarativeDomObject &domObject, DifferenceHandler &differenceHandler) ModelNode TextToModelMerger::createModelNode(const QString &typeName,
int majorVersion,
int minorVersion,
UiObjectMember *astNode,
ReadingContext *context,
DifferenceHandler &differenceHandler)
{ {
ModelNode newNode = m_rewriterView->createModelNode(domObject.objectType(), domObject.objectTypeMajorVersion(), domObject.objectTypeMinorVersion()); qDebug() << "Creating model node for" << typeName << majorVersion << minorVersion;
syncNode(newNode, domObject, differenceHandler); ModelNode newNode = m_rewriterView->createModelNode(typeName,
majorVersion,
minorVersion);
syncNode(newNode, astNode, context, differenceHandler);
return newNode; return newNode;
} }
QVariant TextToModelMerger::convertToVariant(const ModelNode &node, const QDeclarativeDomProperty &qmlProperty, const QDeclarativeDomDynamicProperty &qmlDynamicProperty) QVariant TextToModelMerger::convertToVariant(const ModelNode &node,
const QString &astName,
const QString &astValue,
const QString &astType)
{ {
QString stringValue = qmlProperty.value().toLiteral().literal(); const QString cleanedValue = stripQuotes(astValue.trimmed());
if (qmlDynamicProperty.isValid()) { if (!astType.isEmpty()) {
const int type = qmlDynamicProperty.propertyType(); const int type = propertyType(astType);
QVariant value(stringValue); QVariant value(cleanedValue);
value.convert(static_cast<QVariant::Type>(type)); value.convert(static_cast<QVariant::Type>(type));
return value; return value;
} }
@@ -370,23 +619,30 @@ QVariant TextToModelMerger::convertToVariant(const ModelNode &node, const QDecla
const NodeMetaInfo nodeMetaInfo = node.metaInfo(); const NodeMetaInfo nodeMetaInfo = node.metaInfo();
if (nodeMetaInfo.isValid()) { if (nodeMetaInfo.isValid()) {
const PropertyMetaInfo propertyMetaInfo = nodeMetaInfo.property(qmlProperty.propertyName(), true); const PropertyMetaInfo propertyMetaInfo = nodeMetaInfo.property(astName, true);
if (propertyMetaInfo.isValid()) { if (propertyMetaInfo.isValid()) {
QVariant castedValue = propertyMetaInfo.castedValue(stringValue); QVariant castedValue = propertyMetaInfo.castedValue(cleanedValue);
if (!castedValue.isValid()) if (!castedValue.isValid())
qWarning() << "Casting the value" << stringValue << "of property" << propertyMetaInfo.name() << "to the property type" << propertyMetaInfo.type() << "failed"; qWarning() << "Casting the value" << cleanedValue
<< "of property" << astName
<< "to the property type" << propertyMetaInfo.type()
<< "failed";
return castedValue; return castedValue;
} else if (node.type() == QLatin1String("Qt/PropertyChanges")) { } 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. // 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(stringValue); return QVariant(cleanedValue);
} else { } else {
qWarning() << "Unknown property" << qmlProperty.propertyName() << "in node" << node.type() << "with value" << stringValue; qWarning() << "Unknown property" << astName
<< "in node" << node.type()
<< "with value" << cleanedValue;
return QVariant(); return QVariant();
} }
} else { } else {
qWarning() << "Unknown property" << qmlProperty.propertyName() << "in node" << node.type() << "with value" << stringValue; qWarning() << "Unknown property" << astName
return QVariant::fromValue(stringValue); << "in node" << node.type()
<< "with value" << cleanedValue;
return QVariant::fromValue(cleanedValue);
} }
} }
@@ -400,19 +656,23 @@ void ModelValidator::importAbsentInQMl(const Import &import)
Q_ASSERT(! m_merger->view()->model()->imports().contains(import)); Q_ASSERT(! m_merger->view()->model()->imports().contains(import));
} }
void ModelValidator::bindingExpressionsDiffer(BindingProperty &modelProperty, const QString &QDeclarativeBinding) void ModelValidator::bindingExpressionsDiffer(BindingProperty &modelProperty,
const QString &javascript)
{ {
Q_ASSERT(modelProperty.expression() == QDeclarativeBinding); Q_ASSERT(modelProperty.expression() == javascript);
Q_ASSERT(0); Q_ASSERT(0);
} }
void ModelValidator::shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &/*QDeclarativeBinding*/) void ModelValidator::shouldBeBindingProperty(AbstractProperty &modelProperty,
const QString &/*javascript*/)
{ {
Q_ASSERT(modelProperty.isBindingProperty()); Q_ASSERT(modelProperty.isBindingProperty());
Q_ASSERT(0); Q_ASSERT(0);
} }
void ModelValidator::shouldBeNodeListProperty(AbstractProperty &modelProperty, const QDeclarativeDomList &/*domList*/) void ModelValidator::shouldBeNodeListProperty(AbstractProperty &modelProperty,
const QList<UiObjectMember *> /*arrayMembers*/,
ReadingContext * /*context*/)
{ {
Q_ASSERT(modelProperty.isNodeListProperty()); Q_ASSERT(modelProperty.isNodeListProperty());
Q_ASSERT(0); Q_ASSERT(0);
@@ -435,7 +695,12 @@ void ModelValidator::shouldBeVariantProperty(AbstractProperty &modelProperty, co
Q_ASSERT(0); Q_ASSERT(0);
} }
void ModelValidator::shouldBeNodeProperty(AbstractProperty &modelProperty, const QDeclarativeDomObject &/*qmlObject*/) void ModelValidator::shouldBeNodeProperty(AbstractProperty &modelProperty,
const QString &/*typeName*/,
int /*majorVersion*/,
int /*minorVersion*/,
UiObjectMember * /*astNode*/,
ReadingContext * /*context*/)
{ {
Q_ASSERT(modelProperty.isNodeProperty()); Q_ASSERT(modelProperty.isNodeProperty());
Q_ASSERT(0); Q_ASSERT(0);
@@ -447,17 +712,25 @@ void ModelValidator::modelNodeAbsentFromQml(ModelNode &modelNode)
Q_ASSERT(0); Q_ASSERT(0);
} }
ModelNode ModelValidator::listPropertyMissingModelNode(NodeListProperty &/*modelProperty*/, const QDeclarativeDomObject &/*qmlObject*/) ModelNode ModelValidator::listPropertyMissingModelNode(NodeListProperty &/*modelProperty*/,
ReadingContext * /*context*/,
UiObjectMember * /*arrayMember*/)
{ {
Q_ASSERT(0); Q_ASSERT(0);
return ModelNode(); return ModelNode();
} }
void ModelValidator::typeDiffers(bool /*isRootNode*/, ModelNode &modelNode, const QDeclarativeDomObject &domObject) void ModelValidator::typeDiffers(bool /*isRootNode*/,
ModelNode &modelNode,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember * /*astNode*/,
ReadingContext * /*context*/)
{ {
Q_ASSERT(modelNode.type() == domObject.objectType()); Q_ASSERT(modelNode.type() == typeName);
Q_ASSERT(modelNode.majorVersion() == domObject.objectTypeMajorVersion()); Q_ASSERT(modelNode.majorVersion() == majorVersion);
Q_ASSERT(modelNode.minorVersion() == domObject.objectTypeMinorVersion()); Q_ASSERT(modelNode.minorVersion() == minorVersion);
Q_ASSERT(0); Q_ASSERT(0);
} }
@@ -483,23 +756,30 @@ void ModelAmender::importAbsentInQMl(const Import &import)
m_merger->view()->model()->removeImport(import); m_merger->view()->model()->removeImport(import);
} }
void ModelAmender::bindingExpressionsDiffer(BindingProperty &modelProperty, const QString &QDeclarativeBinding) void ModelAmender::bindingExpressionsDiffer(BindingProperty &modelProperty,
const QString &javascript)
{ {
modelProperty.toBindingProperty().setExpression(QDeclarativeBinding); modelProperty.toBindingProperty().setExpression(javascript);
} }
void ModelAmender::shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &QDeclarativeBinding) void ModelAmender::shouldBeBindingProperty(AbstractProperty &modelProperty,
const QString &javascript)
{ {
ModelNode theNode = modelProperty.parentModelNode(); ModelNode theNode = modelProperty.parentModelNode();
BindingProperty newModelProperty = theNode.bindingProperty(modelProperty.name()); BindingProperty newModelProperty = theNode.bindingProperty(modelProperty.name());
newModelProperty.setExpression(QDeclarativeBinding); newModelProperty.setExpression(javascript);
} }
void ModelAmender::shouldBeNodeListProperty(AbstractProperty &modelProperty, const QDeclarativeDomList &domList) void ModelAmender::shouldBeNodeListProperty(AbstractProperty &modelProperty,
const QList<UiObjectMember *> arrayMembers,
ReadingContext *context)
{ {
ModelNode theNode = modelProperty.parentModelNode(); ModelNode theNode = modelProperty.parentModelNode();
NodeListProperty newNodeListProperty = theNode.nodeListProperty(modelProperty.name()); NodeListProperty newNodeListProperty = theNode.nodeListProperty(modelProperty.name());
m_merger->syncNodeListProperty(newNodeListProperty, domList, *this); m_merger->syncNodeListProperty(newNodeListProperty,
arrayMembers,
context,
*this);
} }
void ModelAmender::variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicType) void ModelAmender::variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicType)
@@ -522,11 +802,21 @@ void ModelAmender::shouldBeVariantProperty(AbstractProperty &modelProperty, cons
newModelProperty.setDynamicTypeNameAndValue(dynamicTypeName, qmlVariantValue); newModelProperty.setDynamicTypeNameAndValue(dynamicTypeName, qmlVariantValue);
} }
void ModelAmender::shouldBeNodeProperty(AbstractProperty &modelProperty, const QDeclarativeDomObject &qmlObject) void ModelAmender::shouldBeNodeProperty(AbstractProperty &modelProperty,
const QString &typeName,
int majorVersion,
int minorVersion,
UiObjectMember *astNode,
ReadingContext *context)
{ {
ModelNode theNode = modelProperty.parentModelNode(); ModelNode theNode = modelProperty.parentModelNode();
NodeProperty newNodeProperty = theNode.nodeProperty(modelProperty.name()); NodeProperty newNodeProperty = theNode.nodeProperty(modelProperty.name());
newNodeProperty.setModelNode(m_merger->createModelNode(qmlObject, *this)); newNodeProperty.setModelNode(m_merger->createModelNode(typeName,
majorVersion,
minorVersion,
astNode,
context,
*this));
} }
void ModelAmender::modelNodeAbsentFromQml(ModelNode &modelNode) void ModelAmender::modelNodeAbsentFromQml(ModelNode &modelNode)
@@ -534,17 +824,53 @@ void ModelAmender::modelNodeAbsentFromQml(ModelNode &modelNode)
modelNode.destroy(); modelNode.destroy();
} }
ModelNode ModelAmender::listPropertyMissingModelNode(NodeListProperty &modelProperty, const QDeclarativeDomObject &qmlObject) ModelNode ModelAmender::listPropertyMissingModelNode(NodeListProperty &modelProperty,
ReadingContext *context,
UiObjectMember *arrayMember)
{ {
const ModelNode &newNode = m_merger->createModelNode(qmlObject, *this); UiQualifiedId *astObjectType = 0;
UiObjectInitializer *astInitializer = 0;
if (UiObjectDefinition *def = cast<UiObjectDefinition *>(arrayMember)) {
astObjectType = def->qualifiedTypeNameId;
astInitializer = def->initializer;
} else if (UiObjectBinding *bin = cast<UiObjectBinding *>(arrayMember)) {
astObjectType = bin->qualifiedTypeNameId;
astInitializer = bin->initializer;
}
if (!astObjectType || !astInitializer)
return ModelNode();
QString typeName;
int majorVersion;
int minorVersion;
context->lookup(astObjectType, typeName, majorVersion, minorVersion);
if (typeName.isEmpty()) {
qWarning() << "Skipping node with unknown type" << flatten(astObjectType);
return ModelNode();
}
const ModelNode &newNode = m_merger->createModelNode(typeName,
majorVersion,
minorVersion,
arrayMember,
context,
*this);
modelProperty.reparentHere(newNode); modelProperty.reparentHere(newNode);
return newNode; return newNode;
} }
void ModelAmender::typeDiffers(bool isRootNode, ModelNode &modelNode, const QDeclarativeDomObject &domObject) void ModelAmender::typeDiffers(bool isRootNode,
ModelNode &modelNode,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context)
{ {
if (isRootNode) { if (isRootNode) {
modelNode.view()->changeRootNodeType(domObject.objectType(), domObject.objectTypeMajorVersion(), domObject.objectTypeMinorVersion()); modelNode.view()->changeRootNodeType(typeName, majorVersion, minorVersion);
} else { } else {
NodeAbstractProperty parentProperty = modelNode.parentProperty(); NodeAbstractProperty parentProperty = modelNode.parentProperty();
int nodeIndex = -1; int nodeIndex = -1;
@@ -555,7 +881,12 @@ void ModelAmender::typeDiffers(bool isRootNode, ModelNode &modelNode, const QDec
modelNode.destroy(); modelNode.destroy();
const ModelNode &newNode = m_merger->createModelNode(domObject, *this); const ModelNode &newNode = m_merger->createModelNode(typeName,
majorVersion,
minorVersion,
astNode,
context,
*this);
parentProperty.reparentHere(newNode); parentProperty.reparentHere(newNode);
if (nodeIndex >= 0) { if (nodeIndex >= 0) {
int currentIndex = parentProperty.toNodeListProperty().toModelNodeList().indexOf(newNode); int currentIndex = parentProperty.toNodeListProperty().toModelNodeList().indexOf(newNode);
@@ -575,13 +906,6 @@ void ModelAmender::idsDiffer(ModelNode &modelNode, const QString &qmlId)
modelNode.setId(qmlId); modelNode.setId(qmlId);
} }
bool TextToModelMerger::isSignalPropertyName(const QString &signalName)
{
// see QmlCompiler::isSignalPropertyName
return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) &&
signalName.at(2).isLetter();
}
void TextToModelMerger::setupComponent(const ModelNode &node) void TextToModelMerger::setupComponent(const ModelNode &node)
{ {
Q_ASSERT(node.type() == QLatin1String("Qt/Component")); Q_ASSERT(node.type() == QLatin1String("Qt/Component"));
@@ -605,3 +929,16 @@ void TextToModelMerger::setupComponent(const ModelNode &node)
node.variantProperty("__component_data") = result; node.variantProperty("__component_data") = result;
} }
QString TextToModelMerger::textAt(const Document::Ptr &doc,
const SourceLocation &location)
{
return doc->source().mid(location.offset, location.length);
}
QString TextToModelMerger::textAt(const Document::Ptr &doc,
const SourceLocation &from,
const SourceLocation &to)
{
return doc->source().mid(from.offset, to.end() - from.begin());
}

View File

@@ -34,6 +34,7 @@
#include "import.h" #include "import.h"
#include "nodelistproperty.h" #include "nodelistproperty.h"
#include "modelnode.h" #include "modelnode.h"
#include <qmljs/qmljsdocument.h>
#include <private/qdeclarativedom_p.h> #include <private/qdeclarativedom_p.h>
@@ -43,6 +44,7 @@ class CORESHARED_EXPORT RewriterView;
namespace Internal { namespace Internal {
class ReadingContext;
class DifferenceHandler; class DifferenceHandler;
class TextToModelMerger class TextToModelMerger
@@ -54,7 +56,7 @@ public:
TextToModelMerger(RewriterView *reWriterView); TextToModelMerger(RewriterView *reWriterView);
bool isActive() const; bool isActive() const;
void setupImports(QDeclarativeDomDocument &doc, DifferenceHandler &differenceHandler); void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler);
bool load(const QByteArray &data, DifferenceHandler &differenceHandler); bool load(const QByteArray &data, DifferenceHandler &differenceHandler);
RewriterView *view() const RewriterView *view() const
@@ -65,25 +67,51 @@ protected:
public: public:
void syncNode(ModelNode &modelNode, void syncNode(ModelNode &modelNode,
const QDeclarativeDomObject &qmlObject, QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context,
DifferenceHandler &differenceHandler); DifferenceHandler &differenceHandler);
void syncProperty(AbstractProperty &modelProperty, void syncNodeId(ModelNode &modelNode, const QString &astObjectId,
const QDeclarativeDomProperty &qmlProperty, DifferenceHandler &differenceHandler);
const QDeclarativeDomDynamicProperty &qmlDynamicProperty, void syncNodeProperty(AbstractProperty &modelProperty,
DifferenceHandler &differenceHandler); QmlJS::AST::UiObjectBinding *binding,
ReadingContext *context,
DifferenceHandler &differenceHandler);
void syncExpressionProperty(AbstractProperty &modelProperty,
const QString &javascript,
DifferenceHandler &differenceHandler);
void syncArrayProperty(AbstractProperty &modelProperty,
QmlJS::AST::UiArrayBinding *array,
ReadingContext *context,
DifferenceHandler &differenceHandler);
void syncVariantProperty(AbstractProperty &modelProperty,
const QString &astName,
const QString &astValue,
const QString &astType,
DifferenceHandler &differenceHandler);
void syncNodeListProperty(NodeListProperty &modelListProperty, void syncNodeListProperty(NodeListProperty &modelListProperty,
const QDeclarativeDomList &domList, const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
ReadingContext *context,
DifferenceHandler &differenceHandler); DifferenceHandler &differenceHandler);
ModelNode createModelNode(const QDeclarativeDomObject &domObject, ModelNode createModelNode(const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context,
DifferenceHandler &differenceHandler); DifferenceHandler &differenceHandler);
static QVariant convertToVariant(const ModelNode &node, static QVariant convertToVariant(const ModelNode &node,
const QDeclarativeDomProperty &qmlProperty, const QString &astName,
const QDeclarativeDomDynamicProperty &qmlDynamicProperty); const QString &astValue,
const QString &astType);
private: private:
static bool isSignalPropertyName(const QString &signalName);
void setupComponent(const ModelNode &node); void setupComponent(const ModelNode &node);
static QString textAt(const QmlJS::Document::Ptr &doc,
const QmlJS::AST::SourceLocation &location);
static QString textAt(const QmlJS::Document::Ptr &doc,
const QmlJS::AST::SourceLocation &from,
const QmlJS::AST::SourceLocation &to);
private: private:
RewriterView *m_rewriterView; RewriterView *m_rewriterView;
bool m_isActive; bool m_isActive;
@@ -100,15 +128,32 @@ public:
virtual void modelMissesImport(const Import &import) = 0; virtual void modelMissesImport(const Import &import) = 0;
virtual void importAbsentInQMl(const Import &import) = 0; virtual void importAbsentInQMl(const Import &import) = 0;
virtual void bindingExpressionsDiffer(BindingProperty &modelProperty, const QString &QDeclarativeBinding) = 0; virtual void bindingExpressionsDiffer(BindingProperty &modelProperty,
virtual void shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &QDeclarativeBinding) = 0; const QString &javascript) = 0;
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty, const QDeclarativeDomList &domList) = 0; virtual void shouldBeBindingProperty(AbstractProperty &modelProperty,
const QString &javascript) = 0;
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty,
const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
ReadingContext *context) = 0;
virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName) = 0; virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName) = 0;
virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName) = 0; virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName) = 0;
virtual void shouldBeNodeProperty(AbstractProperty &modelProperty, const QDeclarativeDomObject &qmlObject) = 0; virtual void shouldBeNodeProperty(AbstractProperty &modelProperty,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context) = 0;
virtual void modelNodeAbsentFromQml(ModelNode &modelNode) = 0; virtual void modelNodeAbsentFromQml(ModelNode &modelNode) = 0;
virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty, const QDeclarativeDomObject &qmlObject) = 0; virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
virtual void typeDiffers(bool isRootNode, ModelNode &modelNode, const QDeclarativeDomObject &domObject) = 0; ReadingContext *context,
QmlJS::AST::UiObjectMember *arrayMember) = 0;
virtual void typeDiffers(bool isRootNode,
ModelNode &modelNode,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context) = 0;
virtual void propertyAbsentFromQml(AbstractProperty &modelProperty) = 0; virtual void propertyAbsentFromQml(AbstractProperty &modelProperty) = 0;
virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId) = 0; virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId) = 0;
@@ -127,15 +172,32 @@ public:
virtual void modelMissesImport(const Import &import); virtual void modelMissesImport(const Import &import);
virtual void importAbsentInQMl(const Import &import); virtual void importAbsentInQMl(const Import &import);
virtual void bindingExpressionsDiffer(BindingProperty &modelProperty, const QString &QDeclarativeBinding); virtual void bindingExpressionsDiffer(BindingProperty &modelProperty,
virtual void shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &QDeclarativeBinding); const QString &javascript);
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty, const QDeclarativeDomList &domList); virtual void shouldBeBindingProperty(AbstractProperty &modelProperty,
const QString &javascript);
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty,
const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
ReadingContext *context);
virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName); virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName);
virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName); virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName);
virtual void shouldBeNodeProperty(AbstractProperty &modelProperty, const QDeclarativeDomObject &qmlObject); virtual void shouldBeNodeProperty(AbstractProperty &modelProperty,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context);
virtual void modelNodeAbsentFromQml(ModelNode &modelNode); virtual void modelNodeAbsentFromQml(ModelNode &modelNode);
virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty, const QDeclarativeDomObject &qmlObject); virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
virtual void typeDiffers(bool isRootNode, ModelNode &modelNode, const QDeclarativeDomObject &domObject); ReadingContext *context,
QmlJS::AST::UiObjectMember *arrayMember);
virtual void typeDiffers(bool isRootNode,
ModelNode &modelNode,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context);
virtual void propertyAbsentFromQml(AbstractProperty &modelProperty); virtual void propertyAbsentFromQml(AbstractProperty &modelProperty);
virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId); virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId);
}; };
@@ -151,15 +213,32 @@ public:
virtual void modelMissesImport(const Import &import); virtual void modelMissesImport(const Import &import);
virtual void importAbsentInQMl(const Import &import); virtual void importAbsentInQMl(const Import &import);
virtual void bindingExpressionsDiffer(BindingProperty &modelProperty, const QString &QDeclarativeBinding); virtual void bindingExpressionsDiffer(BindingProperty &modelProperty,
virtual void shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &QDeclarativeBinding); const QString &javascript);
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty, const QDeclarativeDomList &domList); virtual void shouldBeBindingProperty(AbstractProperty &modelProperty,
const QString &javascript);
virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty,
const QList<QmlJS::AST::UiObjectMember *> arrayMembers,
ReadingContext *context);
virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicType); virtual void variantValuesDiffer(VariantProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicType);
virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName); virtual void shouldBeVariantProperty(AbstractProperty &modelProperty, const QVariant &qmlVariantValue, const QString &dynamicTypeName);
virtual void shouldBeNodeProperty(AbstractProperty &modelProperty, const QDeclarativeDomObject &qmlObject); virtual void shouldBeNodeProperty(AbstractProperty &modelProperty,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context);
virtual void modelNodeAbsentFromQml(ModelNode &modelNode); virtual void modelNodeAbsentFromQml(ModelNode &modelNode);
virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty, const QDeclarativeDomObject &qmlObject); virtual ModelNode listPropertyMissingModelNode(NodeListProperty &modelProperty,
virtual void typeDiffers(bool isRootNode, ModelNode &modelNode, const QDeclarativeDomObject &domObject); ReadingContext *context,
QmlJS::AST::UiObjectMember *arrayMember);
virtual void typeDiffers(bool isRootNode,
ModelNode &modelNode,
const QString &typeName,
int majorVersion,
int minorVersion,
QmlJS::AST::UiObjectMember *astNode,
ReadingContext *context);
virtual void propertyAbsentFromQml(AbstractProperty &modelProperty); virtual void propertyAbsentFromQml(AbstractProperty &modelProperty);
virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId); virtual void idsDiffer(ModelNode &modelNode, const QString &qmlId);
}; };

View File

@@ -4,6 +4,7 @@ TARGET = QmlDesigner
include(../../qtcreatorplugin.pri) include(../../qtcreatorplugin.pri)
include(../private_headers.pri) include(../private_headers.pri)
include(qmldesigner_dependencies.pri) include(qmldesigner_dependencies.pri)
include(../qmljseditor/qmljseditor.pri)
include(core/core.pri) include(core/core.pri)
include(components/integration/integration.pri) include(components/integration/integration.pri)