diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-25 05:52:55 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2010-01-25 05:52:55 (GMT) |
commit | 19db5db690d4daffe6b88580ec1cc886bb02dcfd (patch) | |
tree | 6516027d6d30bd7429c9267c500ea5b2e7117ff9 | |
parent | 3a75eeb5da34fbb50173c3f610c08d160c21f4e3 (diff) | |
download | Qt-19db5db690d4daffe6b88580ec1cc886bb02dcfd.zip Qt-19db5db690d4daffe6b88580ec1cc886bb02dcfd.tar.gz Qt-19db5db690d4daffe6b88580ec1cc886bb02dcfd.tar.bz2 |
Support attached properties in QmlMetaProperty
QTBUG-5580
-rw-r--r-- | src/declarative/qml/qmlmetaproperty.cpp | 56 | ||||
-rw-r--r-- | tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp | 75 |
2 files changed, 115 insertions, 16 deletions
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 6738370..4717782 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -46,6 +46,7 @@ #include "qml.h" #include "qmlbinding.h" #include "qmlcontext.h" +#include "qmlcontext_p.h" #include "qmlboundsignal_p.h" #include "qmlengine.h" #include "qmlengine_p.h" @@ -160,17 +161,13 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (enginePrivate && name.at(0).isUpper()) { // Attached property - //### needs to be done in a better way - QmlCompositeTypeData *typeData = - enginePrivate->typeManager.get(context->baseUrl()); - - if (typeData) { - QmlType *t = 0; - enginePrivate->resolveType(typeData->imports, name.toUtf8(), &t, 0, 0, 0, 0); - if (t && t->attachedPropertiesFunction()) { - attachedFunc = t->index(); + // ### What about qualified types? + QmlTypeNameCache *tnCache = QmlContextPrivate::get(context)->imports; + if (tnCache) { + QmlTypeNameCache::Data *d = tnCache->data(name); + if (d && d->type && d->type->attachedPropertiesFunction()) { + attachedFunc = d->type->index(); } - typeData->release(); } return; @@ -676,7 +673,7 @@ QVariant QmlMetaProperty::read() const return QVariant(); - } else if (type() & Property) { + } else if (type() & Property || type() & Attached) { return d->readValueProperty(); @@ -1122,24 +1119,51 @@ QmlMetaPropertyPrivate::restore(const QByteArray &data, QObject *object, QmlCont Creates a QmlMetaProperty for the property \a name of \a obj. Unlike the QmlMetaProperty(QObject*, QString, QmlContext*) constructor, this static function - will correctly handle dot properties. + will correctly handle dot properties, including value types and attached properties. */ QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &name, QmlContext *context) { - QStringList path = name.split(QLatin1Char('.')); + QmlTypeNameCache *typeNameCache = context?QmlContextPrivate::get(context)->imports:0; + QStringList path = name.split(QLatin1Char('.')); QObject *object = obj; for (int jj = 0; jj < path.count() - 1; ++jj) { const QString &pathName = path.at(jj); + + if (QmlTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) { + if (data->type) { + QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) + return QmlMetaProperty(); + object = qmlAttachedPropertiesObjectById(data->type->index(), object); + if (!object) + return QmlMetaProperty(); + continue; + } else { + Q_ASSERT(data->typeNamespace); + ++jj; + data = data->typeNamespace->data(path.at(jj)); + if (!data || !data->type) + return QmlMetaProperty(); + QmlAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) + return QmlMetaProperty(); + object = qmlAttachedPropertiesObjectById(data->type->index(), object); + if (!object) + return QmlMetaProperty(); + continue; + } + } + QmlMetaProperty prop(object, pathName, context); - if (jj == path.count() - 2 && - prop.propertyType() < (int)QVariant::UserType && + if (jj == path.count() - 2 && prop.propertyType() < (int)QVariant::UserType && qmlValueTypes()->valueTypes[prop.propertyType()]) { - // We're now at a value type property + // We're now at a value type property. We can use a global valuetypes array as we + // never actually use the objects, just look up their properties. QObject *typeObject = qmlValueTypes()->valueTypes[prop.propertyType()]; int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData()); diff --git a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp index 63d8274..a44ea6e 100644 --- a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp +++ b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp @@ -56,6 +56,20 @@ public: QML_DECLARE_TYPE(MyQmlObject); QML_DEFINE_TYPE(Test,1,0,MyQmlObject,MyQmlObject); +class MyAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(int foo READ foo WRITE setFoo) +public: + MyAttached(QObject *parent) : QObject(parent), m_foo(13) {} + + int foo() const { return m_foo; } + void setFoo(int f) { m_foo = f; } + +private: + int m_foo; +}; + class MyContainer : public QObject { Q_OBJECT @@ -67,6 +81,10 @@ public: QList<MyQmlObject*> *children() { return &m_children; } QmlConcreteList<MyQmlObject *> *qmlChildren() { return &m_qmlChildren; } + static MyAttached *qmlAttachedProperties(QObject *o) { + return new MyAttached(o); + } + private: QList<MyQmlObject*> m_children; QmlConcreteList<MyQmlObject *> m_qmlChildren; @@ -74,6 +92,7 @@ private: QML_DECLARE_TYPE(MyContainer); QML_DEFINE_TYPE(Test,1,0,MyContainer,MyContainer); +QML_DECLARE_TYPEINFO(MyContainer, QML_HAS_ATTACHED_PROPERTIES) class tst_qmlmetaproperty : public QObject { @@ -798,6 +817,38 @@ void tst_qmlmetaproperty::read() delete o; QCOMPARE(p.read(), QVariant()); } + + // Attached property + { + QmlComponent component(&engine); + component.setData("import Test 1.0\nMyContainer { }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QmlMetaProperty p = QmlMetaProperty::createProperty(object, "MyContainer.foo", qmlContext(object)); + QCOMPARE(p.read(), QVariant(13)); + delete object; + } + { + QmlComponent component(&engine); + component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QmlMetaProperty p = QmlMetaProperty::createProperty(object, "MyContainer.foo", qmlContext(object)); + QCOMPARE(p.read(), QVariant(10)); + delete object; + } + { + QmlComponent component(&engine); + component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QmlMetaProperty p = QmlMetaProperty::createProperty(object, "Foo.MyContainer.foo", qmlContext(object)); + QCOMPARE(p.read(), QVariant(10)); + delete object; + } } void tst_qmlmetaproperty::write() @@ -896,6 +947,30 @@ void tst_qmlmetaproperty::write() QCOMPARE(p2.write(QUrl("main.qml")), true); QCOMPARE(o.url(), result); } + + // Attached property + { + QmlComponent component(&engine); + component.setData("import Test 1.0\nMyContainer { }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QmlMetaProperty p = QmlMetaProperty::createProperty(object, "MyContainer.foo", qmlContext(object)); + p.write(QVariant(99)); + QCOMPARE(p.read(), QVariant(99)); + delete object; + } + { + QmlComponent component(&engine); + component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QmlMetaProperty p = QmlMetaProperty::createProperty(object, "Foo.MyContainer.foo", qmlContext(object)); + p.write(QVariant(99)); + QCOMPARE(p.read(), QVariant(99)); + delete object; + } } void tst_qmlmetaproperty::writeObjectToList() |