summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-07-02 06:14:27 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-07-02 06:14:27 (GMT)
commit49bceaf197a5964f244ac094aaa75b35cf3ada49 (patch)
tree37428a137a608757d4a1c548decf6ff46f1b67f9 /src/declarative
parentba13a6003d95f9d07f94bdb0e210e0c0453d8b80 (diff)
downloadQt-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')
-rw-r--r--src/declarative/qml/qmlcompiler.cpp156
-rw-r--r--src/declarative/qml/qmlcompiler_p.h17
-rw-r--r--src/declarative/qml/qmlinstruction_p.h1
-rw-r--r--src/declarative/qml/qmlparser_p.h2
-rw-r--r--src/declarative/qml/qmlscriptparser.cpp6
-rw-r--r--src/declarative/qml/qmlvme.cpp2
-rw-r--r--src/declarative/qml/qmlvmemetaobject.cpp52
-rw-r--r--src/declarative/qml/qmlvmemetaobject_p.h13
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