From: Andrew den Exter Date: Tue, 30 Aug 2011 05:00:30 +0000 (+1000) Subject: Refactor QSGVisualDataModel. X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=ce7b66871ce342b4cc62969ec0a3a9d90cee49e9;p=konrad%2Fqtdeclarative.git Refactor QSGVisualDataModel. Split the wrapper for Package models out into its own visual model class, add a QSGVisualAdaptorModel class which encapsulates the creation and maintenance of delegate context data, and move QSGVisualDataModel to its own source files. Task-number: QTBUG-20107 Change-Id: Icdea2756a119c327ec2c748be893daf622bc1356 Reviewed-on: http://codereview.qt-project.org/4033 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri index 9880dd8..0433074 100644 --- a/src/declarative/items/items.pri +++ b/src/declarative/items/items.pri @@ -37,6 +37,8 @@ HEADERS += \ $$PWD/qsgflickable_p.h \ $$PWD/qsgflickable_p_p.h \ $$PWD/qsglistview_p.h \ + $$PWD/qsgvisualadaptormodel_p.h \ + $$PWD/qsgvisualdatamodel_p.h \ $$PWD/qsgvisualitemmodel_p.h \ $$PWD/qsgrepeater_p.h \ $$PWD/qsgrepeater_p_p.h \ @@ -89,6 +91,8 @@ SOURCES += \ $$PWD/qsgpincharea.cpp \ $$PWD/qsgflickable.cpp \ $$PWD/qsglistview.cpp \ + $$PWD/qsgvisualadaptormodel.cpp \ + $$PWD/qsgvisualdatamodel.cpp \ $$PWD/qsgvisualitemmodel.cpp \ $$PWD/qsgrepeater.cpp \ $$PWD/qsggridview.cpp \ diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp index 2ad7e59..41823c1 100644 --- a/src/declarative/items/qsgitemsmodule.cpp +++ b/src/declarative/items/qsgitemsmodule.cpp @@ -58,6 +58,7 @@ #include "qsgflickable_p_p.h" #include "qsglistview_p.h" #include "qsgvisualitemmodel_p.h" +#include "qsgvisualdatamodel_p.h" #include "qsggridview_p.h" #include "qsgpathview_p.h" #include diff --git a/src/declarative/items/qsgitemview_p_p.h b/src/declarative/items/qsgitemview_p_p.h index 2164dd6..afa50af 100644 --- a/src/declarative/items/qsgitemview_p_p.h +++ b/src/declarative/items/qsgitemview_p_p.h @@ -44,7 +44,7 @@ #include "qsgitemview_p.h" #include "qsgflickable_p_p.h" -#include "qsgvisualitemmodel_p.h" +#include "qsgvisualdatamodel_p.h" #include diff --git a/src/declarative/items/qsgpathview_p_p.h b/src/declarative/items/qsgpathview_p_p.h index 30bb74a..520de42 100644 --- a/src/declarative/items/qsgpathview_p_p.h +++ b/src/declarative/items/qsgpathview_p_p.h @@ -56,7 +56,7 @@ #include "qsgpathview_p.h" #include "qsgitem_p.h" -#include "qsgvisualitemmodel_p.h" +#include "qsgvisualdatamodel_p.h" #include #include diff --git a/src/declarative/items/qsgrepeater.cpp b/src/declarative/items/qsgrepeater.cpp index bdb3a3d..4e2fa63 100644 --- a/src/declarative/items/qsgrepeater.cpp +++ b/src/declarative/items/qsgrepeater.cpp @@ -41,7 +41,7 @@ #include "qsgrepeater_p.h" #include "qsgrepeater_p_p.h" -#include "qsgvisualitemmodel_p.h" +#include "qsgvisualdatamodel_p.h" #include #include diff --git a/src/declarative/items/qsgvisualadaptormodel.cpp b/src/declarative/items/qsgvisualadaptormodel.cpp new file mode 100644 index 0000000..3eb6214 --- /dev/null +++ b/src/declarative/items/qsgvisualadaptormodel.cpp @@ -0,0 +1,889 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgvisualadaptormodel_p.h" +#include "qsgitem.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +Q_DECLARE_METATYPE(QModelIndex) + +class VDMDelegateDataType : public QDeclarativeRefCount +{ +public: + 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) + { + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + } + + ~VDMDelegateDataType() + { + if (propertyCache) + propertyCache->release(); + qFree(metaObject); + } + + QMetaObject *metaObject; + QDeclarativePropertyCache *propertyCache; + int propertyOffset; + int signalOffset; + bool shared : 1; + QMetaObjectBuilder builder; +}; + +class QSGVisualAdaptorModelData : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged) +public: + QSGVisualAdaptorModelData(int index, QSGVisualAdaptorModel *model); + ~QSGVisualAdaptorModelData(); + + int index() const; + void setIndex(int index); + +Q_SIGNALS: + void indexChanged(); + +public: + int m_index; + QDeclarativeGuard m_model; + QIntrusiveListNode m_cacheNode; +}; + +typedef QIntrusiveList QSGVisualAdaptorModelDataCache; + +class QSGVisualAdaptorModelDataMetaObject; +class QSGVisualAdaptorModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSGVisualAdaptorModel) +public: + QSGVisualAdaptorModelPrivate() + : m_engine(0) + , m_listAccessor(0) + , m_delegateDataType(0) + , createModelData(&initializeModelData) + , m_ref(0) + , m_count(0) + , m_objectList(false) + { + } + + + static QSGVisualAdaptorModelPrivate *get(QSGVisualAdaptorModel *m) { + return static_cast(QObjectPrivate::get(m)); + } + + 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(); + } + QSGVisualAdaptorModelData *createMetaObject(int index, QSGVisualAdaptorModel *model); + + static QSGVisualAdaptorModelData *initializeModelData(int index, QSGVisualAdaptorModel *model) { + return get(model)->createMetaObject(index, model); + } + + typedef QSGVisualAdaptorModelData *(*CreateModelData)(int index, QSGVisualAdaptorModel *model); + + struct PropertyData { + int role; + bool isModelData : 1; + }; + + int modelCount() const { + if (m_listModelInterface) + return m_listModelInterface->count(); + if (m_abstractItemModel) + return m_abstractItemModel->rowCount(m_root); + if (m_listAccessor) + return m_listAccessor->count(); + return 0; + } + + QDeclarativeGuard m_engine; + QDeclarativeGuard m_listModelInterface; + QDeclarativeGuard m_abstractItemModel; + QDeclarativeListAccessor *m_listAccessor; + VDMDelegateDataType *m_delegateDataType; + CreateModelData createModelData; + + int m_ref; + int m_count; + QSGVisualAdaptorModel::Flags m_flags; + bool m_objectList : 1; + + QVariant m_modelVariant; + QModelIndex m_root; + + QList m_roles; + QList watchedRoleIds; + QList watchedRoles; + QHash m_roleNames; + QVector m_propertyData; + QSGVisualAdaptorModelDataCache m_cache; +}; + +class QSGVisualAdaptorModelDataMetaObject : public QAbstractDynamicMetaObject +{ +public: + QSGVisualAdaptorModelDataMetaObject(QSGVisualAdaptorModelData *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(); + } + + ~QSGVisualAdaptorModelDataMetaObject() { m_type->release(); } + + QSGVisualAdaptorModelData *m_data; + VDMDelegateDataType *m_type; +}; + +class QSGVDMAbstractItemModelDataMetaObject : public QSGVisualAdaptorModelDataMetaObject +{ +public: + QSGVDMAbstractItemModelDataMetaObject(QSGVisualAdaptorModelData *object, VDMDelegateDataType *type) + : QSGVisualAdaptorModelDataMetaObject(object, type) {} + + int metaCall(QMetaObject::Call call, int id, void **arguments) + { + if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) { + QSGVisualAdaptorModelPrivate *model = QSGVisualAdaptorModelPrivate::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); + } + } +}; + +class QSGVDMAbstractItemModelData : public QSGVisualAdaptorModelData +{ + Q_OBJECT + Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT) +public: + bool hasModelChildren() const + { + QSGVisualAdaptorModelPrivate *model = QSGVisualAdaptorModelPrivate::get(m_model); + return model->m_abstractItemModel->hasChildren(model->m_abstractItemModel->index(m_index, 0, model->m_root)); + } + + static QSGVisualAdaptorModelData *create(int index, QSGVisualAdaptorModel *model) { + return new QSGVDMAbstractItemModelData(index, model); } +private: + QSGVDMAbstractItemModelData(int index, QSGVisualAdaptorModel *model) + : QSGVisualAdaptorModelData(index, model) + { + new QSGVDMAbstractItemModelDataMetaObject( + this, QSGVisualAdaptorModelPrivate::get(m_model)->m_delegateDataType); + } +}; + +class QSGVDMListModelInterfaceDataMetaObject : public QSGVisualAdaptorModelDataMetaObject +{ +public: + QSGVDMListModelInterfaceDataMetaObject(QSGVisualAdaptorModelData *object, VDMDelegateDataType *type) + : QSGVisualAdaptorModelDataMetaObject(object, type) {} + + int metaCall(QMetaObject::Call call, int id, void **arguments) + { + if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) { + QSGVisualAdaptorModelPrivate *model = QSGVisualAdaptorModelPrivate::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); + } + } +}; + +class QSGVDMListModelInterfaceData : public QSGVisualAdaptorModelData +{ +public: + static QSGVisualAdaptorModelData *create(int index, QSGVisualAdaptorModel *model) { + return new QSGVDMListModelInterfaceData(index, model); } +private: + QSGVDMListModelInterfaceData(int index, QSGVisualAdaptorModel *model) + : QSGVisualAdaptorModelData(index, model) + { + new QSGVDMListModelInterfaceDataMetaObject( + this, QSGVisualAdaptorModelPrivate::get(m_model)->m_delegateDataType); + } +}; + +class QSGVDMListAccessorData : public QSGVisualAdaptorModelData +{ + Q_OBJECT + Q_PROPERTY(QVariant modelData READ modelData CONSTANT) +public: + QVariant modelData() const { + return QSGVisualAdaptorModelPrivate::get(m_model)->m_listAccessor->at(m_index); } + + static QSGVisualAdaptorModelData *create(int index, QSGVisualAdaptorModel *model) { + return new QSGVDMListAccessorData(index, model); } +private: + QSGVDMListAccessorData(int index, QSGVisualAdaptorModel *model) + : QSGVisualAdaptorModelData(index, model) + { + } +}; + +class QSGVDMObjectDataMetaObject : public QSGVisualAdaptorModelDataMetaObject +{ +public: + QSGVDMObjectDataMetaObject(QSGVisualAdaptorModelData *data, VDMDelegateDataType *type) + : QSGVisualAdaptorModelDataMetaObject(data, type) + , m_object(QSGVisualAdaptorModelPrivate::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 m_data->qt_metacall(call, id, arguments); + } + } + + 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(); + } + + 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; + } + + QDeclarativeGuard m_object; +}; + +class QSGVDMObjectData : public QSGVisualAdaptorModelData, public QSGVisualAdaptorModelProxyInterface +{ + Q_OBJECT + Q_PROPERTY(QObject *modelData READ modelData CONSTANT) + Q_INTERFACES(QSGVisualAdaptorModelProxyInterface) +public: + QObject *modelData() const { return m_metaObject->m_object; } + QObject *proxiedObject() { return m_metaObject->m_object; } + + static QSGVisualAdaptorModelData *create(int index, QSGVisualAdaptorModel *model) { + return new QSGVDMObjectData(index, model); } + +private: + QSGVDMObjectData(int index, QSGVisualAdaptorModel *model) + : QSGVisualAdaptorModelData(index, model) + , m_metaObject(new QSGVDMObjectDataMetaObject(this, QSGVisualAdaptorModelPrivate::get(m_model)->m_delegateDataType)) + { + } + + QSGVDMObjectDataMetaObject *m_metaObject; +}; + +void QSGVisualAdaptorModelPrivate::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); +} + +QSGVisualAdaptorModelData *QSGVisualAdaptorModelPrivate::createMetaObject(int index, QSGVisualAdaptorModel *model) +{ + 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; + m_flags = QSGVisualAdaptorModel::MetaObjectCacheable; + 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); + m_flags = QSGVisualAdaptorModel::MetaObjectCacheable; + } 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); + m_flags = QSGVisualAdaptorModel::MetaObjectCacheable; + } else if (m_listAccessor) { + setModelDataType(); + m_objectList = true; + m_flags = QSGVisualAdaptorModel::ProxiedObject; + } 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_engine, m_delegateDataType->metaObject); + } + return createModelData(index, model); +} + +QSGVisualAdaptorModelData::QSGVisualAdaptorModelData(int index, QSGVisualAdaptorModel *model) + : m_index(index) + , m_model(model) +{ +} + +QSGVisualAdaptorModelData::~QSGVisualAdaptorModelData() +{ +} + +int QSGVisualAdaptorModelData::index() const +{ + return m_index; +} + +// This is internal only - it should not be set from qml +void QSGVisualAdaptorModelData::setIndex(int index) +{ + m_index = index; + emit indexChanged(); +} + +//--------------------------------------------------------------------------- + +QSGVisualAdaptorModel::QSGVisualAdaptorModel(QObject *parent) + : QObject(*(new QSGVisualAdaptorModelPrivate), parent) +{ +} + +QSGVisualAdaptorModel::~QSGVisualAdaptorModel() +{ + Q_D(QSGVisualAdaptorModel); + if (d->m_listAccessor) + delete d->m_listAccessor; + if (d->m_delegateDataType) + d->m_delegateDataType->release(); +} + +QSGVisualAdaptorModel::Flags QSGVisualAdaptorModel::flags() const +{ + Q_D(const QSGVisualAdaptorModel); + return d->m_flags; +} + +QVariant QSGVisualAdaptorModel::model() const +{ + Q_D(const QSGVisualAdaptorModel); + return d->m_modelVariant; +} + +void QSGVisualAdaptorModel::setModel(const QVariant &model, QDeclarativeEngine *engine) +{ + Q_D(QSGVisualAdaptorModel); + delete d->m_listAccessor; + d->m_engine = engine; + d->m_listAccessor = 0; + d->m_modelVariant = model; + if (d->m_listModelInterface) { + // Assume caller has released all items. + QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList)), + this, SLOT(_q_itemsChanged(int,int,QList))); + QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)), + this, SLOT(_q_itemsInserted(int,int))); + QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)), + this, SLOT(_q_itemsRemoved(int,int))); + QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), + this, SLOT(_q_itemsMoved(int,int,int))); + d->m_listModelInterface = 0; + } else if (d->m_abstractItemModel) { + QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex,int,int))); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); + d->m_abstractItemModel = 0; + } + + d->m_roles.clear(); + d->m_roleNames.clear(); + d->m_flags = QSGVisualAdaptorModel::Flags(); + if (d->m_delegateDataType) + d->m_delegateDataType->release(); + d->m_delegateDataType = 0; + d->createModelData = &QSGVisualAdaptorModelPrivate::initializeModelData; + + if (d->m_count) + emit itemsRemoved(0, d->m_count); + + QObject *object = qvariant_cast(model); + if (object && (d->m_listModelInterface = qobject_cast(object))) { + QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList)), + this, SLOT(_q_itemsChanged(int,int,QList))); + QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)), + this, SLOT(_q_itemsInserted(int,int))); + QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)), + this, SLOT(_q_itemsRemoved(int,int))); + QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), + this, SLOT(_q_itemsMoved(int,int,int))); + if ((d->m_count = d->m_listModelInterface->count())) + emit itemsInserted(0, d->m_count); + return; + } else if (object && (d->m_abstractItemModel = qobject_cast(object))) { + QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(_q_rowsInserted(QModelIndex,int,int))); + QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); + QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); + QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + 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())); + + if ((d->m_count = d->m_abstractItemModel->rowCount(d->m_root))) + emit itemsInserted(0, d->m_count); + return; + } + + d->m_listAccessor = new QDeclarativeListAccessor; + d->m_listAccessor->setList(model, d->m_engine); + if ((d->m_count = d->m_listAccessor->count())) + emit itemsInserted(0, d->m_count); +} + +QVariant QSGVisualAdaptorModel::rootIndex() const +{ + Q_D(const QSGVisualAdaptorModel); + return QVariant::fromValue(d->m_root); +} + +void QSGVisualAdaptorModel::setRootIndex(const QVariant &root) +{ + Q_D(QSGVisualAdaptorModel); + QModelIndex modelIndex = qvariant_cast(root); + if (d->m_root != modelIndex) { + int oldCount = d->modelCount(); + d->m_root = modelIndex; + if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex)) + d->m_abstractItemModel->fetchMore(modelIndex); + int newCount = d->modelCount(); + if (oldCount) + emit itemsRemoved(0, oldCount); + if (newCount) + emit itemsInserted(0, newCount); + emit rootIndexChanged(); + } +} + +QVariant QSGVisualAdaptorModel::modelIndex(int idx) const +{ + Q_D(const QSGVisualAdaptorModel); + if (d->m_abstractItemModel) + return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root)); + return QVariant::fromValue(QModelIndex()); +} + +QVariant QSGVisualAdaptorModel::parentModelIndex() const +{ + Q_D(const QSGVisualAdaptorModel); + if (d->m_abstractItemModel) + return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root)); + return QVariant::fromValue(QModelIndex()); +} + +int QSGVisualAdaptorModel::count() const +{ + Q_D(const QSGVisualAdaptorModel); + return d->modelCount(); +} + +QObject *QSGVisualAdaptorModel::data(int index) +{ + Q_D(QSGVisualAdaptorModel); + QSGVisualAdaptorModelData *data = d->createModelData(index, this); + d->m_cache.insert(data); + return data; +} + +QString QSGVisualAdaptorModel::stringValue(int index, const QString &name) +{ + Q_D(QSGVisualAdaptorModel); + if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) { + if (QObject *object = d->m_listAccessor->at(index).value()) + return object->property(name.toUtf8()).toString(); + } + + QString val; + QSGVisualAdaptorModelData *data = d->createModelData(index, this); + + QDeclarativeData *ddata = QDeclarativeData::get(data); + if (ddata && ddata->propertyCache) { + QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name); + if (prop) { + if (prop->propType == QVariant::String) { + void *args[] = { &val, 0 }; + QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args); + } else if (prop->propType == qMetaTypeId()) { + QVariant v; + void *args[] = { &v, 0 }; + QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args); + val = v.toString(); + } + } else { + val = data->property(name.toUtf8()).toString(); + } + } else { + val = data->property(name.toUtf8()).toString(); + } + + delete data; + + return val; +} + +int QSGVisualAdaptorModel::indexOf(QObject *object) const +{ + if (QSGVisualAdaptorModelData *data = qobject_cast(object)) + return data->index(); + return -1; +} + +bool QSGVisualAdaptorModel::canFetchMore() const +{ + Q_D(const QSGVisualAdaptorModel); + return d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root); +} + +void QSGVisualAdaptorModel::fetchMore() +{ + Q_D(QSGVisualAdaptorModel); + if (d->m_abstractItemModel) + d->m_abstractItemModel->fetchMore(d->m_root); +} + +void QSGVisualAdaptorModel::replaceWatchedRoles(const QList &oldRoles, const QList &newRoles) +{ + Q_D(QSGVisualAdaptorModel); + d->watchedRoleIds.clear(); + foreach (const QByteArray &oldRole, oldRoles) + d->watchedRoles.removeOne(oldRole); + d->watchedRoles += newRoles; +} + +void QSGVisualAdaptorModel::_q_itemsChanged(int index, int count, const QList &roles) +{ + Q_D(QSGVisualAdaptorModel); + bool changed = roles.isEmpty(); + if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) { + foreach (QByteArray r, d->watchedRoles) { + if (d->m_roleNames.contains(r)) + d->watchedRoleIds << d->m_roleNames.value(r); + } + } + + 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); + } + + typedef QSGVisualAdaptorModelDataCache::iterator iterator; + for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) { + const int idx = it->index(); + if (idx >= index && idx < index + count) { + QSGVisualAdaptorModelData *data = *it; + for (int i = 0; i < signalIndexes.count(); ++i) + QMetaObject::activate(data, signalIndexes.at(i), 0); + } + } + if (changed) + emit itemsChanged(index, count); +} + +void QSGVisualAdaptorModel::_q_itemsInserted(int index, int count) +{ + Q_D(QSGVisualAdaptorModel); + if (count <= 0) + return; + d->m_count += count; + + typedef QSGVisualAdaptorModelDataCache::iterator iterator; + for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) { + if (it->index() >= index) + it->setIndex(it->index() + count); + } + + emit itemsInserted(index, count); +} + +void QSGVisualAdaptorModel::_q_itemsRemoved(int index, int count) +{ + Q_D(QSGVisualAdaptorModel); + if (count <= 0) + return; + d->m_count -= count; + + typedef QSGVisualAdaptorModelDataCache::iterator iterator; + for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) { + if (it->index() >= index + count) + it->setIndex(it->index() - count); + else if (it->index() >= index) + it->setIndex(-1); + } + + emit itemsRemoved(index, count); +} + +void QSGVisualAdaptorModel::_q_itemsMoved(int from, int to, int count) +{ + Q_D(QSGVisualAdaptorModel); + const int minimum = qMin(from, to); + const int maximum = qMax(from, to) + count; + const int difference = from > to ? count : -count; + + typedef QSGVisualAdaptorModelDataCache::iterator iterator; + for (iterator it = d->m_cache.begin(); it != d->m_cache.end(); ++it) { + if (it->index() >= from && it->index() < from + count) + it->setIndex(it->index() - from + to); + else if (it->index() >= minimum && it->index() < maximum) + it->setIndex(it->index() + difference); + } + emit itemsMoved(from, to, count); +} + +void QSGVisualAdaptorModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end) +{ + Q_D(QSGVisualAdaptorModel); + if (parent == d->m_root) + _q_itemsInserted(begin, end - begin + 1); +} + +void QSGVisualAdaptorModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end) +{ + Q_D(QSGVisualAdaptorModel); + if (parent == d->m_root) + _q_itemsRemoved(begin, end - begin + 1); +} + +void QSGVisualAdaptorModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) +{ + Q_D(QSGVisualAdaptorModel); + const int count = sourceEnd - sourceStart + 1; + if (destinationParent == d->m_root && sourceParent == d->m_root) { + _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-count, count); + } else if (sourceParent == d->m_root) { + _q_itemsRemoved(sourceStart, count); + } else if (destinationParent == d->m_root) { + _q_itemsInserted(destinationRow, count); + } +} + +void QSGVisualAdaptorModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end) +{ + Q_D(QSGVisualAdaptorModel); + if (begin.parent() == d->m_root) + _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); +} + +void QSGVisualAdaptorModel::_q_layoutChanged() +{ + Q_D(QSGVisualAdaptorModel); + _q_itemsChanged(0, count(), d->m_roles); +} + +void QSGVisualAdaptorModel::_q_modelReset() +{ + Q_D(QSGVisualAdaptorModel); + int oldCount = d->m_count; + d->m_root = QModelIndex(); + d->m_count = d->modelCount(); + emit modelReset(oldCount, d->m_count); + emit rootIndexChanged(); + if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root)) + d->m_abstractItemModel->fetchMore(d->m_root); +} + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QListModelInterface) + +#include diff --git a/src/declarative/items/qsgvisualadaptormodel_p.h b/src/declarative/items/qsgvisualadaptormodel_p.h new file mode 100644 index 0000000..bc9d388 --- /dev/null +++ b/src/declarative/items/qsgvisualadaptormodel_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGVISUALADAPTORMODEL_P_H +#define QSGVISUALADAPTORMODEL_P_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; + +class QSGVisualAdaptorModelPrivate; +class QSGVisualAdaptorModel : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSGVisualAdaptorModel) +public: + enum Flag + { + MetaObjectCacheable = 0x01, + ProxiedObject = 0x02 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + QSGVisualAdaptorModel(QObject *parent = 0); + virtual ~QSGVisualAdaptorModel(); + + Flags flags() const; + + QVariant model() const; + void setModel(const QVariant &, QDeclarativeEngine *); + + QVariant rootIndex() const; + void setRootIndex(const QVariant &root); + + QVariant modelIndex(int idx) const; + QVariant parentModelIndex() const; + + int count() const; + QObject *data(int index); + QString stringValue(int index, const QString &role); + void replaceWatchedRoles(const QList &oldRoles, const QList &newRoles); + int indexOf(QObject *object) const; + + bool canFetchMore() const; + void fetchMore(); + +Q_SIGNALS: + void rootIndexChanged(); + void modelReset(int oldCount, int newCount); + + void itemsInserted(int index, int count); + void itemsRemoved(int index, int count); + void itemsMoved(int from, int to, int count); + void itemsChanged(int index, int count); + +private Q_SLOTS: + void _q_itemsChanged(int, int, const QList &); + void _q_itemsInserted(int index, int count); + void _q_itemsRemoved(int index, int count); + void _q_itemsMoved(int from, int to, int count); + void _q_rowsInserted(const QModelIndex &,int,int); + void _q_rowsRemoved(const QModelIndex &,int,int); + void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); + void _q_dataChanged(const QModelIndex&,const QModelIndex&); + void _q_layoutChanged(); + void _q_modelReset(); + +private: + Q_DISABLE_COPY(QSGVisualAdaptorModel) +}; + +class QSGVisualAdaptorModelProxyInterface +{ +public: + virtual ~QSGVisualAdaptorModelProxyInterface() {} + + virtual QObject *proxiedObject() = 0; +}; + +Q_DECLARE_INTERFACE(QSGVisualAdaptorModelProxyInterface, "com.trolltech.qml.QSGVisualAdaptorModelProxyInterface") + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/items/qsgvisualdatamodel.cpp b/src/declarative/items/qsgvisualdatamodel.cpp new file mode 100644 index 0000000..219d1dc --- /dev/null +++ b/src/declarative/items/qsgvisualdatamodel.cpp @@ -0,0 +1,849 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgvisualdatamodel_p.h" +#include "qsgitem.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QSGVisualDataModelParts; +class QSGVisualDataModelData; +class QSGVisualDataModelDataMetaObject; +class QSGVisualDataModelPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSGVisualDataModel) +public: + QSGVisualDataModelPrivate(QDeclarativeContext *); + + static QSGVisualDataModelPrivate *get(QSGVisualDataModel *m) { + return static_cast(QObjectPrivate::get(m)); + } + + void init(); + void connectModel(QSGVisualAdaptorModel *model); + + QObject *object(int index, bool complete); + QSGVisualDataModel::ReleaseFlags release(QObject *object); + QString stringValue(int index, const QString &name); + void emitCreatedPackage(int index, QDeclarativePackage *package) { + emit q_func()->createdPackage(index, package); } + void emitDestroyingPackage(QDeclarativePackage *package) { + emit q_func()->destroyingPackage(package); } + + QSGVisualAdaptorModel *m_adaptorModel; + QDeclarativeComponent *m_delegate; + QDeclarativeGuard m_context; + + struct ObjectRef { + ObjectRef(QObject *object=0) : obj(object), ref(1) {} + QObject *obj; + int ref; + }; + class Cache : public QHash { + public: + QObject *getItem(int index) { + QObject *item = 0; + QHash::iterator it = find(index); + if (it != end()) { + (*it).ref++; + item = (*it).obj; + } + return item; + } + QObject *item(int index) { + QObject *item = 0; + QHash::const_iterator it = find(index); + if (it != end()) + item = (*it).obj; + return item; + } + void insertItem(int index, QObject *obj) { + insert(index, ObjectRef(obj)); + } + bool releaseItem(QObject *obj) { + QHash::iterator it = begin(); + for (; it != end(); ++it) { + ObjectRef &objRef = *it; + if (objRef.obj == obj) { + if (--objRef.ref == 0) { + erase(it); + return true; + } + break; + } + } + return false; + } + }; + + Cache m_cache; + QHash m_packaged; + + QSGVisualDataModelParts *m_parts; + friend class QSGVisualItemParts; + + friend class QSGVisualDataModelData; + bool m_delegateValidated : 1; + bool m_completePending : 1; + + QList watchedRoles; +}; + +//--------------------------------------------------------------------------- + +class QSGVisualPartsModel : public QSGVisualModel +{ + Q_OBJECT + +public: + QSGVisualPartsModel(QSGVisualDataModel *model, const QString &part, QObject *parent = 0); + ~QSGVisualPartsModel(); + + int count() const; + bool isValid() const; + QSGItem *item(int index, bool complete=true); + ReleaseFlags release(QSGItem *item); + bool completePending() const; + void completeItem(); + QString stringValue(int index, const QString &role); + void setWatchedRoles(QList roles); + + int indexOf(QSGItem *item, QObject *objectContext) const; + +public Q_SLOTS: + void createdPackage(int index, QDeclarativePackage *package); + void destroyingPackage(QDeclarativePackage *package); + +private: + QSGVisualDataModel *m_model; + QHash m_packaged; + QString m_part; + QList m_watchedRoles; +}; + +class QSGVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject +{ +public: + QSGVisualDataModelPartsMetaObject(QObject *parent) + : QDeclarativeOpenMetaObject(parent) {} + + virtual void propertyCreated(int, QMetaPropertyBuilder &); + virtual QVariant initialValue(int); +}; + +class QSGVisualDataModelParts : public QObject +{ +Q_OBJECT +public: + QSGVisualDataModelParts(QSGVisualDataModel *parent); + +private: + friend class QSGVisualDataModelPartsMetaObject; + QSGVisualDataModel *model; +}; + +void QSGVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop) +{ + prop.setWritable(false); +} + +QVariant QSGVisualDataModelPartsMetaObject::initialValue(int id) +{ + QSGVisualPartsModel *m = new QSGVisualPartsModel( + static_cast(object())->model, + QString::fromUtf8(name(id)), + object()); + return QVariant::fromValue(static_cast(m)); +} + +QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent) +: QObject(parent), model(parent) +{ + new QSGVisualDataModelPartsMetaObject(this); +} + +QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt) + : m_adaptorModel(0) + , m_delegate(0) + , m_context(ctxt) + , m_parts(0) + , m_delegateValidated(false) + , m_completePending(false) +{ +} + +//--------------------------------------------------------------------------- + +/*! + \qmlclass VisualDataModel QSGVisualDataModel + \inqmlmodule QtQuick 2 + \ingroup qml-working-with-data + \brief The VisualDataModel encapsulates a model and delegate + + A VisualDataModel encapsulates a model and the delegate that will + be instantiated for items in the model. + + It is usually not necessary to create VisualDataModel elements. + However, it can be useful for manipulating and accessing the \l modelIndex + when a QAbstractItemModel subclass is used as the + model. Also, VisualDataModel is used together with \l Package to + provide delegates to multiple views. + + The example below illustrates using a VisualDataModel with a ListView. + + \snippet doc/src/snippets/declarative/visualdatamodel.qml 0 +*/ + +void QSGVisualDataModelPrivate::connectModel(QSGVisualAdaptorModel *model) +{ + Q_Q(QSGVisualDataModel); + + QObject::connect(model, SIGNAL(itemsInserted(int,int)), q, SLOT(_q_itemsInserted(int,int))); + QObject::connect(model, SIGNAL(itemsRemoved(int,int)), q, SLOT(_q_itemsRemoved(int,int))); + QObject::connect(model, SIGNAL(itemsMoved(int,int,int)), q, SLOT(_q_itemsMoved(int,int,int))); + QObject::connect(model, SIGNAL(itemsChanged(int,int)), q, SLOT(_q_itemsChanged(int,int))); + QObject::connect(model, SIGNAL(modelReset(int,int)), q, SLOT(_q_modelReset(int,int))); +} + +void QSGVisualDataModelPrivate::init() +{ + Q_Q(QSGVisualDataModel); + m_adaptorModel = new QSGVisualAdaptorModel; + QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged())); + connectModel(m_adaptorModel); +} + +QSGVisualDataModel::QSGVisualDataModel() +: QSGVisualModel(*(new QSGVisualDataModelPrivate(0))) +{ + Q_D(QSGVisualDataModel); + d->init(); +} + +QSGVisualDataModel::QSGVisualDataModel(QDeclarativeContext *ctxt, QObject *parent) +: QSGVisualModel(*(new QSGVisualDataModelPrivate(ctxt)), parent) +{ + Q_D(QSGVisualDataModel); + d->init(); +} + +QSGVisualDataModel::~QSGVisualDataModel() +{ + Q_D(QSGVisualDataModel); + delete d->m_adaptorModel; +} + +/*! + \qmlproperty model QtQuick2::VisualDataModel::model + This property holds the model providing data for the VisualDataModel. + + The model provides a set of data that is used to create the items + for a view. For large or dynamic datasets the model is usually + provided by a C++ model object. The C++ model object must be a \l + {QAbstractItemModel} subclass or a simple list. + + Models can also be created directly in QML, using a \l{ListModel} or + \l{XmlListModel}. + + \sa {qmlmodels}{Data Models} +*/ +QVariant QSGVisualDataModel::model() const +{ + Q_D(const QSGVisualDataModel); + return d->m_adaptorModel->model(); +} + +void QSGVisualDataModel::setModel(const QVariant &model) +{ + Q_D(QSGVisualDataModel); + d->m_adaptorModel->setModel(model, d->m_context ? d->m_context->engine() : qmlEngine(this)); + if (d->m_adaptorModel->canFetchMore()) + QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); +} + +/*! + \qmlproperty Component QtQuick2::VisualDataModel::delegate + + The delegate provides a template defining each item instantiated by a view. + The index is exposed as an accessible \c index property. Properties of the + model are also available depending upon the type of \l {qmlmodels}{Data Model}. +*/ +QDeclarativeComponent *QSGVisualDataModel::delegate() const +{ + Q_D(const QSGVisualDataModel); + return d->m_delegate; +} + +void QSGVisualDataModel::setDelegate(QDeclarativeComponent *delegate) +{ + Q_D(QSGVisualDataModel); + bool wasValid = d->m_delegate != 0; + d->m_delegate = delegate; + d->m_delegateValidated = false; + if (!wasValid && d->m_adaptorModel->count() && d->m_delegate) { + emit itemsInserted(0, d->m_adaptorModel->count()); + emit countChanged(); + } + if (wasValid && !d->m_delegate && d->m_adaptorModel->count()) { + _q_itemsRemoved(0, d->m_adaptorModel->count()); + emit countChanged(); + } +} + +/*! + \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex + + QAbstractItemModel provides a hierarchical tree of data, whereas + QML only operates on list data. \c rootIndex allows the children of + any node in a QAbstractItemModel to be provided by this model. + + This property only affects models of type QAbstractItemModel that + are hierarchical (e.g, a tree model). + + For example, here is a simple interactive file system browser. + When a directory name is clicked, the view's \c rootIndex is set to the + QModelIndex node of the clicked directory, thus updating the view to show + the new directory's contents. + + \c main.cpp: + \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0 + + \c view.qml: + \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0 + + If the \l model is a QAbstractItemModel subclass, the delegate can also + reference a \c hasModelChildren property (optionally qualified by a + \e model. prefix) that indicates whether the delegate's model item has + any child nodes. + + + \sa modelIndex(), parentModelIndex() +*/ +QVariant QSGVisualDataModel::rootIndex() const +{ + Q_D(const QSGVisualDataModel); + return d->m_adaptorModel->rootIndex(); +} + +void QSGVisualDataModel::setRootIndex(const QVariant &root) +{ + Q_D(QSGVisualDataModel); + d->m_adaptorModel->setRootIndex(root); +} + +/*! + \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index) + + QAbstractItemModel provides a hierarchical tree of data, whereas + QML only operates on list data. This function assists in using + tree models in QML. + + Returns a QModelIndex for the specified index. + This value can be assigned to rootIndex. + + \sa rootIndex +*/ +QVariant QSGVisualDataModel::modelIndex(int idx) const +{ + Q_D(const QSGVisualDataModel); + return d->m_adaptorModel->modelIndex(idx); +} + +/*! + \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex() + + QAbstractItemModel provides a hierarchical tree of data, whereas + QML only operates on list data. This function assists in using + tree models in QML. + + Returns a QModelIndex for the parent of the current rootIndex. + This value can be assigned to rootIndex. + + \sa rootIndex +*/ +QVariant QSGVisualDataModel::parentModelIndex() const +{ + Q_D(const QSGVisualDataModel); + return d->m_adaptorModel->parentModelIndex(); +} + +int QSGVisualDataModel::count() const +{ + Q_D(const QSGVisualDataModel); + if (!d->m_delegate) + return 0; + return d->m_adaptorModel->count(); +} + +QSGVisualDataModel::ReleaseFlags QSGVisualDataModelPrivate::release(QObject *object) +{ + QSGVisualDataModel::ReleaseFlags stat = 0; + + if (m_cache.releaseItem(object)) { + // Remove any bindings to avoid warnings due to parent change. + QObjectPrivate *p = QObjectPrivate::get(object); + Q_ASSERT(p->declarativeData); + QDeclarativeData *d = static_cast(p->declarativeData); + if (d->ownContext && d->context) + d->context->clearContext(); + stat |= QSGVisualDataModel::Destroyed; + object->deleteLater(); + } else { + stat |= QSGVisualDataModel::Referenced; + } + + return stat; +} + +/* + Returns ReleaseStatus flags. +*/ + +QSGVisualDataModel::ReleaseFlags QSGVisualDataModel::release(QSGItem *item) +{ + Q_D(QSGVisualDataModel); + QSGVisualModel::ReleaseFlags stat = d->release(item); + if (stat & Destroyed) + item->setParentItem(0); + return stat; +} + +/*! + \qmlproperty object QtQuick2::VisualDataModel::parts + + The \a parts property selects a VisualDataModel which creates + delegates from the part named. This is used in conjunction with + the \l Package element. + + For example, the code below selects a model which creates + delegates named \e list from a \l Package: + + \code + VisualDataModel { + id: visualModel + delegate: Package { + Item { Package.name: "list" } + } + model: myModel + } + + ListView { + width: 200; height:200 + model: visualModel.parts.list + } + \endcode + + \sa Package +*/ + +QObject *QSGVisualDataModel::parts() +{ + Q_D(QSGVisualDataModel); + if (!d->m_parts) + d->m_parts = new QSGVisualDataModelParts(this); + return d->m_parts; +} + +QObject *QSGVisualDataModelPrivate::object(int index, bool complete) +{ + Q_Q(QSGVisualDataModel); + if (m_adaptorModel->count() <= 0 || !m_delegate) + return 0; + QObject *nobj = m_cache.getItem(index); + bool needComplete = false; + if (!nobj) { + QObject *data = m_adaptorModel->data(index); + + QDeclarativeContext *rootContext = new QDeclarativeContext( + m_context ? m_context.data() : qmlContext(q)); + QDeclarativeContext *ctxt = rootContext; + if (m_adaptorModel->flags() & QSGVisualAdaptorModel::ProxiedObject) { + if (QSGVisualAdaptorModelProxyInterface *proxy = qobject_cast(data)) { + ctxt->setContextObject(proxy->proxiedObject()); + ctxt = new QDeclarativeContext(ctxt, ctxt); + } + } + + QDeclarative_setParent_noEvent(data, ctxt); + ctxt->setContextProperty(QLatin1String("model"), data); + ctxt->setContextObject(data); + + m_completePending = false; + nobj = m_delegate->beginCreate(ctxt); + if (complete) { + m_delegate->completeCreate(); + } else { + m_completePending = true; + needComplete = true; + } + if (nobj) { + QDeclarative_setParent_noEvent(rootContext, nobj); + m_cache.insertItem(index, nobj); + if (QDeclarativePackage *package = qobject_cast(nobj)) + emitCreatedPackage(index, package); + } else { + delete rootContext; + qmlInfo(q, m_delegate->errors()) << "Error creating delegate"; + } + } + + if (index == m_adaptorModel->count() -1 && m_adaptorModel->canFetchMore()) + QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest)); + + return nobj; +} + +QSGItem *QSGVisualDataModel::item(int index, bool complete) +{ + Q_D(QSGVisualDataModel); + QObject *object = d->object(index, complete); + if (QSGItem *item = qobject_cast(object)) + return item; + + if (completePending()) + completeItem(); + d->release(object); + if (!d->m_delegateValidated) { + qmlInfo(d->m_delegate) << tr("Delegate component must be Item type."); + d->m_delegateValidated = true; + } + return 0; +} + +bool QSGVisualDataModel::completePending() const +{ + Q_D(const QSGVisualDataModel); + return d->m_completePending; +} + +void QSGVisualDataModel::completeItem() +{ + Q_D(QSGVisualDataModel); + d->m_delegate->completeCreate(); + d->m_completePending = false; +} + +QString QSGVisualDataModelPrivate::stringValue(int index, const QString &name) +{ + return m_adaptorModel->stringValue(index, name); +} + +QString QSGVisualDataModel::stringValue(int index, const QString &name) +{ + Q_D(QSGVisualDataModel); + return d->stringValue(index, name); +} + +int QSGVisualDataModel::indexOf(QSGItem *item, QObject *) const +{ + Q_D(const QSGVisualDataModel); + return d->m_adaptorModel->indexOf(item); +} + +void QSGVisualDataModel::setWatchedRoles(QList roles) +{ + Q_D(QSGVisualDataModel); + d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles); + d->watchedRoles = roles; +} + +bool QSGVisualDataModel::event(QEvent *e) +{ + Q_D(QSGVisualDataModel); + if (e->type() == QEvent::UpdateRequest) + d->m_adaptorModel->fetchMore(); + return QSGVisualModel::event(e); +} + +void QSGVisualDataModel::_q_itemsChanged(int index, int count) +{ + Q_D(QSGVisualDataModel); + if (!d->m_delegate) + return; + emit itemsChanged(index, count); +} + +void QSGVisualDataModel::_q_itemsInserted(int index, int count) +{ + Q_D(QSGVisualDataModel); + if (!d->m_delegate) + return; + + // XXX - highly inefficient + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); + iter != d->m_cache.end(); ) { + + if (iter.key() >= index) { + QSGVisualDataModelPrivate::ObjectRef objRef = *iter; + int index = iter.key() + count; + iter = d->m_cache.erase(iter); + + items.insert(index, objRef); + } else { + ++iter; + } + } + d->m_cache.unite(items); + + emit itemsInserted(index, count); + emit countChanged(); +} + +void QSGVisualDataModel::_q_itemsRemoved(int index, int count) +{ + Q_D(QSGVisualDataModel); + if (!d->m_delegate) + return; + // XXX - highly inefficient + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); + iter != d->m_cache.end(); ) { + if (iter.key() >= index && iter.key() < index + count) { + QSGVisualDataModelPrivate::ObjectRef objRef = *iter; + iter = d->m_cache.erase(iter); + items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately + } else if (iter.key() >= index + count) { + QSGVisualDataModelPrivate::ObjectRef objRef = *iter; + int index = iter.key() - count; + iter = d->m_cache.erase(iter); + items.insert(index, objRef); + } else { + ++iter; + } + } + d->m_cache.unite(items); + + emit itemsRemoved(index, count); + emit countChanged(); +} + +void QSGVisualDataModel::_q_itemsMoved(int from, int to, int count) +{ + Q_D(QSGVisualDataModel); + if (!d->m_delegate) + return; + + // XXX - highly inefficient + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); + iter != d->m_cache.end(); ) { + if (iter.key() >= from && iter.key() < from + count) { + QSGVisualDataModelPrivate::ObjectRef objRef = *iter; + int index = iter.key() - from + to; + items.insert(index, objRef); + iter = d->m_cache.erase(iter); + } else { + ++iter; + } + } + for (QHash::Iterator iter = d->m_cache.begin(); + iter != d->m_cache.end(); ) { + int diff = from > to ? count : -count; + if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) { + QSGVisualDataModelPrivate::ObjectRef objRef = *iter; + int index = iter.key() + diff; + iter = d->m_cache.erase(iter); + items.insert(index, objRef); + } else { + ++iter; + } + } + d->m_cache.unite(items); + emit itemsMoved(from, to, count); +} + +void QSGVisualDataModel::_q_modelReset(int, int) +{ + Q_D(QSGVisualDataModel); + if (!d->m_delegate) + return; + emit modelReset(); + emit countChanged(); +} + +//============================================================================ + +QSGVisualPartsModel::QSGVisualPartsModel(QSGVisualDataModel *model, const QString &part, QObject *parent) + : QSGVisualModel(*new QObjectPrivate, parent) + , m_model(model) + , m_part(part) +{ + connect(m_model, SIGNAL(modelReset()), this, SIGNAL(modelReset())); + connect(m_model, SIGNAL(itemsInserted(int,int)), this, SIGNAL(itemsInserted(int,int))); + connect(m_model, SIGNAL(itemsRemoved(int,int)), this, SIGNAL(itemsRemoved(int,int))); + connect(m_model, SIGNAL(itemsChanged(int,int)), this, SIGNAL(itemsChanged(int,int))); + connect(m_model, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); + connect(m_model, SIGNAL(createdPackage(int,QDeclarativePackage*)), + this, SLOT(createdPackage(int,QDeclarativePackage*))); + connect(m_model, SIGNAL(destroyingPackage(QDeclarativePackage*)), + this, SLOT(destroyingPackage(QDeclarativePackage*))); +} + +QSGVisualPartsModel::~QSGVisualPartsModel() +{ +} + +int QSGVisualPartsModel::count() const +{ + return m_model->count(); +} + +bool QSGVisualPartsModel::isValid() const +{ + return m_model->isValid(); +} + +QSGItem *QSGVisualPartsModel::item(int index, bool complete) +{ + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); + + QObject *object = model->object(index, complete); + + if (QDeclarativePackage *package = qobject_cast(object)) { + QObject *part = package->part(m_part); + if (!part) + return 0; + if (QSGItem *item = qobject_cast(part)) { + m_packaged.insertMulti(item, package); + return item; + } + } + + if (m_model->completePending()) + m_model->completeItem(); + model->release(object); + if (!model->m_delegateValidated) { + qmlInfo(model->m_delegate) << tr("Delegate component must be Package type."); + model->m_delegateValidated = true; + } + + return 0; +} + +QSGVisualModel::ReleaseFlags QSGVisualPartsModel::release(QSGItem *item) +{ + QSGVisualModel::ReleaseFlags flags = 0; + + QHash::iterator it = m_packaged.find(item); + if (it != m_packaged.end()) { + QDeclarativePackage *package = *it; + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); + flags = model->release(package); + m_packaged.erase(it); + if (!m_packaged.contains(item)) + flags &= ~Referenced; + if (flags & Destroyed) + QSGVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package); + } + return flags; +} + +bool QSGVisualPartsModel::completePending() const +{ + return m_model->completePending(); +} + +void QSGVisualPartsModel::completeItem() +{ + m_model->completeItem(); +} + +QString QSGVisualPartsModel::stringValue(int index, const QString &role) +{ + return QSGVisualDataModelPrivate::get(m_model)->stringValue(index, role); +} + +void QSGVisualPartsModel::setWatchedRoles(QList roles) +{ + QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); + model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles); + m_watchedRoles = roles; +} + +int QSGVisualPartsModel::indexOf(QSGItem *item, QObject *) const +{ + const QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model); + QHash::const_iterator it = m_packaged.find(item); + return it != m_packaged.end() + ? model->m_adaptorModel->indexOf(*it) + : -1; +} + +void QSGVisualPartsModel::createdPackage(int index, QDeclarativePackage *package) +{ + if (QSGItem *item = qobject_cast(package->part(m_part))) + emit createdItem(index, item); +} + +void QSGVisualPartsModel::destroyingPackage(QDeclarativePackage *package) +{ + if (QSGItem *item = qobject_cast(package->part(m_part))) { + Q_ASSERT(!m_packaged.contains(item)); + emit destroyingItem(item); + } +} + +QT_END_NAMESPACE + +#include diff --git a/src/declarative/items/qsgvisualdatamodel_p.h b/src/declarative/items/qsgvisualdatamodel_p.h new file mode 100644 index 0000000..d3f1d18 --- /dev/null +++ b/src/declarative/items/qsgvisualdatamodel_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGVISUALDATAMODEL_P_H +#define QSGVISUALDATAMODEL_P_H + +#include +#include + +QT_BEGIN_HEADER + +Q_DECLARE_METATYPE(QModelIndex) + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeComponent; +class QDeclarativePackage; +class QSGVisualDataModelPrivate; +class Q_DECLARATIVE_EXPORT QSGVisualDataModel : public QSGVisualModel +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSGVisualDataModel) + + Q_PROPERTY(QVariant model READ model WRITE setModel) + Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate) + Q_PROPERTY(QObject *parts READ parts CONSTANT) + Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged) + Q_CLASSINFO("DefaultProperty", "delegate") +public: + QSGVisualDataModel(); + QSGVisualDataModel(QDeclarativeContext *, QObject *parent=0); + virtual ~QSGVisualDataModel(); + + QVariant model() const; + void setModel(const QVariant &); + + QDeclarativeComponent *delegate() const; + void setDelegate(QDeclarativeComponent *); + + QVariant rootIndex() const; + void setRootIndex(const QVariant &root); + + Q_INVOKABLE QVariant modelIndex(int idx) const; + Q_INVOKABLE QVariant parentModelIndex() const; + + int count() const; + bool isValid() const { return delegate() != 0; } + QSGItem *item(int index, bool complete=true); + ReleaseFlags release(QSGItem *item); + bool completePending() const; + void completeItem(); + virtual QString stringValue(int index, const QString &role); + virtual void setWatchedRoles(QList roles); + + int indexOf(QSGItem *item, QObject *objectContext) const; + + QObject *parts(); + + bool event(QEvent *); + +Q_SIGNALS: + void createdPackage(int index, QDeclarativePackage *package); + void destroyingPackage(QDeclarativePackage *package); + void rootIndexChanged(); + +private Q_SLOTS: + void _q_itemsChanged(int index, int count); + void _q_itemsInserted(int index, int count); + void _q_itemsRemoved(int index, int count); + void _q_itemsMoved(int from, int to, int count); + void _q_modelReset(int oldCount, int newCount); +private: + Q_DISABLE_COPY(QSGVisualDataModel) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QSGVisualDataModel) + +QT_END_HEADER + +#endif // QSGVISUALDATAMODEL_P_H diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp index c6e5896..fbc8a1a 100644 --- a/src/declarative/items/qsgvisualitemmodel.cpp +++ b/src/declarative/items/qsgvisualitemmodel.cpp @@ -42,22 +42,11 @@ #include "qsgvisualitemmodel_p.h" #include "qsgitem.h" +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include #include @@ -247,1315 +236,5 @@ QSGVisualItemModelAttached *QSGVisualItemModel::qmlAttachedProperties(QObject *o return QSGVisualItemModelAttached::properties(obj); } -//============================================================================ - -class VDMDelegateDataType : public QDeclarativeRefCount -{ -public: - 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) - { - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - } - - ~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 *); - - static QSGVisualDataModelPrivate *get(QSGVisualDataModel *m) { - return static_cast(QObjectPrivate::get(m)); - } - - QDeclarativeGuard m_listModelInterface; - QDeclarativeGuard m_abstractItemModel; - QDeclarativeGuard m_visualItemModel; - QString m_part; - - QDeclarativeComponent *m_delegate; - QDeclarativeGuard m_context; - QList m_roles; - QHash m_roleNames; - - 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); - - 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; - int ref; - }; - class Cache : public QHash { - public: - QObject *getItem(int index) { - QObject *item = 0; - QHash::iterator it = find(index); - if (it != end()) { - (*it).ref++; - item = (*it).obj; - } - return item; - } - QObject *item(int index) { - QObject *item = 0; - QHash::const_iterator it = find(index); - if (it != end()) - item = (*it).obj; - return item; - } - void insertItem(int index, QObject *obj) { - insert(index, ObjectRef(obj)); - } - bool releaseItem(QObject *obj) { - QHash::iterator it = begin(); - for (; it != end(); ++it) { - ObjectRef &objRef = *it; - if (objRef.obj == obj) { - if (--objRef.ref == 0) { - erase(it); - return true; - } - break; - } - } - return false; - } - }; - - int modelCount() const { - if (m_visualItemModel) - return m_visualItemModel->count(); - if (m_listModelInterface) - return m_listModelInterface->count(); - if (m_abstractItemModel) - return m_abstractItemModel->rowCount(m_root); - if (m_listAccessor) - return m_listAccessor->count(); - return 0; - } - - Cache m_cache; - QHash m_packaged; - - QSGVisualDataModelParts *m_parts; - friend class QSGVisualItemParts; - - VDMDelegateDataType *m_delegateDataType; - CreateModelData createModelData; - - friend class QSGVisualDataModelData; - bool m_delegateValidated : 1; - bool m_completePending : 1; - bool m_objectList : 1; - - QSGVisualDataModelData *data(QObject *item); - - QVariant m_modelVariant; - QDeclarativeListAccessor *m_listAccessor; - - QModelIndex m_root; - QList watchedRoles; - QList watchedRoleIds; - - QVector m_propertyData; -}; - -class QSGVisualDataModelData : public QObject -{ - Q_OBJECT - Q_PROPERTY(int index READ index NOTIFY indexChanged) -public: - QSGVisualDataModelData(int index, QSGVisualDataModel *model); - ~QSGVisualDataModelData(); - - int index() const; - void setIndex(int index); - -Q_SIGNALS: - void indexChanged(); - -public: - int m_index; - QDeclarativeGuard m_model; -}; - -class QSGVisualDataModelDataMetaObject : public QAbstractDynamicMetaObject -{ -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(); - } - - ~QSGVisualDataModelDataMetaObject() { m_type->release(); } - - QSGVisualDataModelData *m_data; - VDMDelegateDataType *m_type; -}; - -class QSGVDMAbstractItemModelDataMetaObject : public QSGVisualDataModelDataMetaObject -{ -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); - } - } -}; - -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)); - } - - 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); - } -}; - -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); - } - } -}; - -class QSGVDMListModelInterfaceData : public QSGVisualDataModelData -{ -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); - } -}; - -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); } - - 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 m_data->qt_metacall(call, id, arguments); - } - } - - 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(); - } - - 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; - } - - 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 *QSGVisualDataModelPrivate::createMetaObject(int index, QSGVisualDataModel *model) -{ - 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(int index, QSGVisualDataModel *model) - : m_index(index) - , m_model(model) -{ -} - -QSGVisualDataModelData::~QSGVisualDataModelData() -{ -} - -int QSGVisualDataModelData::index() const -{ - return m_index; -} - -// This is internal only - it should not be set from qml -void QSGVisualDataModelData::setIndex(int index) -{ - m_index = index; - emit indexChanged(); -} - -//--------------------------------------------------------------------------- - -class QSGVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject -{ -public: - QSGVisualDataModelPartsMetaObject(QObject *parent) - : QDeclarativeOpenMetaObject(parent) {} - - virtual void propertyCreated(int, QMetaPropertyBuilder &); - virtual QVariant initialValue(int); -}; - -class QSGVisualDataModelParts : public QObject -{ -Q_OBJECT -public: - QSGVisualDataModelParts(QSGVisualDataModel *parent); - -private: - friend class QSGVisualDataModelPartsMetaObject; - QSGVisualDataModel *model; -}; - -void QSGVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop) -{ - prop.setWritable(false); -} - -QVariant QSGVisualDataModelPartsMetaObject::initialValue(int id) -{ - QSGVisualDataModel *m = new QSGVisualDataModel; - m->setParent(object()); - m->setPart(QString::fromUtf8(name(id))); - m->setModel(QVariant::fromValue(static_cast(object())->model)); - - QVariant var = QVariant::fromValue((QObject *)m); - return var; -} - -QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent) -: QObject(parent), model(parent) -{ - new QSGVisualDataModelPartsMetaObject(this); -} - -QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt) -: m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0) -, m_context(ctxt), m_parts(0), m_delegateDataType(0), createModelData(&initializeModelData) -, m_delegateValidated(false), m_completePending(false), m_objectList(false), m_listAccessor(0) -{ -} - -QSGVisualDataModelData *QSGVisualDataModelPrivate::data(QObject *item) -{ - QSGVisualDataModelData *dataItem = - item->findChild(); - Q_ASSERT(dataItem); - return dataItem; -} - -//--------------------------------------------------------------------------- - -/*! - \qmlclass VisualDataModel QSGVisualDataModel - \inqmlmodule QtQuick 2 - \ingroup qml-working-with-data - \brief The VisualDataModel encapsulates a model and delegate - - A VisualDataModel encapsulates a model and the delegate that will - be instantiated for items in the model. - - It is usually not necessary to create VisualDataModel elements. - However, it can be useful for manipulating and accessing the \l modelIndex - when a QAbstractItemModel subclass is used as the - model. Also, VisualDataModel is used together with \l Package to - provide delegates to multiple views. - - The example below illustrates using a VisualDataModel with a ListView. - - \snippet doc/src/snippets/declarative/visualdatamodel.qml 0 -*/ - -QSGVisualDataModel::QSGVisualDataModel() -: QSGVisualModel(*(new QSGVisualDataModelPrivate(0))) -{ -} - -QSGVisualDataModel::QSGVisualDataModel(QDeclarativeContext *ctxt, QObject *parent) -: QSGVisualModel(*(new QSGVisualDataModelPrivate(ctxt)), parent) -{ -} - -QSGVisualDataModel::~QSGVisualDataModel() -{ - Q_D(QSGVisualDataModel); - if (d->m_listAccessor) - delete d->m_listAccessor; - if (d->m_delegateDataType) - d->m_delegateDataType->release(); -} - -/*! - \qmlproperty model QtQuick2::VisualDataModel::model - This property holds the model providing data for the VisualDataModel. - - The model provides a set of data that is used to create the items - for a view. For large or dynamic datasets the model is usually - provided by a C++ model object. The C++ model object must be a \l - {QAbstractItemModel} subclass or a simple list. - - Models can also be created directly in QML, using a \l{ListModel} or - \l{XmlListModel}. - - \sa {qmlmodels}{Data Models} -*/ -QVariant QSGVisualDataModel::model() const -{ - Q_D(const QSGVisualDataModel); - return d->m_modelVariant; -} - -void QSGVisualDataModel::setModel(const QVariant &model) -{ - Q_D(QSGVisualDataModel); - delete d->m_listAccessor; - d->m_listAccessor = 0; - d->m_modelVariant = model; - if (d->m_listModelInterface) { - // Assume caller has released all items. - QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList)), - this, SLOT(_q_itemsChanged(int,int,QList))); - QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)), - this, SLOT(_q_itemsInserted(int,int))); - QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)), - this, SLOT(_q_itemsRemoved(int,int))); - QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), - this, SLOT(_q_itemsMoved(int,int,int))); - d->m_listModelInterface = 0; - } else if (d->m_abstractItemModel) { - QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(_q_rowsInserted(QModelIndex,int,int))); - QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - QObject::disconnect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); - QObject::disconnect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); - d->m_abstractItemModel = 0; - } else if (d->m_visualItemModel) { - QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)), - this, SIGNAL(itemsInserted(int,int))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)), - this, SIGNAL(itemsRemoved(int,int))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), - this, SIGNAL(itemsMoved(int,int,int))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)), - this, SLOT(_q_createdPackage(int,QDeclarativePackage*))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)), - this, SLOT(_q_destroyingPackage(QDeclarativePackage*))); - d->m_visualItemModel = 0; - } - - d->m_roles.clear(); - d->m_roleNames.clear(); - if (d->m_delegateDataType) - d->m_delegateDataType->release(); - d->m_delegateDataType = 0; - d->createModelData = &QSGVisualDataModelPrivate::initializeModelData; - - QObject *object = qvariant_cast(model); - if (object && (d->m_listModelInterface = qobject_cast(object))) { - QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList)), - this, SLOT(_q_itemsChanged(int,int,QList))); - QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)), - this, SLOT(_q_itemsInserted(int,int))); - QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)), - this, SLOT(_q_itemsRemoved(int,int))); - QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)), - this, SLOT(_q_itemsMoved(int,int,int))); - if (d->m_delegate && d->m_listModelInterface->count()) - emit itemsInserted(0, d->m_listModelInterface->count()); - return; - } else if (object && (d->m_abstractItemModel = qobject_cast(object))) { - QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(_q_rowsInserted(QModelIndex,int,int))); - QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - 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())); - if (d->m_abstractItemModel->canFetchMore(d->m_root)) - d->m_abstractItemModel->fetchMore(d->m_root); - return; - } - if ((d->m_visualItemModel = qvariant_cast(model))) { - QObject::connect(d->m_visualItemModel, SIGNAL(countChanged()), - this, SIGNAL(countChanged())); - QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)), - this, SIGNAL(itemsInserted(int,int))); - QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)), - this, SIGNAL(itemsRemoved(int,int))); - QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), - this, SIGNAL(itemsMoved(int,int,int))); - QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QDeclarativePackage*)), - this, SLOT(_q_createdPackage(int,QDeclarativePackage*))); - QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QDeclarativePackage*)), - this, SLOT(_q_destroyingPackage(QDeclarativePackage*))); - return; - } - 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) - if (d->m_delegate && d->modelCount()) { - emit itemsInserted(0, d->modelCount()); - emit countChanged(); - } -} - -/*! - \qmlproperty Component QtQuick2::VisualDataModel::delegate - - The delegate provides a template defining each item instantiated by a view. - The index is exposed as an accessible \c index property. Properties of the - model are also available depending upon the type of \l {qmlmodels}{Data Model}. -*/ -QDeclarativeComponent *QSGVisualDataModel::delegate() const -{ - Q_D(const QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->delegate(); - return d->m_delegate; -} - -void QSGVisualDataModel::setDelegate(QDeclarativeComponent *delegate) -{ - Q_D(QSGVisualDataModel); - bool wasValid = d->m_delegate != 0; - d->m_delegate = delegate; - d->m_delegateValidated = false; - if (!wasValid && d->modelCount() && d->m_delegate) { - emit itemsInserted(0, d->modelCount()); - emit countChanged(); - } - if (wasValid && !d->m_delegate && d->modelCount()) { - _q_itemsRemoved(0, d->modelCount()); - emit countChanged(); - } -} - -/*! - \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex - - QAbstractItemModel provides a hierarchical tree of data, whereas - QML only operates on list data. \c rootIndex allows the children of - any node in a QAbstractItemModel to be provided by this model. - - This property only affects models of type QAbstractItemModel that - are hierarchical (e.g, a tree model). - - For example, here is a simple interactive file system browser. - When a directory name is clicked, the view's \c rootIndex is set to the - QModelIndex node of the clicked directory, thus updating the view to show - the new directory's contents. - - \c main.cpp: - \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0 - - \c view.qml: - \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0 - - If the \l model is a QAbstractItemModel subclass, the delegate can also - reference a \c hasModelChildren property (optionally qualified by a - \e model. prefix) that indicates whether the delegate's model item has - any child nodes. - - - \sa modelIndex(), parentModelIndex() -*/ -QVariant QSGVisualDataModel::rootIndex() const -{ - Q_D(const QSGVisualDataModel); - return QVariant::fromValue(d->m_root); -} - -void QSGVisualDataModel::setRootIndex(const QVariant &root) -{ - Q_D(QSGVisualDataModel); - QModelIndex modelIndex = qvariant_cast(root); - if (d->m_root != modelIndex) { - int oldCount = d->modelCount(); - d->m_root = modelIndex; - if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex)) - d->m_abstractItemModel->fetchMore(modelIndex); - int newCount = d->modelCount(); - if (d->m_delegate && oldCount) - _q_itemsRemoved(0, oldCount); - if (d->m_delegate && newCount) - emit itemsInserted(0, newCount); - if (newCount != oldCount) - emit countChanged(); - emit rootIndexChanged(); - } -} - -/*! - \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index) - - QAbstractItemModel provides a hierarchical tree of data, whereas - QML only operates on list data. This function assists in using - tree models in QML. - - Returns a QModelIndex for the specified index. - This value can be assigned to rootIndex. - - \sa rootIndex -*/ -QVariant QSGVisualDataModel::modelIndex(int idx) const -{ - Q_D(const QSGVisualDataModel); - if (d->m_abstractItemModel) - return QVariant::fromValue(d->m_abstractItemModel->index(idx, 0, d->m_root)); - return QVariant::fromValue(QModelIndex()); -} - -/*! - \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex() - - QAbstractItemModel provides a hierarchical tree of data, whereas - QML only operates on list data. This function assists in using - tree models in QML. - - Returns a QModelIndex for the parent of the current rootIndex. - This value can be assigned to rootIndex. - - \sa rootIndex -*/ -QVariant QSGVisualDataModel::parentModelIndex() const -{ - Q_D(const QSGVisualDataModel); - if (d->m_abstractItemModel) - return QVariant::fromValue(d->m_abstractItemModel->parent(d->m_root)); - return QVariant::fromValue(QModelIndex()); -} - -/*! - \qmlproperty object QtQuick2::VisualDataModel::parts - - The \a parts property selects a VisualDataModel which creates - delegates from the part named. This is used in conjunction with - the \l Package element. - - For example, the code below selects a model which creates - delegates named \e list from a \l Package: - - \code - VisualDataModel { - id: visualModel - delegate: Package { - Item { Package.name: "list" } - } - model: myModel - } - - ListView { - width: 200; height:200 - model: visualModel.parts.list - } - \endcode - - \sa Package -*/ -QString QSGVisualDataModel::part() const -{ - Q_D(const QSGVisualDataModel); - return d->m_part; -} - -void QSGVisualDataModel::setPart(const QString &part) -{ - Q_D(QSGVisualDataModel); - d->m_part = part; -} - -int QSGVisualDataModel::count() const -{ - Q_D(const QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->count(); - if (!d->m_delegate) - return 0; - return d->modelCount(); -} - -QSGItem *QSGVisualDataModel::item(int index, bool complete) -{ - Q_D(QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->item(index, d->m_part.toUtf8(), complete); - return item(index, QByteArray(), complete); -} - -/* - Returns ReleaseStatus flags. -*/ -QSGVisualDataModel::ReleaseFlags QSGVisualDataModel::release(QSGItem *item) -{ - Q_D(QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->release(item); - - ReleaseFlags stat = 0; - QObject *obj = item; - bool inPackage = false; - - QHash::iterator it = d->m_packaged.find(item); - if (it != d->m_packaged.end()) { - QDeclarativePackage *package = *it; - d->m_packaged.erase(it); - if (d->m_packaged.contains(item)) - stat |= Referenced; - inPackage = true; - obj = package; // fall through and delete - } - - if (d->m_cache.releaseItem(obj)) { - // Remove any bindings to avoid warnings due to parent change. - QObjectPrivate *p = QObjectPrivate::get(obj); - Q_ASSERT(p->declarativeData); - QDeclarativeData *d = static_cast(p->declarativeData); - if (d->ownContext && d->context) - d->context->clearContext(); - - if (inPackage) { - emit destroyingPackage(qobject_cast(obj)); - } else { - // XXX todo - the original did item->scene()->removeItem(). Why? - item->setParentItem(0); - } - stat |= Destroyed; - obj->deleteLater(); - } else if (!inPackage) { - stat |= Referenced; - } - - return stat; -} - -QObject *QSGVisualDataModel::parts() -{ - Q_D(QSGVisualDataModel); - if (!d->m_parts) - d->m_parts = new QSGVisualDataModelParts(this); - return d->m_parts; -} - -QSGItem *QSGVisualDataModel::item(int index, const QByteArray &viewId, bool complete) -{ - Q_D(QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->item(index, viewId, complete); - - if (d->modelCount() <= 0 || !d->m_delegate) - return 0; - QObject *nobj = d->m_cache.getItem(index); - bool needComplete = false; - if (!nobj) { - QDeclarativeContext *ccontext = d->m_context; - if (!ccontext) ccontext = qmlContext(this); - QDeclarativeContext *ctxt = new QDeclarativeContext(ccontext); - 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; - nobj = d->m_delegate->beginCreate(ctxt); - if (complete) { - d->m_delegate->completeCreate(); - } else { - d->m_completePending = true; - needComplete = true; - } - if (nobj) { - QDeclarative_setParent_noEvent(ctxt, nobj); - QDeclarative_setParent_noEvent(data, nobj); - d->m_cache.insertItem(index, nobj); - if (QDeclarativePackage *package = qobject_cast(nobj)) - emit createdPackage(index, package); - } else { - delete data; - delete ctxt; - qmlInfo(this, d->m_delegate->errors()) << "Error creating delegate"; - } - } - QSGItem *item = qobject_cast(nobj); - if (!item) { - QDeclarativePackage *package = qobject_cast(nobj); - if (package) { - QObject *o = package->part(QString::fromUtf8(viewId)); - item = qobject_cast(o); - if (item) - d->m_packaged.insertMulti(item, package); - } - } - if (!item) { - if (needComplete) - d->m_delegate->completeCreate(); - d->m_cache.releaseItem(nobj); - if (!d->m_delegateValidated) { - qmlInfo(d->m_delegate) << QSGVisualDataModel::tr("Delegate component must be Item type."); - d->m_delegateValidated = true; - } - } - if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root)) - d->m_abstractItemModel->fetchMore(d->m_root); - - return item; -} - -bool QSGVisualDataModel::completePending() const -{ - Q_D(const QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->completePending(); - return d->m_completePending; -} - -void QSGVisualDataModel::completeItem() -{ - Q_D(QSGVisualDataModel); - if (d->m_visualItemModel) { - d->m_visualItemModel->completeItem(); - return; - } - - d->m_delegate->completeCreate(); - d->m_completePending = false; -} - -QString QSGVisualDataModel::stringValue(int index, const QString &name) -{ - Q_D(QSGVisualDataModel); - if (d->m_visualItemModel) - return d->m_visualItemModel->stringValue(index, name); - - if ((!d->m_listModelInterface || !d->m_abstractItemModel) && d->m_listAccessor) { - if (QObject *object = d->m_listAccessor->at(index).value()) - return object->property(name.toUtf8()).toString(); - } - - if ((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate) - return QString(); - - QString val; - QObject *data = 0; - bool tempData = false; - - if (QObject *nobj = d->m_cache.item(index)) - data = d->data(nobj); - if (!data) { - data = d->createModelData(index, this); - tempData = true; - } - - QDeclarativeData *ddata = QDeclarativeData::get(data); - if (ddata && ddata->propertyCache) { - QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name); - if (prop) { - if (prop->propType == QVariant::String) { - void *args[] = { &val, 0 }; - QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args); - } else if (prop->propType == qMetaTypeId()) { - QVariant v; - void *args[] = { &v, 0 }; - QMetaObject::metacall(data, QMetaObject::ReadProperty, prop->coreIndex, args); - val = v.toString(); - } - } else { - val = data->property(name.toUtf8()).toString(); - } - } else { - val = data->property(name.toUtf8()).toString(); - } - - if (tempData) - delete data; - - return val; -} - -int QSGVisualDataModel::indexOf(QSGItem *item, QObject *) const -{ - QVariant val = QDeclarativeEngine::contextForObject(item)->contextProperty(QLatin1String("index")); - return val.toInt(); - return -1; -} - -void QSGVisualDataModel::setWatchedRoles(QList roles) -{ - Q_D(QSGVisualDataModel); - d->watchedRoles = roles; - d->watchedRoleIds.clear(); -} - -void QSGVisualDataModel::_q_itemsChanged(int index, int count, - const QList &roles) -{ - Q_D(QSGVisualDataModel); - bool changed = false; - if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) { - foreach (QByteArray r, d->watchedRoles) { - if (d->m_roleNames.contains(r)) - d->watchedRoleIds << d->m_roleNames.value(r); - } - } - - 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(); - - if (idx >= index && idx < index+count) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - QSGVisualDataModelData *data = d->data(objRef.obj); - for (int i = 0; i < signalIndexes.count(); ++i) - QMetaObject::activate(data, signalIndexes.at(i), 0); - } - } - if (changed) - emit itemsChanged(index, count); -} - -void QSGVisualDataModel::_q_itemsInserted(int index, int count) -{ - Q_D(QSGVisualDataModel); - if (!count) - return; - // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - if (iter.key() >= index) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - int index = iter.key() + count; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualDataModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - d->m_cache.unite(items); - - emit itemsInserted(index, count); - emit countChanged(); -} - -void QSGVisualDataModel::_q_itemsRemoved(int index, int count) -{ - Q_D(QSGVisualDataModel); - if (!count) - return; - // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - if (iter.key() >= index && iter.key() < index + count) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - iter = d->m_cache.erase(iter); - items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately - QSGVisualDataModelData *data = d->data(objRef.obj); - data->setIndex(-1); - } else if (iter.key() >= index + count) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - int index = iter.key() - count; - iter = d->m_cache.erase(iter); - items.insert(index, objRef); - QSGVisualDataModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - - d->m_cache.unite(items); - emit itemsRemoved(index, count); - emit countChanged(); -} - -void QSGVisualDataModel::_q_itemsMoved(int from, int to, int count) -{ - Q_D(QSGVisualDataModel); - // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - if (iter.key() >= from && iter.key() < from + count) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - int index = iter.key() - from + to; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualDataModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - for (QHash::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ) { - - int diff = from > to ? count : -count; - if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) { - QSGVisualDataModelPrivate::ObjectRef objRef = *iter; - int index = iter.key() + diff; - iter = d->m_cache.erase(iter); - - items.insert(index, objRef); - - QSGVisualDataModelData *data = d->data(objRef.obj); - data->setIndex(index); - } else { - ++iter; - } - } - d->m_cache.unite(items); - - emit itemsMoved(from, to, count); -} - -void QSGVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end) -{ - Q_D(QSGVisualDataModel); - if (parent == d->m_root) - _q_itemsInserted(begin, end - begin + 1); -} - -void QSGVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end) -{ - Q_D(QSGVisualDataModel); - if (parent == d->m_root) - _q_itemsRemoved(begin, end - begin + 1); -} - -void QSGVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) -{ - Q_D(QSGVisualDataModel); - const int count = sourceEnd - sourceStart + 1; - if (destinationParent == d->m_root && sourceParent == d->m_root) { - _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow-count, count); - } else if (sourceParent == d->m_root) { - _q_itemsRemoved(sourceStart, count); - } else if (destinationParent == d->m_root) { - _q_itemsInserted(destinationRow, count); - } -} - -void QSGVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end) -{ - Q_D(QSGVisualDataModel); - if (begin.parent() == d->m_root) - _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); -} - -void QSGVisualDataModel::_q_layoutChanged() -{ - Q_D(QSGVisualDataModel); - _q_itemsChanged(0, count(), d->m_roles); -} - -void QSGVisualDataModel::_q_modelReset() -{ - Q_D(QSGVisualDataModel); - d->m_root = QModelIndex(); - emit modelReset(); - emit rootIndexChanged(); - if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root)) - d->m_abstractItemModel->fetchMore(d->m_root); -} - -void QSGVisualDataModel::_q_createdPackage(int index, QDeclarativePackage *package) -{ - Q_D(QSGVisualDataModel); - emit createdItem(index, qobject_cast(package->part(d->m_part))); -} - -void QSGVisualDataModel::_q_destroyingPackage(QDeclarativePackage *package) -{ - Q_D(QSGVisualDataModel); - emit destroyingItem(qobject_cast(package->part(d->m_part))); -} - QT_END_NAMESPACE -QML_DECLARE_TYPE(QListModelInterface) - -#include diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h index 9acaab6..2eeff3c 100644 --- a/src/declarative/items/qsgvisualitemmodel_p.h +++ b/src/declarative/items/qsgvisualitemmodel_p.h @@ -45,20 +45,14 @@ #include #include -#include QT_BEGIN_HEADER -Q_DECLARE_METATYPE(QModelIndex) - QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QSGItem; -class QDeclarativeComponent; -class QDeclarativePackage; -class QSGVisualDataModelPrivate; class Q_DECLARATIVE_EXPORT QSGVisualModel : public QObject { @@ -137,75 +131,6 @@ private: Q_DISABLE_COPY(QSGVisualItemModel) }; - -class Q_DECLARATIVE_EXPORT QSGVisualDataModel : public QSGVisualModel -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QSGVisualDataModel) - - Q_PROPERTY(QVariant model READ model WRITE setModel) - Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate) - Q_PROPERTY(QString part READ part WRITE setPart) - Q_PROPERTY(QObject *parts READ parts CONSTANT) - Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged) - Q_CLASSINFO("DefaultProperty", "delegate") -public: - QSGVisualDataModel(); - QSGVisualDataModel(QDeclarativeContext *, QObject *parent=0); - virtual ~QSGVisualDataModel(); - - QVariant model() const; - void setModel(const QVariant &); - - QDeclarativeComponent *delegate() const; - void setDelegate(QDeclarativeComponent *); - - QVariant rootIndex() const; - void setRootIndex(const QVariant &root); - - Q_INVOKABLE QVariant modelIndex(int idx) const; - Q_INVOKABLE QVariant parentModelIndex() const; - - QString part() const; - void setPart(const QString &); - - int count() const; - bool isValid() const { return delegate() != 0; } - QSGItem *item(int index, bool complete=true); - QSGItem *item(int index, const QByteArray &, bool complete=true); - ReleaseFlags release(QSGItem *item); - bool completePending() const; - void completeItem(); - virtual QString stringValue(int index, const QString &role); - virtual void setWatchedRoles(QList roles); - - int indexOf(QSGItem *item, QObject *objectContext) const; - - QObject *parts(); - -Q_SIGNALS: - void createdPackage(int index, QDeclarativePackage *package); - void destroyingPackage(QDeclarativePackage *package); - void rootIndexChanged(); - -private Q_SLOTS: - void _q_itemsChanged(int, int, const QList &); - void _q_itemsInserted(int index, int count); - void _q_itemsRemoved(int index, int count); - void _q_itemsMoved(int from, int to, int count); - void _q_rowsInserted(const QModelIndex &,int,int); - void _q_rowsRemoved(const QModelIndex &,int,int); - void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); - void _q_dataChanged(const QModelIndex&,const QModelIndex&); - void _q_layoutChanged(); - void _q_modelReset(); - void _q_createdPackage(int index, QDeclarativePackage *package); - void _q_destroyingPackage(QDeclarativePackage *package); - -private: - Q_DISABLE_COPY(QSGVisualDataModel) -}; - class QSGVisualItemModelAttached : public QObject { Q_OBJECT @@ -250,7 +175,6 @@ QT_END_NAMESPACE QML_DECLARE_TYPE(QSGVisualModel) QML_DECLARE_TYPE(QSGVisualItemModel) QML_DECLARE_TYPEINFO(QSGVisualItemModel, QML_HAS_ATTACHED_PROPERTIES) -QML_DECLARE_TYPE(QSGVisualDataModel) QT_END_HEADER diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml b/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml index 0bb5cd1..0d4d9e2 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml +++ b/tests/auto/declarative/qsgvisualdatamodel/data/visualdatamodel.qml @@ -8,4 +8,5 @@ VisualDataModel { rootIndex = parentModelIndex(); } model: myModel + delegate: Item {} } diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp index 61a6314..a2e6d95 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp +++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp @@ -49,7 +49,7 @@ #include #include #include -#include +#include #include #include #include