From bbe72dadd3ab73a2a3a7dabfb9db3e99b36a272a Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 2 Aug 2011 15:19:06 +1000 Subject: [PATCH] Don't cache model data in VisualDataModel. VisualDataModel doesn't have any way to monitor the lifetime of objects cached other than relying on the source model to emit a changed signal. If the model doesn't do this or a pointer property is referenced after an item has been removed from the model then cache can return a stale pointer. This can be avoided by querying the model directly whenever a property is accessed. Task-number: QTBUG-18036 Change-Id: I7688174c2337cb5c0f77eb7d31a01f4aa958071b Reviewed-on: http://codereview.qt.nokia.com/2647 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- src/declarative/items/qsgvisualitemmodel.cpp | 561 ++++++++++++-------- .../declarative/qsggridview/data/gridview1.qml | 1 + .../declarative/qsggridview/tst_qsggridview.cpp | 2 +- .../declarative/qsglistview/tst_qsglistview.cpp | 2 +- .../declarative/qsgpathview/tst_qsgpathview.cpp | 2 +- .../qsgvisualdatamodel/data/modelproperties.qml | 2 + .../qsgvisualdatamodel/data/modelproperties2.qml | 2 + .../qsgvisualdatamodel/data/objectlist.qml | 2 +- .../qsgvisualdatamodel/data/singlerole1.qml | 2 +- .../qsgvisualdatamodel/data/singlerole2.qml | 2 +- .../qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp | 1 - 11 files changed, 360 insertions(+), 219 deletions(-) diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp index 7e45aeb..09b5ea0 100644 --- a/src/declarative/items/qsgvisualitemmodel.cpp +++ b/src/declarative/items/qsgvisualitemmodel.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -198,20 +199,52 @@ QSGVisualItemModelAttached *QSGVisualItemModel::qmlAttachedProperties(QObject *o //============================================================================ -class VDMDelegateDataType : public QDeclarativeOpenMetaObjectType +class VDMDelegateDataType : public QDeclarativeRefCount { public: - VDMDelegateDataType(const QMetaObject *base, QDeclarativeEngine *engine) : QDeclarativeOpenMetaObjectType(base, engine) {} + VDMDelegateDataType() + : metaObject(0) + , propertyCache(0) + , propertyOffset(0) + , signalOffset(0) + , shared(true) + { + } + + VDMDelegateDataType(const VDMDelegateDataType &type) + : metaObject(0) + , propertyCache(0) + , propertyOffset(type.propertyOffset) + , signalOffset(type.signalOffset) + , shared(false) + , builder(type.metaObject, QMetaObjectBuilder::Properties + | QMetaObjectBuilder::Signals + | QMetaObjectBuilder::SuperClass + | QMetaObjectBuilder::ClassName) + { + } - void propertyCreated(int, QMetaPropertyBuilder &prop) { - prop.setWritable(false); + ~VDMDelegateDataType() + { + if (propertyCache) + propertyCache->release(); + qFree(metaObject); } + + QMetaObject *metaObject; + QDeclarativePropertyCache *propertyCache; + int propertyOffset; + int signalOffset; + bool shared : 1; + QMetaObjectBuilder builder; }; class QSGVisualDataModelParts; class QSGVisualDataModelData; +class QSGVisualDataModelDataMetaObject; class QSGVisualDataModelPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QSGVisualDataModel) public: QSGVisualDataModelPrivate(QDeclarativeContext *); @@ -228,55 +261,30 @@ public: QDeclarativeGuard m_context; QList m_roles; 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)).toUtf8(), m_roles.at(ii)); - } 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(*it, it.key()); - } - if (m_roles.count()) - m_roleNames.insert("hasModelChildren", -1); - } else if (m_listAccessor) { - m_roleNames.insert("modelData", 0); - if (m_listAccessor->type() == QDeclarativeListAccessor::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(prop.name(), 0); - } - } - } - } - } + + void addProperty(int role, int propertyId, const char *propertyName, const char *propertyType, bool isModelData = false); + template void setModelDataType() + { + createModelData = &T::create; + m_delegateDataType->builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + m_delegateDataType->builder.setClassName(T::staticMetaObject.className()); + m_delegateDataType->builder.setSuperClass(&T::staticMetaObject); + m_delegateDataType->propertyOffset = T::staticMetaObject.propertyCount(); + m_delegateDataType->signalOffset = T::staticMetaObject.methodCount(); } + QSGVisualDataModelData *createMetaObject(int index, QSGVisualDataModel *model); - QHash m_roleToPropId; - int m_modelDataPropId; - void createMetaData() { - if (!m_metaDataCreated) { - ensureRoles(); - if (m_roleNames.count()) { - QHash::const_iterator it = m_roleNames.begin(); - while (it != m_roleNames.end()) { - int propId = m_delegateDataType->createProperty(it.key()) - m_delegateDataType->propertyOffset(); - m_roleToPropId.insert(*it, propId); - ++it; - } - // Add modelData property - if (m_roles.count() == 1 && !m_roleNames.contains("modelData")) - m_modelDataPropId = m_delegateDataType->createProperty("modelData") - m_delegateDataType->propertyOffset(); - m_metaDataCreated = true; - } - } + static QSGVisualDataModelData *initializeModelData(int index, QSGVisualDataModel *model) { + return get(model)->createMetaObject(index, model); } + typedef QSGVisualDataModelData *(*CreateModelData)(int index, QSGVisualDataModel *model); + + struct PropertyData { + int role; + bool isModelData : 1; + }; + struct ObjectRef { ObjectRef(QObject *object=0) : obj(object), ref(1) {} QObject *obj; @@ -338,11 +346,12 @@ public: friend class QSGVisualItemParts; VDMDelegateDataType *m_delegateDataType; + CreateModelData createModelData; + friend class QSGVisualDataModelData; - bool m_metaDataCreated : 1; - bool m_metaDataCacheable : 1; bool m_delegateValidated : 1; bool m_completePending : 1; + bool m_objectList : 1; QSGVisualDataModelData *data(QObject *item); @@ -352,164 +361,315 @@ public: QModelIndex m_root; QList watchedRoles; QList watchedRoleIds; -}; - -class QSGVisualDataModelDataMetaObject : public QDeclarativeOpenMetaObject -{ -public: - QSGVisualDataModelDataMetaObject(QObject *parent, QDeclarativeOpenMetaObjectType *type) - : QDeclarativeOpenMetaObject(parent, type) {} - - virtual QVariant initialValue(int); - virtual int createProperty(const char *, const char *); -private: - friend class QSGVisualDataModelData; + QVector m_propertyData; }; class QSGVisualDataModelData : public QObject { -Q_OBJECT + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged) public: QSGVisualDataModelData(int index, QSGVisualDataModel *model); ~QSGVisualDataModelData(); - Q_PROPERTY(int index READ index NOTIFY indexChanged) int index() const; void setIndex(int index); - int propForRole(int) const; - int modelDataPropertyId() const { - QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); - return model->m_modelDataPropId; - } - - void setValue(int, const QVariant &); - bool hasValue(int id) const { - return m_meta->hasValue(id); - } - - void ensureProperties(); - Q_SIGNALS: void indexChanged(); -private: - friend class QSGVisualDataModelDataMetaObject; +public: int m_index; QDeclarativeGuard m_model; - QSGVisualDataModelDataMetaObject *m_meta; }; -int QSGVisualDataModelData::propForRole(int id) const +class QSGVisualDataModelDataMetaObject : public QAbstractDynamicMetaObject { - QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); - QHash::const_iterator it = model->m_roleToPropId.find(id); - if (it != model->m_roleToPropId.end()) - return *it; +public: + QSGVisualDataModelDataMetaObject(QSGVisualDataModelData *data, VDMDelegateDataType *type) + : m_data(data) + , m_type(type) + { + QObjectPrivate *op = QObjectPrivate::get(m_data); + *static_cast(this) = *type->metaObject; + op->metaObject = this; + m_type->addref(); + } - return -1; -} + ~QSGVisualDataModelDataMetaObject() { m_type->release(); } -void QSGVisualDataModelData::setValue(int id, const QVariant &val) -{ - m_meta->setValue(id, val); -} + QSGVisualDataModelData *m_data; + VDMDelegateDataType *m_type; +}; -int QSGVisualDataModelDataMetaObject::createProperty(const char *name, const char *type) +class QSGVDMAbstractItemModelDataMetaObject : public QSGVisualDataModelDataMetaObject { - QSGVisualDataModelData *data = - static_cast(object()); +public: + QSGVDMAbstractItemModelDataMetaObject(QSGVisualDataModelData *object, VDMDelegateDataType *type) + : QSGVisualDataModelDataMetaObject(object, type) {} + + int metaCall(QMetaObject::Call call, int id, void **arguments) + { + if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) { + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_data->m_model); + if (m_data->m_index == -1 || !model->m_abstractItemModel) + return -1; + *static_cast(arguments[0]) = model->m_abstractItemModel->index( + m_data->m_index, 0, model->m_root).data(model->m_propertyData.at(id - m_type->propertyOffset).role); + return -1; + } else { + return m_data->qt_metacall(call, id, arguments); + } + } +}; - if (!data->m_model) - return -1; +class QSGVDMAbstractItemModelData : public QSGVisualDataModelData +{ + Q_OBJECT + Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT) +public: + bool hasModelChildren() const + { + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); + return model->m_abstractItemModel->hasChildren(model->m_abstractItemModel->index(m_index, 0, model->m_root)); + } - QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model); - if (data->m_index < 0 || data->m_index >= model->modelCount()) - return -1; + static QSGVisualDataModelData *create(int index, QSGVisualDataModel *model) { + return new QSGVDMAbstractItemModelData(index, model); } +private: + QSGVDMAbstractItemModelData(int index, QSGVisualDataModel *model) + : QSGVisualDataModelData(index, model) + { + new QSGVDMAbstractItemModelDataMetaObject( + this, QSGVisualDataModelPrivate::get(m_model)->m_delegateDataType); + } +}; - if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { - if (model->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) { - model->ensureRoles(); - if (qstrcmp(name,"modelData") == 0) - return QDeclarativeOpenMetaObject::createProperty(name, type); +class QSGVDMListModelInterfaceDataMetaObject : public QSGVisualDataModelDataMetaObject +{ +public: + QSGVDMListModelInterfaceDataMetaObject(QSGVisualDataModelData *object, VDMDelegateDataType *type) + : QSGVisualDataModelDataMetaObject(object, type) {} + + int metaCall(QMetaObject::Call call, int id, void **arguments) + { + if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) { + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_data->m_model); + if (m_data->m_index == -1 || !model->m_listModelInterface) + return -1; + *static_cast(arguments[0]) = model->m_listModelInterface->data( + m_data->m_index, model->m_propertyData.at(id - m_type->propertyOffset).role); + return -1; + } else { + return m_data->qt_metacall(call, id, arguments); } } - return -1; -} +}; -QVariant QSGVisualDataModelDataMetaObject::initialValue(int propId) +class QSGVDMListModelInterfaceData : public QSGVisualDataModelData { - QSGVisualDataModelData *data = - static_cast(object()); +public: + static QSGVisualDataModelData *create(int index, QSGVisualDataModel *model) { + return new QSGVDMListModelInterfaceData(index, model); } +private: + QSGVDMListModelInterfaceData(int index, QSGVisualDataModel *model) + : QSGVisualDataModelData(index, model) + { + new QSGVDMListModelInterfaceDataMetaObject( + this, QSGVisualDataModelPrivate::get(m_model)->m_delegateDataType); + } +}; - Q_ASSERT(data->m_model); - QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(data->m_model); +class QSGVDMListAccessorData : public QSGVisualDataModelData +{ + Q_OBJECT + Q_PROPERTY(QVariant modelData READ modelData CONSTANT) +public: + QVariant modelData() const { + return QSGVisualDataModelPrivate::get(m_model)->m_listAccessor->at(m_index); } - QByteArray propName = name(propId); - if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { - if (propName == "modelData") { - if (model->m_listAccessor->type() == QDeclarativeListAccessor::Instance) { - QObject *object = model->m_listAccessor->at(0).value(); - return object->metaObject()->property(1).read(object); // the first property after objectName - } - return model->m_listAccessor->at(data->m_index); + static QSGVisualDataModelData *create(int index, QSGVisualDataModel *model) { + return new QSGVDMListAccessorData(index, model); } +private: + QSGVDMListAccessorData(int index, QSGVisualDataModel *model) + : QSGVisualDataModelData(index, model) + { + } +}; + +class QSGVDMObjectDataMetaObject : public QSGVisualDataModelDataMetaObject +{ +public: + QSGVDMObjectDataMetaObject(QSGVisualDataModelData *data, VDMDelegateDataType *type) + : QSGVisualDataModelDataMetaObject(data, type) + , m_object(QSGVisualDataModelPrivate::get(data->m_model)->m_listAccessor->at(data->m_index).value()) + {} + + int metaCall(QMetaObject::Call call, int id, void **arguments) + { + if (id >= m_type->propertyOffset + && (call == QMetaObject::ReadProperty + || call == QMetaObject::WriteProperty + || call == QMetaObject::ResetProperty)) { + if (m_object) + QMetaObject::metacall(m_object, call, id - m_type->propertyOffset + 1, arguments); + return -1; + } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) { + QMetaObject::activate(m_data, this, id, 0); + return -1; } else { - // return any property of a single object instance. - QObject *object = model->m_listAccessor->at(data->m_index).value(); - return object->property(propName); + return m_data->qt_metacall(call, id, arguments); } - } else if (model->m_listModelInterface) { - model->ensureRoles(); - QHash::const_iterator it = model->m_roleNames.find(propName); - if (it != model->m_roleNames.end()) { - QVariant value = model->m_listModelInterface->data(data->m_index, *it); - return value; - } else if (model->m_roles.count() == 1 && propName == "modelData") { - //for compatibility with other lists, assign modelData if there is only a single role - QVariant value = model->m_listModelInterface->data(data->m_index, model->m_roles.first()); - return value; + } + + int createProperty(const char *name, const char *) + { + if (!m_object) + return -1; + const QMetaObject *metaObject = m_object->metaObject(); + + const int previousPropertyCount = propertyCount() - propertyOffset(); + int propertyIndex = metaObject->indexOfProperty(name); + if (propertyIndex == -1) + return -1; + if (previousPropertyCount + 1 == metaObject->propertyCount()) + return propertyIndex + m_type->propertyOffset - 1; + + if (m_type->shared) { + VDMDelegateDataType *type = m_type; + m_type = new VDMDelegateDataType(*m_type); + type->release(); } - } else if (model->m_abstractItemModel) { - model->ensureRoles(); - QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0, model->m_root); - if (propName == "hasModelChildren") { - return model->m_abstractItemModel->hasChildren(index); - } else { - QHash::const_iterator it = model->m_roleNames.find(propName); - if (it != model->m_roleNames.end()) { - return model->m_abstractItemModel->data(index, *it); - } else if (model->m_roles.count() == 1 && propName == "modelData") { - //for compatibility with other lists, assign modelData if there is only a single role - return model->m_abstractItemModel->data(index, model->m_roles.first()); + + const int previousMethodCount = methodCount(); + int notifierId = previousMethodCount; + for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - 1; ++propertyId) { + QMetaProperty property = metaObject->property(propertyId + 1); + QMetaPropertyBuilder propertyBuilder; + if (property.hasNotifySignal()) { + m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()"); + propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId); + ++notifierId; + } else { + propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName()); + } + propertyBuilder.setWritable(property.isWritable()); + propertyBuilder.setResettable(property.isResettable()); + propertyBuilder.setConstant(property.isConstant()); + } + + if (m_type->metaObject) + qFree(m_type->metaObject); + m_type->metaObject = m_type->builder.toMetaObject(); + *static_cast(this) = *m_type->metaObject; + + notifierId = previousMethodCount; + for (int i = previousPropertyCount; i < metaObject->propertyCount(); ++i) { + QMetaProperty property = metaObject->property(i); + if (property.hasNotifySignal()) { + QDeclarativePropertyPrivate::connect( + m_object, property.notifySignalIndex(), m_data, notifierId); + ++notifierId; } } + return propertyIndex + m_type->propertyOffset - 1; } - Q_ASSERT(!"Can never be reached"); - return QVariant(); + + QDeclarativeGuard m_object; +}; + +class QSGVDMObjectData : public QSGVisualDataModelData +{ + Q_OBJECT + Q_PROPERTY(QObject *modelData READ modelData CONSTANT) +public: + QObject *modelData() const { return m_metaObject->m_object; } + + static QSGVisualDataModelData *create(int index, QSGVisualDataModel *model) { + return new QSGVDMObjectData(index, model); } + +private: + QSGVDMObjectData(int index, QSGVisualDataModel *model) + : QSGVisualDataModelData(index, model) + , m_metaObject(new QSGVDMObjectDataMetaObject(this, QSGVisualDataModelPrivate::get(m_model)->m_delegateDataType)) + { + } + + QSGVDMObjectDataMetaObject *m_metaObject; +}; + +void QSGVisualDataModelPrivate::addProperty( + int role, int propertyId, const char *propertyName, const char *propertyType, bool isModelData) +{ + PropertyData propertyData; + propertyData.role = role; + propertyData.isModelData = isModelData; + m_delegateDataType->builder.addSignal("__" + QByteArray::number(propertyId) + "()"); + QMetaPropertyBuilder property = m_delegateDataType->builder.addProperty( + propertyName, propertyType, propertyId); + property.setWritable(false); + + m_propertyData.append(propertyData); } -QSGVisualDataModelData::QSGVisualDataModelData(int index, - QSGVisualDataModel *model) -: m_index(index), m_model(model), -m_meta(new QSGVisualDataModelDataMetaObject(this, QSGVisualDataModelPrivate::get(model)->m_delegateDataType)) +QSGVisualDataModelData *QSGVisualDataModelPrivate::createMetaObject(int index, QSGVisualDataModel *model) { - ensureProperties(); + Q_ASSERT(!m_delegateDataType); + + m_objectList = false; + m_propertyData.clear(); + if (m_listAccessor + && m_listAccessor->type() != QDeclarativeListAccessor::ListProperty + && m_listAccessor->type() != QDeclarativeListAccessor::Instance) { + createModelData = &QSGVDMListAccessorData::create; + return QSGVDMListAccessorData::create(index, model); + } + + m_delegateDataType = new VDMDelegateDataType; + if (m_listModelInterface) { + setModelDataType(); + QList roles = m_listModelInterface->roles(); + for (int propertyId = 0; propertyId < roles.count(); ++propertyId) { + const int role = roles.at(propertyId); + const QByteArray propertyName = m_listModelInterface->toString(role).toUtf8(); + addProperty(role, propertyId, propertyName, "QVariant"); + m_roleNames.insert(propertyName, role); + } + if (m_propertyData.count() == 1) + addProperty(roles.first(), 1, "modelData", "QVariant", true); + } else if (m_abstractItemModel) { + setModelDataType(); + QHash roleNames = m_abstractItemModel->roleNames(); + for (QHash::const_iterator it = roleNames.begin(); it != roleNames.end(); ++it) { + addProperty(it.key(), m_propertyData.count(), it.value(), "QVariant"); + m_roleNames.insert(it.value(), it.key()); + } + if (m_propertyData.count() == 1) + addProperty(roleNames.begin().key(), 1, "modelData", "QVariant", true); + } else if (m_listAccessor) { + setModelDataType(); + m_objectList = true; + } else { + Q_ASSERT(!"No model set on VisualDataModel"); + return 0; + } + m_delegateDataType->metaObject = m_delegateDataType->builder.toMetaObject(); + if (!m_objectList) { + m_delegateDataType->propertyCache = new QDeclarativePropertyCache( + m_context ? m_context->engine() : qmlEngine(q_func()), m_delegateDataType->metaObject); + } + return createModelData(index, model); } -QSGVisualDataModelData::~QSGVisualDataModelData() +QSGVisualDataModelData::QSGVisualDataModelData(int index, QSGVisualDataModel *model) + : m_index(index) + , m_model(model) { } -void QSGVisualDataModelData::ensureProperties() +QSGVisualDataModelData::~QSGVisualDataModelData() { - QSGVisualDataModelPrivate *modelPriv = QSGVisualDataModelPrivate::get(m_model); - if (modelPriv->m_metaDataCacheable) { - if (!modelPriv->m_metaDataCreated) - modelPriv->createMetaData(); - if (modelPriv->m_metaDataCreated) - m_meta->setCached(true); - } } int QSGVisualDataModelData::index() const @@ -571,8 +731,8 @@ QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent) QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt) : m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0) -, m_context(ctxt), m_modelDataPropId(-1), m_parts(0), m_delegateDataType(0), m_metaDataCreated(false) -, m_metaDataCacheable(false), m_delegateValidated(false), m_completePending(false), m_listAccessor(0) +, m_context(ctxt), m_parts(0), m_delegateDataType(0), createModelData(&initializeModelData) +, m_delegateValidated(false), m_completePending(false), m_objectList(false), m_listAccessor(0) { } @@ -658,9 +818,8 @@ void QSGVisualDataModel::setModel(const QVariant &model) d->m_roleNames.clear(); if (d->m_delegateDataType) d->m_delegateDataType->release(); - d->m_metaDataCreated = 0; - d->m_metaDataCacheable = false; - d->m_delegateDataType = new VDMDelegateDataType(&QSGVisualDataModelData::staticMetaObject, d->m_context?d->m_context->engine():qmlEngine(this)); + d->m_delegateDataType = 0; + d->createModelData = &QSGVisualDataModelPrivate::initializeModelData; QObject *object = qvariant_cast(model); if (object && (d->m_listModelInterface = qobject_cast(object))) { @@ -672,7 +831,6 @@ void QSGVisualDataModel::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; @@ -687,7 +845,6 @@ void QSGVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); - d->m_metaDataCacheable = true; if (d->m_abstractItemModel->canFetchMore(d->m_root)) d->m_abstractItemModel->fetchMore(d->m_root); return; @@ -710,7 +867,6 @@ void QSGVisualDataModel::setModel(const QVariant &model) d->m_listAccessor = new QDeclarativeListAccessor; d->m_listAccessor->setList(model, d->m_context?d->m_context->engine():qmlEngine(this)); if (d->m_listAccessor->type() != QDeclarativeListAccessor::ListProperty) - d->m_metaDataCacheable = true; if (d->m_delegate && d->modelCount()) { emit itemsInserted(0, d->modelCount()); emit countChanged(); @@ -881,12 +1037,11 @@ QSGItem *QSGVisualDataModel::item(int index, const QByteArray &viewId, bool comp QDeclarativeContext *ccontext = d->m_context; if (!ccontext) ccontext = qmlContext(this); QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); - QSGVisualDataModelData *data = new QSGVisualDataModelData(index, this); - if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor - && d->m_listAccessor->type() == QDeclarativeListAccessor::ListProperty) { - ctxt->setContextObject(d->m_listAccessor->at(index).value()); - ctxt = new QDeclarativeContext(ctxt, ctxt); + if (d->m_objectList) { + ctxt->setContextObject(d->m_listAccessor->at(index).value()); + ctxt = new QDeclarativeContext(ctxt); } + QSGVisualDataModelData *data = d->createModelData(index, this); ctxt->setContextProperty(QLatin1String("model"), data); ctxt->setContextObject(data); d->m_completePending = false; @@ -975,7 +1130,7 @@ QString QSGVisualDataModel::stringValue(int index, const QString &name) if (QObject *nobj = d->m_cache.item(index)) data = d->data(nobj); if (!data) { - data = new QSGVisualDataModelData(index, this); + data = d->createModelData(index, this); tempData = true; } @@ -1031,6 +1186,21 @@ void QSGVisualDataModel::_q_itemsChanged(int index, int count, } } + QVector signalIndexes; + for (int i = 0; i < roles.count(); ++i) { + const int role = roles.at(i); + if (!changed && d->watchedRoleIds.contains(role)) + changed = true; + for (int propertyId = 0; propertyId < d->m_propertyData.count(); ++propertyId) { + if (d->m_propertyData.at(propertyId).role == role) + signalIndexes.append(propertyId + d->m_delegateDataType->signalOffset); + } + } + if (roles.isEmpty()) { + for (int propertyId = 0; propertyId < d->m_propertyData.count(); ++propertyId) + signalIndexes.append(propertyId + d->m_delegateDataType->signalOffset); + } + for (QHash::ConstIterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ++iter) { const int idx = iter.key(); @@ -1038,41 +1208,8 @@ void QSGVisualDataModel::_q_itemsChanged(int index, int count, if (idx >= index && idx < index+count) { QSGVisualDataModelPrivate::ObjectRef objRef = *iter; QSGVisualDataModelData *data = d->data(objRef.obj); - for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) { - int role = roles.at(roleIdx); - if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role)) - changed = true; - int propId = data->propForRole(role); - if (propId != -1) { - if (data->hasValue(propId)) { - if (d->m_listModelInterface) { - data->setValue(propId, d->m_listModelInterface->data(idx, role)); - } else if (d->m_abstractItemModel) { - QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); - data->setValue(propId, d->m_abstractItemModel->data(index, role)); - } - } - } else { - QString roleName; - if (d->m_listModelInterface) - roleName = d->m_listModelInterface->toString(role); - else if (d->m_abstractItemModel) - roleName = QString::fromUtf8(d->m_abstractItemModel->roleNames().value(role)); - qmlInfo(this) << "Changing role not present in item: " << roleName; - } - } - if (d->m_modelDataPropId != -1) { - // Handle the modelData role we add if there is just one role. - if (data->hasValue(d->m_modelDataPropId)) { - int role = d->m_roles.at(0); - if (d->m_listModelInterface) { - data->setValue(d->m_modelDataPropId, d->m_listModelInterface->data(idx, role)); - } else if (d->m_abstractItemModel) { - QModelIndex index = d->m_abstractItemModel->index(idx, 0, d->m_root); - data->setValue(d->m_modelDataPropId, d->m_abstractItemModel->data(index, role)); - } - } - } + for (int i = 0; i < signalIndexes.count(); ++i) + QMetaObject::activate(data, signalIndexes.at(i), 0); } } if (changed) diff --git a/tests/auto/declarative/qsggridview/data/gridview1.qml b/tests/auto/declarative/qsggridview/data/gridview1.qml index 0f148ed..e6a3923 100644 --- a/tests/auto/declarative/qsggridview/data/gridview1.qml +++ b/tests/auto/declarative/qsggridview/data/gridview1.qml @@ -20,6 +20,7 @@ Rectangle { width: 80 height: 60 border.color: "blue" + property string name: model.name Text { text: index } diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp index 11d90ec..c478f0d 100644 --- a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp +++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp @@ -1344,7 +1344,7 @@ void tst_QSGGridView::modelChanges() QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild("alternateModel"); QTRY_VERIFY(alternateModel); - QVariant modelVariant = QVariant::fromValue(alternateModel); + QVariant modelVariant = QVariant::fromValue(alternateModel); QSignalSpy modelSpy(gridView, SIGNAL(modelChanged())); gridView->setModel(modelVariant); diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp index 6f19692..59847d3 100644 --- a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp +++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp @@ -2008,7 +2008,7 @@ void tst_QSGListView::modelChanges() QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild("alternateModel"); QTRY_VERIFY(alternateModel); - QVariant modelVariant = QVariant::fromValue(alternateModel); + QVariant modelVariant = QVariant::fromValue(alternateModel); QSignalSpy modelSpy(listView, SIGNAL(modelChanged())); listView->setModel(modelVariant); diff --git a/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp b/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp index 00202f7..96a591f 100644 --- a/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp +++ b/tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp @@ -835,7 +835,7 @@ void tst_QSGPathView::modelChanges() QDeclarativeListModel *alternateModel = canvas->rootObject()->findChild("alternateModel"); QVERIFY(alternateModel); - QVariant modelVariant = QVariant::fromValue(alternateModel); + QVariant modelVariant = QVariant::fromValue(alternateModel); QSignalSpy modelSpy(pathView, SIGNAL(modelChanged())); pathView->setModel(modelVariant); diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml index 6d86cde..73b766f 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml @@ -6,6 +6,8 @@ ListView { model: myModel delegate: Item { objectName: "delegate" + width: 100 + height: 2 property variant test1: name property variant test2: model.name property variant test3: modelData diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml index 6a92431..ea5c240 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml @@ -15,5 +15,7 @@ ListView { property variant test7: index property variant test8: model.index property variant test9: model.modelData.display + width: 100 + height: 2 } } diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml b/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml index 9086e5a..b3952a8 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml @@ -10,7 +10,7 @@ ListView { height: 25 width: 100 color: model.modelData.color - Text { objectName: "name"; text: name } + Text { objectName: "name"; text: name; function getText() { return name } } Text { objectName: "section"; text: parent.ListView.section } } } diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml index d5b0fcf..c471893 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml @@ -5,6 +5,6 @@ ListView { height: 100 model: myModel delegate: Component { - Text { objectName: "name"; text: name } + Text { objectName: "name"; text: name; function getText() { return name; } } } } diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml index c6d3413..ab17989 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml @@ -5,6 +5,6 @@ ListView { height: 100 model: myModel delegate: Component { - Text { objectName: "name"; text: modelData } + Text { objectName: "name"; text: modelData; function getText() { return modelData } } } } diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp index e56fcb0..7470153 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp +++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp @@ -460,7 +460,6 @@ void tst_qsgvisualdatamodel::modelProperties() QSGItem *delegate = findItem(contentItem, "delegate", 1); QVERIFY(delegate); QCOMPARE(delegate->property("test1").toString(),QString("Item 2")); - QEXPECT_FAIL("", "QTBUG-13576", Continue); QCOMPARE(delegate->property("test2").toString(),QString("Item 2")); QVERIFY(qobject_cast(delegate->property("test3").value()) != 0); QVERIFY(qobject_cast(delegate->property("test4").value()) != 0); -- 1.7.2.5