diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-07-02 06:14:27 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-07-02 06:14:27 (GMT) |
commit | 49bceaf197a5964f244ac094aaa75b35cf3ada49 (patch) | |
tree | 37428a137a608757d4a1c548decf6ff46f1b67f9 /src/declarative/qml | |
parent | ba13a6003d95f9d07f94bdb0e210e0c0453d8b80 (diff) | |
download | Qt-49bceaf197a5964f244ac094aaa75b35cf3ada49.zip Qt-49bceaf197a5964f244ac094aaa75b35cf3ada49.tar.gz Qt-49bceaf197a5964f244ac094aaa75b35cf3ada49.tar.bz2 |
Initial property aliasing support
Currently very basic - the only alias "script" that is allowed is Id.property
Diffstat (limited to 'src/declarative/qml')
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 156 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler_p.h | 17 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction_p.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlscriptparser.cpp | 6 | ||||
-rw-r--r-- | src/declarative/qml/qmlvme.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlvmemetaobject.cpp | 52 | ||||
-rw-r--r-- | src/declarative/qml/qmlvmemetaobject_p.h | 13 |
8 files changed, 220 insertions, 29 deletions
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 47f69a0..57d77ac 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -554,17 +554,18 @@ void QmlCompiler::compileTree(Object *tree) if (!compileObject(tree, 0)) // Compile failed return; - if (tree->metatype) - static_cast<QMetaObject &>(output->root) = *tree->metaObject(); - else - static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject(); - QmlInstruction def; init.line = 0; def.type = QmlInstruction::SetDefault; output->bytecode << def; finalizeComponent(0); + + if (tree->metatype) + static_cast<QMetaObject &>(output->root) = *tree->metaObject(); + else + static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject(); + } bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) @@ -798,13 +799,12 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ct if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); - finalizeComponent(count); + COMPILE_CHECK(finalizeComponent(count)); create.createComponent.count = output->bytecode.count() - count; compileState = oldComponentCompileState; return true; } - bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); @@ -1398,7 +1398,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) +bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) { // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && @@ -1411,14 +1411,20 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + bool hasAlias = false; for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); - if (p.isDefaultProperty) + if (p.isDefaultProperty && + (p.type != Object::DynamicProperty::Alias || preAlias != -1)) builder.addClassInfo("DefaultProperty", p.name); QByteArray type; switch(p.type) { + case Object::DynamicProperty::Alias: + hasAlias = true; + continue; + break; case Object::DynamicProperty::Variant: type = "QVariant"; break; @@ -1466,7 +1472,29 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); builder.addSlot(s.name + "()"); - output->primitives << s.body; + + if (preAlias == -1) + output->primitives << s.body; + } + + QByteArray aliasData; + if (preAlias != -1) { + int dynProperties = 0; + QByteArray data; + int propCount = builder.propertyCount(); + int signalCount = builder.methodCount(); + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (p.type == Object::DynamicProperty::Alias) { + dynProperties++; + compileAlias(builder, data, obj, p); + } + } + aliasData.append((const char *)&dynProperties, sizeof(int)); + aliasData.append((const char *)&propCount, sizeof(int)); + aliasData.append((const char *)&signalCount, sizeof(int)); + aliasData.append(data); } if (obj->metatype) @@ -1475,17 +1503,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) obj->extObjectData = builder.toMetaObject(); static_cast<QMetaObject &>(obj->extObject) = *obj->extObjectData; - output->synthesizedMetaObjects << obj->extObjectData; - QmlInstruction store; - store.type = QmlInstruction::StoreMetaObject; - store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; - store.storeMeta.slotData = slotStart; - store.line = obj->location.start.line; - output->bytecode << store; + if (preAlias != -1) { + QmlInstruction &store = output->bytecode[preAlias]; + + store.storeMeta.aliasData = output->indexForByteArray(aliasData); + qFree(output->synthesizedMetaObjects.at(store.storeMeta.data)); + output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData; + + } else { + output->synthesizedMetaObjects << obj->extObjectData; + QmlInstruction store; + store.type = QmlInstruction::StoreMetaObject; + store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; + store.storeMeta.slotData = slotStart; + store.storeMeta.aliasData = -1; + store.line = obj->location.start.line; + output->bytecode << store; + + if (hasAlias) { + AliasReference alias; + alias.object = obj; + alias.instructionIdx = output->bytecode.count() - 1; + compileState.aliases << alias; + } + } for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + if (p.type == Object::DynamicProperty::Alias) + continue; + if (p.defaultValue) { p.defaultValue->name = p.name; p.defaultValue->isDefault = false; @@ -1496,6 +1544,66 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } +#include <private/qmljsparser_p.h> +static QStringList astNodeToStringList(QmlJS::AST::Node *node) +{ + if (node->kind == QmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QmlJS::AST::IdentifierExpression *>(node)->name->asString(); + return QStringList() << name; + } else if (node->kind == QmlJS::AST::Node::Kind_FieldMemberExpression) { + QmlJS::AST::FieldMemberExpression *expr = static_cast<QmlJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name->asString()); + return rv; + } + return QStringList(); +} + +bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, + QByteArray &data, + Object *obj, + const Object::DynamicProperty &prop) +{ + if (!prop.defaultValue) + COMPILE_EXCEPTION("No property alias location"); + + if (prop.defaultValue->values.count() != 1 || + prop.defaultValue->values.at(0)->object || + !prop.defaultValue->values.at(0)->value.isScript()) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + if (!node) + COMPILE_EXCEPTION("No property alias location"); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() != 2) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + if (!compileState.ids.contains(alias.at(0))) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + const IdReference &id = compileState.ids[alias.at(0)]; + int propIdx = id.object->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + + if (-1 == propIdx) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + QMetaProperty aliasProperty = id.object->metaObject()->property(propIdx); + + data.append((const char *)&id.idx, sizeof(id.idx)); + data.append((const char *)&propIdx, sizeof(propIdx)); + + builder.addSignal(prop.name + "Changed()"); + builder.addProperty(prop.name, aliasProperty.typeName(), builder.methodCount() - 1); + return true; +} + bool QmlCompiler::compileBinding(QmlParser::Value *value, QmlParser::Property *prop, const BindingContext &ctxt) @@ -1564,17 +1672,29 @@ protected: // Update the init instruction with final data, and optimize some simple // bindings -void QmlCompiler::finalizeComponent(int patch) +bool QmlCompiler::finalizeComponent(int patch) { for (int ii = 0; ii < compileState.bindings.count(); ++ii) { const BindingReference &binding = compileState.bindings.at(ii); finalizeBinding(binding); } + for (int ii = 0; ii < compileState.aliases.count(); ++ii) { + const AliasReference &alias = compileState.aliases.at(ii); + COMPILE_CHECK(finalizeAlias(alias)); + } + output->bytecode[patch].init.dataSize = compileState.savedObjects;; output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); output->bytecode[patch].init.parserStatusSize = compileState.parserStatusCount; + + return true; +} + +bool QmlCompiler::finalizeAlias(const AliasReference &alias) +{ + COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx)); } void QmlCompiler::finalizeBinding(const BindingReference &binding) diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 819c4ad..1c45f57 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -118,6 +118,7 @@ private: int indexForLocation(const QmlParser::LocationSpan &); }; +class QMetaObjectBuilder; class Q_DECLARATIVE_EXPORT QmlCompiler { public: @@ -181,13 +182,19 @@ private: const QMetaProperty &prop, QmlParser::Value *value); - bool compileDynamicMeta(QmlParser::Object *obj); + bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1); + bool compileAlias(QMetaObjectBuilder &, + QByteArray &data, + QmlParser::Object *obj, + const QmlParser::Object::DynamicProperty &); bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, const BindingContext &ctxt); - void finalizeComponent(int patch); + bool finalizeComponent(int patch); struct BindingReference; void finalizeBinding(const BindingReference &); + struct AliasReference; + bool finalizeAlias(const AliasReference &); bool canConvert(int, QmlParser::Object *); QStringList deferredProperties(QmlParser::Object *); @@ -199,6 +206,11 @@ private: int idx; }; + struct AliasReference { + QmlParser::Object *object; + int instructionIdx; + }; + struct BindingReference { QmlParser::Variant expression; QmlParser::Property *property; @@ -215,6 +227,7 @@ private: int savedObjects; int pushedProperties; QList<BindingReference> bindings; + QList<AliasReference> aliases; QmlParser::Object *root; }; ComponentCompileState compileState; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index f2f3ac2..40f9a32 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -181,6 +181,7 @@ public: struct { int data; int slotData; + int aliasData; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 9daa336..803c73e 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -144,7 +144,7 @@ namespace QmlParser DynamicProperty(); DynamicProperty(const DynamicProperty &); - enum Type { Variant, Int, Bool, Real, String, Url, Color, Date }; + enum Type { Variant, Int, Bool, Real, String, Url, Color, Date, Alias }; bool isDefaultProperty; Type type; diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 7475943..cb65c5c 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -534,6 +534,12 @@ bool ProcessAST::visit(AST::UiPublicMember *node) bool typeFound = false; Object::DynamicProperty::Type type; + + if (memberType == QLatin1String("alias")) { + type = Object::DynamicProperty::Alias; + typeFound = true; + } + for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) { type = propTypeNameToTypes[ii].type; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 962d917..0f49e1e 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -240,7 +240,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp case QmlInstruction::StoreMetaObject: { QObject *target = stack.top(); - new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, comp); + new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (instr.storeMeta.aliasData != -1)?datas.at(instr.storeMeta.aliasData):QByteArray(), comp); } break; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index ec269b8..dc06bc5 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -47,6 +47,7 @@ #include <QtCore/qlist.h> #include <QtCore/qdebug.h> #include <qmlexpression.h> +#include <private/qmlcontext_p.h> QT_BEGIN_NAMESPACE @@ -54,8 +55,10 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, QList<QString> *strData, int slotData, + const QByteArray &alias, QmlRefCount *rc) -: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData), parent(0) +: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData), parent(0), + aliasData(alias), aliases(0), aliasArray(0) { if (ref) ref->addref(); @@ -68,13 +71,20 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); op->metaObject = this; + if (!aliasData.isEmpty()) { + aliases = (Aliases *)aliasData.constData(); + aliasArray = (AliasArray *)(aliasData.constData() + 3 * sizeof(int)); + aConnected.resize(aliases->aliasCount); + } + baseProp = propertyOffset(); baseSig = methodOffset(); - data = new QVariant[propertyCount() - baseProp]; - vTypes.resize(propertyCount() - baseProp); + int propCount = propertyCount() - (aliases?aliases->aliasCount:0); + data = new QVariant[propCount - baseProp]; + vTypes.resize(propCount - baseProp); // ### Optimize - for (int ii = baseProp; ii < propertyCount(); ++ii) { + for (int ii = baseProp; ii < propCount; ++ii) { QMetaProperty prop = property(ii); if ((int)prop.type() != -1) { data[ii - baseProp] = QVariant((QVariant::Type)prop.userType()); @@ -117,7 +127,34 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a) int propId = id - baseProp; bool needActivate = false; - if (vTypes.testBit(propId)) { + if (aliases && propId >= aliases->propCount) { + QmlContext *ctxt = qmlContext(object); + + if (!ctxt) return -1; + int aliasId = propId - aliases->propCount; + AliasArray *d = aliasArray + aliasId; + QmlContextPrivate *ctxtPriv = + (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + QObject *target = *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data(); + if (!target) return -1; + + if (c == QMetaObject::ReadProperty && + !aConnected.testBit(aliasId)) { + + int mySigIdx = baseSig + aliasId + aliases->signalOffset; + QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, mySigIdx); + + QMetaProperty prop = target->metaObject()->property(d->propIdx); + if (prop.hasNotifySignal()) + QMetaObject::connect(target, prop.notifySignalIndex(), + object, mySigIdx); + aConnected.setBit(aliasId); + + } + return QMetaObject::metacall(target, c, d->propIdx, a); + + } else if (vTypes.testBit(propId)) { if (c == QMetaObject::ReadProperty) { *reinterpret_cast<QVariant *>(a[0]) = data[propId]; } else if (c == QMetaObject::WriteProperty) { @@ -168,7 +205,10 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a) return id; } } else if(c == QMetaObject::InvokeMetaMethod) { - if (id >= baseSig && (baseSlot == -1 || id < baseSlot)) { + if (id >= baseSig && (aliases && id >= baseSig + aliases->signalOffset)) { + QMetaObject::activate(object, id, a); + return id; + } else if (id >= baseSig && (baseSlot == -1 || id < baseSlot)) { QMetaObject::activate(object, id, a); return id; } else if (id >= baseSlot && id < (baseSlot + slotCount)) { diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 7b6fd2d..45fb33d 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -63,7 +63,7 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QByteArray &aliasData, QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -78,9 +78,20 @@ private: int slotCount; QVariant *data; QBitArray vTypes; + QBitArray aConnected; QList<QString> *slotData; int slotDataIdx; QAbstractDynamicMetaObject *parent; + QByteArray aliasData; + struct Aliases { + int aliasCount; + int propCount; + int signalOffset; + } *aliases; + struct AliasArray { + int contextIdx; + int propIdx; + } *aliasArray; }; QT_END_NAMESPACE |