aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2011-08-02 15:19:06 +1000
committerQt by Nokia <qt-info@nokia.com>2011-08-05 04:56:52 +0200
commitbbe72dadd3ab73a2a3a7dabfb9db3e99b36a272a (patch)
tree4df5c242fd4fbb23056c30e14717a01beed91eee
parentaa54e27adeff3c7e6f59e2d68e9f006e60e542dc (diff)
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 <qt_sanity_bot@ovi.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
-rw-r--r--src/declarative/items/qsgvisualitemmodel.cpp557
-rw-r--r--tests/auto/declarative/qsggridview/data/gridview1.qml1
-rw-r--r--tests/auto/declarative/qsggridview/tst_qsggridview.cpp2
-rw-r--r--tests/auto/declarative/qsglistview/tst_qsglistview.cpp2
-rw-r--r--tests/auto/declarative/qsgpathview/tst_qsgpathview.cpp2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/modelproperties.qml2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/modelproperties2.qml2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/objectlist.qml2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/singlerole1.qml2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/singlerole2.qml2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp1
11 files changed, 358 insertions, 217 deletions
diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp
index 7e45aeb629..09b5ea0d94 100644
--- a/src/declarative/items/qsgvisualitemmodel.cpp
+++ b/src/declarative/items/qsgvisualitemmodel.cpp
@@ -57,6 +57,7 @@
#include <private/qdeclarativeglobal_p.h>
#include <private/qlistmodelinterface_p.h>
#include <private/qmetaobjectbuilder_p.h>
+#include <private/qdeclarativeproperty_p.h>
#include <private/qobject_p.h>
#include <QtCore/qhash.h>
@@ -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<QDeclarativeContext> m_context;
QList<int> m_roles;
QHash<QByteArray,int> 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<int,QByteArray>::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<QObject*>()) {
- 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 <typename T> 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<int,int> m_roleToPropId;
- int m_modelDataPropId;
- void createMetaData() {
- if (!m_metaDataCreated) {
- ensureRoles();
- if (m_roleNames.count()) {
- QHash<QByteArray, int>::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<QByteArray> watchedRoles;
QList<int> 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<PropertyData> 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<QSGVisualDataModel> m_model;
- QSGVisualDataModelDataMetaObject *m_meta;
};
-int QSGVisualDataModelData::propForRole(int id) const
+class QSGVisualDataModelDataMetaObject : public QAbstractDynamicMetaObject
{
- QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
- QHash<int,int>::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<QMetaObject *>(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<QSGVisualDataModelData *>(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<QVariant *>(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<QVariant *>(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<QSGVisualDataModelData *>(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<QObject*>();
- 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<QObject *>())
+ {}
+
+ 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<QObject*>();
- return object->property(propName);
+ return m_data->qt_metacall(call, id, arguments);
}
- } else if (model->m_listModelInterface) {
- model->ensureRoles();
- QHash<QByteArray,int>::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<QByteArray,int>::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<QMetaObject *>(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<QObject> 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<QSGVDMListModelInterfaceData>();
+ QList<int> 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<QSGVDMAbstractItemModelData>();
+ QHash<int, QByteArray> roleNames = m_abstractItemModel->roleNames();
+ for (QHash<int, QByteArray>::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<QSGVDMObjectData>();
+ 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<QObject *>(model);
if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(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<QObject*>());
- ctxt = new QDeclarativeContext(ctxt, ctxt);
+ if (d->m_objectList) {
+ ctxt->setContextObject(d->m_listAccessor->at(index).value<QObject *>());
+ 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<int> 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<int,QSGVisualDataModelPrivate::ObjectRef>::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 0f148ed387..e6a3923532 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 11d90eca6e..c478f0dab3 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<QDeclarativeListModel*>("alternateModel");
QTRY_VERIFY(alternateModel);
- QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QVariant modelVariant = QVariant::fromValue<QObject *>(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 6f19692ad0..59847d37f5 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<QDeclarativeListModel*>("alternateModel");
QTRY_VERIFY(alternateModel);
- QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QVariant modelVariant = QVariant::fromValue<QObject *>(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 00202f7436..96a591f511 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<QDeclarativeListModel*>("alternateModel");
QVERIFY(alternateModel);
- QVariant modelVariant = QVariant::fromValue(alternateModel);
+ QVariant modelVariant = QVariant::fromValue<QObject *>(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 6d86cdea2e..73b766f1af 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 6a92431cdf..ea5c240b29 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 9086e5ab57..b3952a8a4d 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 d5b0fcf09b..c471893e1d 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 c6d3413dfd..ab1798999d 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 e56fcb062e..7470153933 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<QSGItem>(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<DataObject*>(delegate->property("test3").value<QObject*>()) != 0);
QVERIFY(qobject_cast<DataObject*>(delegate->property("test4").value<QObject*>()) != 0);