From 3051067a661db92c77f9cf8c31d3231174a6a475 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 11 Dec 2009 13:59:34 +1000 Subject: Dynamic metaobject sharing and caching. --- .../graphicsitems/qmlgraphicsvisualitemmodel.cpp | 156 ++++++++++++--------- src/declarative/qml/qmlpropertycache.cpp | 29 ++-- src/declarative/qml/qmlpropertycache_p.h | 2 + src/declarative/util/qmlopenmetaobject.cpp | 115 ++++++++++----- src/declarative/util/qmlopenmetaobject_p.h | 22 ++- 5 files changed, 208 insertions(+), 116 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp index c6f790c..7c2159f 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp @@ -241,6 +241,17 @@ QmlGraphicsVisualItemModelAttached *QmlGraphicsVisualItemModel::qmlAttachedPrope return QmlGraphicsVisualItemModelAttached::properties(obj); } +//============================================================================ + +class VDMDelegateDataType : public QmlOpenMetaObjectType +{ +public: + VDMDelegateDataType(const QMetaObject *base, QmlEngine *engine) : QmlOpenMetaObjectType(base, engine) {} + + void propertyCreated(int, QMetaPropertyBuilder &prop) { + prop.setWritable(false); + } +}; class QmlGraphicsVisualDataModelParts; class QmlGraphicsVisualDataModelData; @@ -261,31 +272,31 @@ public: QmlComponent *m_delegate; QmlContext *m_context; QList m_roles; - QHash m_roleNames; + QHash m_roleNames; void ensureRoles() { if (m_roleNames.isEmpty()) { if (m_listModelInterface) { m_roles = m_listModelInterface->roles(); for (int ii = 0; ii < m_roles.count(); ++ii) - m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)), m_roles.at(ii)); + m_roleNames.insert(m_listModelInterface->toString(m_roles.at(ii)).toUtf8(), m_roles.at(ii)); if (m_roles.count() == 1) - m_roleNames.insert(QLatin1String("modelData"), m_roles.at(0)); + m_roleNames.insert("modelData", m_roles.at(0)); } else if (m_abstractItemModel) { for (QHash::const_iterator it = m_abstractItemModel->roleNames().begin(); it != m_abstractItemModel->roleNames().end(); ++it) { m_roles.append(it.key()); - m_roleNames.insert(QString::fromUtf8(*it), it.key()); + m_roleNames.insert(*it, it.key()); } if (m_roles.count() == 1) - m_roleNames.insert(QLatin1String("modelData"), m_roles.at(0)); + m_roleNames.insert("modelData", m_roles.at(0)); } else if (m_listAccessor) { - m_roleNames.insert(QLatin1String("modelData"), 0); + m_roleNames.insert("modelData", 0); if (m_listAccessor->type() == QmlListAccessor::Instance) { if (QObject *object = m_listAccessor->at(0).value()) { int count = object->metaObject()->propertyCount(); for (int ii = 1; ii < count; ++ii) { const QMetaProperty &prop = object->metaObject()->property(ii); - m_roleNames.insert(QString::fromUtf8(prop.name()), 0); + m_roleNames.insert(prop.name(), 0); } } } @@ -293,6 +304,18 @@ public: } } + void createMetaData() { + if (!m_metaDataCreated) { + ensureRoles(); + QHash::const_iterator it = m_roleNames.begin(); + while (it != m_roleNames.end()) { + m_delegateDataType->createProperty(it.key()); + ++it; + } + m_metaDataCreated = true; + } + } + struct ObjectRef { ObjectRef(QObject *object=0) : obj(object), ref(1) {} QObject *obj; @@ -335,31 +358,33 @@ public: } }; + int modelCount() const { + if (m_visualItemModel) + return m_visualItemModel->count(); + if (m_listModelInterface) + return m_listModelInterface->count(); + if (m_abstractItemModel) + return m_abstractItemModel->rowCount(); + if (m_listAccessor) + return m_listAccessor->count(); + return 0; + } + Cache m_cache; QHash m_packaged; QmlGraphicsVisualDataModelParts *m_parts; friend class QmlGraphicsVisualItemParts; - QmlOpenMetaObjectType *m_delegateDataType; + VDMDelegateDataType *m_delegateDataType; friend class QmlGraphicsVisualDataModelData; + bool m_metaDataCreated; + bool m_metaDataCacheable; QmlGraphicsVisualDataModelData *data(QObject *item); QVariant m_modelVariant; QmlListAccessor *m_listAccessor; - - int modelCount() const { - if (m_visualItemModel) - return m_visualItemModel->count(); - if (m_listModelInterface) - return m_listModelInterface->count(); - if (m_abstractItemModel) - return m_abstractItemModel->rowCount(); - if (m_listAccessor) - return m_listAccessor->count(); - return 0; - } }; class QmlGraphicsVisualDataModelDataMetaObject : public QmlOpenMetaObject @@ -368,13 +393,12 @@ public: QmlGraphicsVisualDataModelDataMetaObject(QObject *parent, QmlOpenMetaObjectType *type) : QmlOpenMetaObject(parent, type) {} - virtual void propertyCreated(int, QMetaPropertyBuilder &); virtual QVariant initialValue(int); virtual int createProperty(const char *, const char *); private: friend class QmlGraphicsVisualDataModelData; - QList roles; + QHash roleToProp; }; class QmlGraphicsVisualDataModelData : public QObject @@ -388,8 +412,7 @@ public: int index() const; void setIndex(int index); - int count() const; - int role(int) const; + int propForRole(int) const; void setValue(int, const QVariant &); Q_SIGNALS: @@ -402,15 +425,12 @@ private: QmlGraphicsVisualDataModelDataMetaObject *m_meta; }; -int QmlGraphicsVisualDataModelData::count() const -{ - return m_meta->count(); -} - -int QmlGraphicsVisualDataModelData::role(int id) const +int QmlGraphicsVisualDataModelData::propForRole(int id) const { - Q_ASSERT(id >= 0 && id < count()); - return m_meta->roles.at(id); + QHash::const_iterator it = m_meta->roleToProp.find(id); + if (it != m_meta->roleToProp.end()) + return m_meta->roleToProp[id]; + return -1; } void QmlGraphicsVisualDataModelData::setValue(int id, const QVariant &val) @@ -429,28 +449,16 @@ int QmlGraphicsVisualDataModelDataMetaObject::createProperty(const char *name, c QmlGraphicsVisualDataModelPrivate *model = QmlGraphicsVisualDataModelPrivate::get(data->m_model); if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { - model->ensureRoles(); - if (model->m_roleNames.contains(QString::fromUtf8(name))) { - return QmlOpenMetaObject::createProperty(name, type); - } else if (model->m_listAccessor->type() == QmlListAccessor::QmlList) { + if (model->m_listAccessor->type() == QmlListAccessor::QmlList) { + model->ensureRoles(); QObject *object = model->m_listAccessor->at(data->m_index).value(); if (object && object->property(name).isValid()) return QmlOpenMetaObject::createProperty(name, type); } - } else { - model->ensureRoles(); - QString sname = QString::fromUtf8(name); - if (model->m_roleNames.contains(sname)) - return QmlOpenMetaObject::createProperty(name, type); } return -1; } -void QmlGraphicsVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop) -{ - prop.setWritable(false); -} - QVariant QmlGraphicsVisualDataModelDataMetaObject::initialValue(int propId) { QmlGraphicsVisualDataModelData *data = @@ -459,9 +467,9 @@ QVariant QmlGraphicsVisualDataModelDataMetaObject::initialValue(int propId) Q_ASSERT(data->m_model); QmlGraphicsVisualDataModelPrivate *model = QmlGraphicsVisualDataModelPrivate::get(data->m_model); - QString strName = QString::fromUtf8(name(propId)); + QByteArray propName = name(propId); if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { - if (strName == QLatin1String("modelData")) { + if (propName == "modelData") { if (model->m_listAccessor->type() == QmlListAccessor::Instance) { QObject *object = model->m_listAccessor->at(0).value(); return object->metaObject()->property(1).read(object); // the first property after objectName @@ -470,20 +478,21 @@ QVariant QmlGraphicsVisualDataModelDataMetaObject::initialValue(int propId) } else { // return any property of a single object instance. QObject *object = model->m_listAccessor->at(data->m_index).value(); - return object->property(name(propId)); + return object->property(propName); } } else if (model->m_listModelInterface) { model->ensureRoles(); - QHash::const_iterator it = model->m_roleNames.find(strName); + QHash::const_iterator it = model->m_roleNames.find(propName); if (it != model->m_roleNames.end()) { - roles.append(*it); + roleToProp.insert(*it, propId); QHash values = model->m_listModelInterface->data(data->m_index, QList() << *it); if (values.isEmpty()) return QVariant(); else return values.value(*it); - } else if (model->m_roles.count() == 1 && strName == QLatin1String("modelData")) { + } else if (model->m_roles.count() == 1 && propName == "modelData") { //for compatability with other lists, assign modelData if there is only a single role + roleToProp.insert(model->m_roles.first(), propId); QHash values = model->m_listModelInterface->data(data->m_index, QList() << model->m_roles.first()); if (values.isEmpty()) return QVariant(); @@ -492,9 +501,9 @@ QVariant QmlGraphicsVisualDataModelDataMetaObject::initialValue(int propId) } } else if (model->m_abstractItemModel) { model->ensureRoles(); - QHash::const_iterator it = model->m_roleNames.find(strName); + QHash::const_iterator it = model->m_roleNames.find(propName); if (it != model->m_roleNames.end()) { - roles.append(*it); + roleToProp.insert(*it, propId); QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0); return model->m_abstractItemModel->data(index, *it); } @@ -508,6 +517,12 @@ QmlGraphicsVisualDataModelData::QmlGraphicsVisualDataModelData(int index, : m_index(index), m_model(model), m_meta(new QmlGraphicsVisualDataModelDataMetaObject(this, QmlGraphicsVisualDataModelPrivate::get(model)->m_delegateDataType)) { + QmlGraphicsVisualDataModelPrivate *modelPriv = QmlGraphicsVisualDataModelPrivate::get(model); + if (modelPriv->m_metaDataCacheable) { + if (!modelPriv->m_metaDataCreated) + modelPriv->createMetaData(); + m_meta->setCached(true); + } } QmlGraphicsVisualDataModelData::~QmlGraphicsVisualDataModelData() @@ -526,6 +541,8 @@ void QmlGraphicsVisualDataModelData::setIndex(int index) emit indexChanged(); } +//--------------------------------------------------------------------------- + class QmlGraphicsVisualDataModelPartsMetaObject : public QmlOpenMetaObject { public: @@ -571,7 +588,8 @@ QmlGraphicsVisualDataModelParts::QmlGraphicsVisualDataModelParts(QmlGraphicsVisu QmlGraphicsVisualDataModelPrivate::QmlGraphicsVisualDataModelPrivate(QmlContext *ctxt) : m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0) -, m_context(ctxt), m_parts(0), m_delegateDataType(0), m_listAccessor(0) +, m_context(ctxt), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false) +, m_metaDataCacheable(false), m_listAccessor(0) { } @@ -583,6 +601,8 @@ QmlGraphicsVisualDataModelData *QmlGraphicsVisualDataModelPrivate::data(QObject return dataItem; } +//--------------------------------------------------------------------------- + QmlGraphicsVisualDataModel::QmlGraphicsVisualDataModel() : QmlGraphicsVisualModel(*(new QmlGraphicsVisualDataModelPrivate(0))) { @@ -598,6 +618,8 @@ QmlGraphicsVisualDataModel::~QmlGraphicsVisualDataModel() Q_D(QmlGraphicsVisualDataModel); if (d->m_listAccessor) delete d->m_listAccessor; + if (d->m_delegateDataType) + d->m_delegateDataType->release(); } QVariant QmlGraphicsVisualDataModel::model() const @@ -648,8 +670,11 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) d->m_roles.clear(); d->m_roleNames.clear(); - delete d->m_delegateDataType; - d->m_delegateDataType = new QmlOpenMetaObjectType(d->m_context?d->m_context->engine():qmlEngine(this)); + if (d->m_delegateDataType) + d->m_delegateDataType->release(); + d->m_metaDataCreated = 0; + d->m_metaDataCacheable = false; + d->m_delegateDataType = new VDMDelegateDataType(&QmlGraphicsVisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this)); QObject *object = qvariant_cast(model); if (object && (d->m_listModelInterface = qobject_cast(object))) { @@ -661,6 +686,7 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_itemsRemoved(int,int))); QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), this, SLOT(_q_itemsMoved(int,int,int))); + d->m_metaDataCacheable = true; if (d->m_delegate && d->m_listModelInterface->count()) emit itemsInserted(0, d->m_listModelInterface->count()); return; @@ -673,6 +699,7 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&))); QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int))); + d->m_metaDataCacheable = true; return; } if ((d->m_visualItemModel = qvariant_cast(model))) { @@ -690,6 +717,8 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) } d->m_listAccessor = new QmlListAccessor; d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this)); + if (d->m_listAccessor->type() != QmlListAccessor::QmlList) + d->m_metaDataCacheable = true; if (d->m_delegate && d->modelCount()) { emit itemsInserted(0, d->modelCount()); emit countChanged(); @@ -903,20 +932,19 @@ void QmlGraphicsVisualDataModel::_q_itemsChanged(int index, int count, if (QObject *item = d->m_cache.item(ii)) { QmlGraphicsVisualDataModelData *data = d->data(item); - for (int prop = 0; prop < data->count(); ++prop) { - - int role = data->role(prop); - if (roles.contains(role)) { + for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) { + int role = roles.at(roleIdx); + int propId = data->propForRole(role); + if (propId != -1) { if (d->m_listModelInterface) { - data->setValue(prop, d->m_listModelInterface->data(ii, QList() << role).value(role)); + data->setValue(propId, d->m_listModelInterface->data(ii, QList() << role).value(role)); } else if (d->m_abstractItemModel) { QModelIndex index = d->m_abstractItemModel->index(ii, 0); - data->setValue(prop, d->m_abstractItemModel->data(index, role)); + data->setValue(propId, d->m_abstractItemModel->data(index, role)); } } } } - } } diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index bad8ad8..6ba6028 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -43,6 +43,7 @@ #include "qmlengine_p.h" #include "qmlbinding.h" +#include "qdebug.h" QT_BEGIN_NAMESPACE @@ -119,7 +120,6 @@ QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, Q_ASSERT(metaObject); QmlPropertyCache::Data rv; - int idx = metaObject->indexOfProperty(property.toUtf8()); if (idx != -1) { rv.load(metaObject->property(idx)); @@ -151,13 +151,22 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject Q_ASSERT(metaObject); QmlPropertyCache *cache = new QmlPropertyCache(engine); + cache->update(engine, metaObject); + return cache; +} +void QmlPropertyCache::update(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + clear(); + // ### The properties/methods should probably be spliced on a per-metaobject basis int propCount = metaObject->propertyCount(); - cache->indexCache.resize(propCount); + indexCache.resize(propCount); for (int ii = propCount - 1; ii >= 0; --ii) { QMetaProperty p = metaObject->property(ii); QString propName = QString::fromUtf8(p.name()); @@ -167,13 +176,13 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject data->load(p); - cache->indexCache[ii] = data; + indexCache[ii] = data; - if (cache->stringCache.contains(propName)) + if (stringCache.contains(propName)) continue; - cache->stringCache.insert(propName, data); - cache->identifierCache.insert(data->identifier.identifier, data); + stringCache.insert(propName, data); + identifierCache.insert(data->identifier.identifier, data); data->addref(); data->addref(); } @@ -187,7 +196,7 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject Q_ASSERT(parenIdx != -1); methodName = methodName.left(parenIdx); - if (cache->stringCache.contains(methodName)) + if (stringCache.contains(methodName)) continue; RData *data = new RData; @@ -195,12 +204,10 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject data->load(m); - cache->stringCache.insert(methodName, data); - cache->identifierCache.insert(data->identifier.identifier, data); + stringCache.insert(methodName, data); + identifierCache.insert(data->identifier.identifier, data); data->addref(); } - - return cache; } QmlPropertyCache::Data * diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 7cee606..613f4dd 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -110,6 +110,8 @@ public: int valueTypePropType; // The QVariant::Type of access property on the value type wrapper }; + void update(QmlEngine *, const QMetaObject *); + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); static Data create(const QMetaObject *, const QString &); diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp index 473d9d9..e66a3e7 100644 --- a/src/declarative/util/qmlopenmetaobject.cpp +++ b/src/declarative/util/qmlopenmetaobject.cpp @@ -43,7 +43,7 @@ #include "qmlpropertycache_p.h" #include "qmldeclarativedata_p.h" #include -#include +#include QT_BEGIN_NAMESPACE @@ -51,39 +51,69 @@ QT_BEGIN_NAMESPACE class QmlOpenMetaObjectTypePrivate { public: - QmlOpenMetaObjectTypePrivate() : mem(0), engine(0) {} + QmlOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {} - void init(QObject *obj); + void init(const QMetaObject *metaObj); int propertyOffset; int signalOffset; QHash names; QMetaObjectBuilder mob; QMetaObject *mem; + QmlPropertyCache *cache; QmlEngine *engine; + QSet referers; }; -QmlOpenMetaObjectType::QmlOpenMetaObjectType(QmlEngine *engine) +QmlOpenMetaObjectType::QmlOpenMetaObjectType(const QMetaObject *base, QmlEngine *engine) : d(new QmlOpenMetaObjectTypePrivate) { d->engine = engine; + d->init(base); } QmlOpenMetaObjectType::~QmlOpenMetaObjectType() { + if (d->mem) + qFree(d->mem); + delete d; +} + +int QmlOpenMetaObjectType::createProperty(const QByteArray &name) +{ + int id = d->mob.propertyCount(); + d->mob.addSignal("__" + QByteArray::number(id) + "()"); + QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id); + build.setDynamic(true); + propertyCreated(id, build); qFree(d->mem); + d->mem = d->mob.toMetaObject(); + d->names.insert(name, id); + QSet::iterator it = d->referers.begin(); + while (it != d->referers.end()) { + QmlOpenMetaObject *omo = *it; + *static_cast(omo) = *d->mem; + if (d->cache) + d->cache->update(d->engine, omo); + ++it; + } + + return d->propertyOffset + id; } -void QmlOpenMetaObjectTypePrivate::init(QObject *obj) +void QmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder) +{ + if (d->referers.count()) + (*d->referers.begin())->propertyCreated(id, builder); +} + +void QmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj) { if (!mem) { - mob.setSuperClass(obj->metaObject()); - mob.setClassName(obj->metaObject()->className()); + mob.setSuperClass(metaObj); + mob.setClassName(metaObj->className()); mob.setFlags(QMetaObjectBuilder::DynamicMetaObject); - QObjectPrivate *op = QObjectPrivate::get(obj); - if (op->metaObject) - mob.setSuperClass(op->metaObject); mem = mob.toMetaObject(); propertyOffset = mem->propertyOffset(); @@ -91,10 +121,13 @@ void QmlOpenMetaObjectTypePrivate::init(QObject *obj) } } +//---------------------------------------------------------------------------- + class QmlOpenMetaObjectPrivate { public: - QmlOpenMetaObjectPrivate(QmlOpenMetaObject *_q) : q(_q), parent(0), type(0), ownType(false) {} + QmlOpenMetaObjectPrivate(QmlOpenMetaObject *_q) + : q(_q), parent(0), type(0), cacheProperties(false) {} inline QVariant &getData(int idx) { while (data.count() <= idx) @@ -121,7 +154,7 @@ public: QList > data; QObject *object; QmlOpenMetaObjectType *type; - bool ownType; + bool cacheProperties; }; QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, bool automatic) @@ -130,9 +163,8 @@ QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, bool automatic) d->autoCreate = automatic; d->object = obj; - d->type = new QmlOpenMetaObjectType(0); - d->ownType = true; - d->type->d->init(obj); + d->type = new QmlOpenMetaObjectType(obj->metaObject(), 0); + d->type->d->referers.insert(this); QObjectPrivate *op = QObjectPrivate::get(obj); *static_cast(this) = *d->type->d->mem; @@ -146,7 +178,8 @@ QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, QmlOpenMetaObjectType *type, d->object = obj; d->type = type; - d->type->d->init(obj); + d->type->addref(); + d->type->d->referers.insert(this); QObjectPrivate *op = QObjectPrivate::get(obj); *static_cast(this) = *d->type->d->mem; @@ -157,11 +190,16 @@ QmlOpenMetaObject::~QmlOpenMetaObject() { if (d->parent) delete d->parent; - if (d->ownType) - delete d->type; + d->type->d->referers.remove(this); + d->type->release(); delete d; } +QmlOpenMetaObjectType *QmlOpenMetaObject::type() const +{ + return d->type; +} + int QmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) { if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) @@ -220,7 +258,7 @@ void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) int id = -1; if (iter == d->type->d->names.end()) { - id = doCreateProperty(name.constData()) - d->type->d->propertyOffset; + id = d->type->createProperty(name.constData()) - d->type->d->propertyOffset; } else { id = *iter; } @@ -233,29 +271,34 @@ void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val) activate(d->object, id + d->type->d->signalOffset, 0); } +void QmlOpenMetaObject::setCached(bool c) +{ + if (c == d->cacheProperties || !d->type->d->engine) + return; + + d->cacheProperties = c; + + QmlDeclarativeData *qmldata = QmlDeclarativeData::get(d->object, true); + if (d->cacheProperties) { + if (!d->type->d->cache) + d->type->d->cache = QmlPropertyCache::create(d->type->d->engine, this); + qmldata->propertyCache = d->type->d->cache; + d->type->d->cache->addref(); + } else { + if (d->type->d->cache) + d->type->d->cache->release(); + qmldata->propertyCache = 0; + } +} + int QmlOpenMetaObject::createProperty(const char *name, const char *) { if (d->autoCreate) - return doCreateProperty(name); + return d->type->createProperty(name); else return -1; } -int QmlOpenMetaObject::doCreateProperty(const char *name) -{ - int id = d->type->d->mob.propertyCount(); - d->type->d->mob.addSignal("__" + QByteArray::number(id) + "()"); - QMetaPropertyBuilder build = d->type->d->mob.addProperty(name, "QVariant", id); - build.setDynamic(true); - propertyCreated(id, build); - qFree(d->type->d->mem); - d->type->d->mem = d->type->d->mob.toMetaObject(); - *static_cast(this) = *d->type->d->mem; - d->type->d->names.insert(name, id); - - return d->type->d->propertyOffset + id; -} - void QmlOpenMetaObject::propertyRead(int) { } @@ -264,7 +307,7 @@ void QmlOpenMetaObject::propertyWrite(int) { } -void QmlOpenMetaObject::propertyCreated(int id, QMetaPropertyBuilder &) +void QmlOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &) { } diff --git a/src/declarative/util/qmlopenmetaobject_p.h b/src/declarative/util/qmlopenmetaobject_p.h index b33f99b..73e3a98 100644 --- a/src/declarative/util/qmlopenmetaobject_p.h +++ b/src/declarative/util/qmlopenmetaobject_p.h @@ -42,6 +42,7 @@ #ifndef QMLOPENMETAOBJECT_H #define QMLOPENMETAOBJECT_H +#include #include #include @@ -54,13 +55,19 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QmlEngine; +class QMetaPropertyBuilder; class QmlOpenMetaObjectTypePrivate; -class QmlOpenMetaObjectType +class QmlOpenMetaObjectType : public QmlRefCount { public: - QmlOpenMetaObjectType(QmlEngine *engine); + QmlOpenMetaObjectType(const QMetaObject *base, QmlEngine *engine); ~QmlOpenMetaObjectType(); + int createProperty(const QByteArray &name); + +protected: + virtual void propertyCreated(int, QMetaPropertyBuilder &); + private: QmlOpenMetaObjectTypePrivate *d; friend class QmlOpenMetaObject; @@ -68,7 +75,6 @@ private: }; class QmlOpenMetaObjectPrivate; -class QMetaPropertyBuilder; class Q_DECLARATIVE_EXPORT QmlOpenMetaObject : public QAbstractDynamicMetaObject { public: @@ -87,6 +93,13 @@ public: QObject *object() const; virtual QVariant initialValue(int); + + // Be careful - once setCached(true) is called createProperty() is no + // longer automatically called for new properties. + void setCached(bool); + + QmlOpenMetaObjectType *type() const; + protected: virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); virtual int createProperty(const char *, const char *); @@ -96,9 +109,8 @@ protected: virtual void propertyCreated(int, QMetaPropertyBuilder &); private: - int doCreateProperty(const char *); - QmlOpenMetaObjectPrivate *d; + friend class QmlOpenMetaObjectType; }; QT_END_NAMESPACE -- cgit v0.12