aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickvisualdatamodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickvisualdatamodel.cpp')
-rw-r--r--src/quick/items/qquickvisualdatamodel.cpp2668
1 files changed, 2668 insertions, 0 deletions
diff --git a/src/quick/items/qquickvisualdatamodel.cpp b/src/quick/items/qquickvisualdatamodel.cpp
new file mode 100644
index 0000000000..649ca6f96b
--- /dev/null
+++ b/src/quick/items/qquickvisualdatamodel.cpp
@@ -0,0 +1,2668 @@
+/****************************************************************************
+**
+** 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 "qquickvisualdatamodel_p.h"
+#include "qquickitem.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtDeclarative/qdeclarativeincubator.h>
+
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativepackage_p.h>
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativelistaccessor_p.h>
+#include <private/qdeclarativedata_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qquickvisualadaptormodel_p.h>
+#include <private/qdeclarativechangeset_p.h>
+#include <private/qdeclarativelistcompositor_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qquickitem_p.h>
+#include <private/qobject_p.h>
+
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef QDeclarativeListCompositor Compositor;
+
+class QQuickVisualDataModelPrivate;
+class QVDMIncubationTask : public QDeclarativeIncubator
+{
+public:
+ QVDMIncubationTask(QQuickVisualDataModelPrivate *l, IncubationMode mode)
+ : QDeclarativeIncubator(mode)
+ , incubating(0)
+ , incubatingContext(0)
+ , vdm(l) {}
+
+ virtual void statusChanged(Status);
+ virtual void setInitialState(QObject *);
+
+ QQuickVisualDataModelCacheItem *incubating;
+ QDeclarativeContext *incubatingContext;
+
+private:
+ QQuickVisualDataModelPrivate *vdm;
+};
+
+
+class QQuickVisualDataGroupEmitter
+{
+public:
+ virtual void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset) = 0;
+ virtual void createdPackage(int, QDeclarativePackage *) {}
+ virtual void initPackage(int, QDeclarativePackage *) {}
+ virtual void destroyingPackage(QDeclarativePackage *) {}
+
+ QIntrusiveListNode emitterNode;
+};
+
+typedef QIntrusiveList<QQuickVisualDataGroupEmitter, &QQuickVisualDataGroupEmitter::emitterNode> QQuickVisualDataGroupEmitterList;
+
+//---------------------------------------------------------------------------
+
+class QQuickVisualDataGroupPrivate : public QObjectPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QQuickVisualDataGroup)
+
+ QQuickVisualDataGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
+
+ static QQuickVisualDataGroupPrivate *get(QQuickVisualDataGroup *group) {
+ return static_cast<QQuickVisualDataGroupPrivate *>(QObjectPrivate::get(group)); }
+
+ void setModel(QQuickVisualDataModel *model, Compositor::Group group);
+ void emitChanges(QV8Engine *engine);
+ void emitModelUpdated(bool reset);
+
+ void createdPackage(int index, QDeclarativePackage *package);
+ void initPackage(int index, QDeclarativePackage *package);
+ void destroyingPackage(QDeclarativePackage *package);
+
+ bool parseGroupArgs(QDeclarativeV8Function *args, int *index, int *count, int *groups) const;
+
+ Compositor::Group group;
+ QDeclarativeGuard<QQuickVisualDataModel> model;
+ QQuickVisualDataGroupEmitterList emitters;
+ QDeclarativeChangeSet changeSet;
+ QString name;
+ bool defaultInclude;
+};
+
+//---------------------------------------------------------------------------
+
+class QQuickVisualDataModelCacheItem;
+class QQuickVisualDataModelCacheMetaType;
+class QQuickVisualDataModelParts;
+
+class QQuickVisualDataModelCacheMetaType : public QDeclarativeRefCount
+{
+public:
+ QQuickVisualDataModelCacheMetaType(QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames);
+ ~QQuickVisualDataModelCacheMetaType();
+
+ int parseGroups(const QStringList &groupNames) const;
+ int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
+
+ static v8::Handle<v8::Value> get_model(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_groups(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_groups(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_member(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_member(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info);
+
+ QDeclarativeGuard<QQuickVisualDataModel> model;
+ const int groupCount;
+ const int memberPropertyOffset;
+ const int indexPropertyOffset;
+ QV8Engine * const v8Engine;
+ QMetaObject *metaObject;
+ const QStringList groupNames;
+ v8::Persistent<v8::Function> constructor;
+};
+
+class QQuickVisualDataModelCacheItem : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(VisualDataItemType)
+public:
+ QQuickVisualDataModelCacheItem(QQuickVisualDataModelCacheMetaType *metaType)
+ : QV8ObjectResource(metaType->v8Engine)
+ , metaType(metaType)
+ , object(0)
+ , attached(0)
+ , objectRef(0)
+ , scriptRef(0)
+ , groups(0)
+ , incubationTask(0)
+ {
+ metaType->addref();
+ }
+
+ ~QQuickVisualDataModelCacheItem();
+
+ void referenceObject() { ++objectRef; }
+ bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
+ bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
+
+ bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag) || incubationTask; }
+
+ void Dispose();
+
+ QQuickVisualDataModelCacheMetaType * const metaType;
+ QDeclarativeGuard<QObject> object;
+ QQuickVisualDataModelAttached *attached;
+ int objectRef;
+ int scriptRef;
+ int groups;
+ int index[Compositor::MaximumGroupCount];
+ QVDMIncubationTask *incubationTask;
+};
+
+
+class QQuickVisualDataModelPrivate : public QObjectPrivate, public QQuickVisualDataGroupEmitter
+{
+ Q_DECLARE_PUBLIC(QQuickVisualDataModel)
+public:
+ QQuickVisualDataModelPrivate(QDeclarativeContext *);
+ ~QQuickVisualDataModelPrivate();
+
+ static QQuickVisualDataModelPrivate *get(QQuickVisualDataModel *m) {
+ return static_cast<QQuickVisualDataModelPrivate *>(QObjectPrivate::get(m));
+ }
+
+ void init();
+ void connectModel(QQuickVisualAdaptorModel *model);
+
+ QObject *object(Compositor::Group group, int index, bool asynchronous, bool reference);
+ void destroy(QObject *object);
+ QQuickVisualDataModel::ReleaseFlags release(QObject *object);
+ QString stringValue(Compositor::Group group, int index, const QString &name);
+ int cacheIndexOf(QObject *object) const;
+ void emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
+ void emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
+ void emitCreatedItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
+ emit q_func()->createdItem(cacheItem->index[m_compositorGroup], item); }
+ void emitInitItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
+ emit q_func()->initItem(cacheItem->index[m_compositorGroup], item); }
+ void emitDestroyingPackage(QDeclarativePackage *package);
+ void emitDestroyingItem(QQuickItem *item) { emit q_func()->destroyingItem(item); }
+
+ void updateFilterGroup();
+
+ void addGroups(Compositor::Group group, int index, int count, int groupFlags);
+ void removeGroups(Compositor::Group group, int index, int count, int groupFlags);
+ void setGroups(Compositor::Group group, int index, int count, int groupFlags);
+
+ void itemsInserted(
+ const QVector<Compositor::Insert> &inserts,
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
+ QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems = 0);
+ void itemsInserted(const QVector<Compositor::Insert> &inserts);
+ void itemsRemoved(
+ const QVector<Compositor::Remove> &removes,
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
+ QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems = 0);
+ void itemsRemoved(const QVector<Compositor::Remove> &removes);
+ void itemsMoved(
+ const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts);
+ void itemsChanged(const QVector<Compositor::Change> &changes);
+ template <typename T> static v8::Local<v8::Array> buildChangeList(const QVector<T> &changes);
+ void emitChanges();
+ void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
+
+
+ static void group_append(QDeclarativeListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group);
+ static int group_count(QDeclarativeListProperty<QQuickVisualDataGroup> *property);
+ static QQuickVisualDataGroup *group_at(QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index);
+
+ void releaseIncubator(QVDMIncubationTask *incubationTask);
+ void incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status);
+ void setInitialState(QVDMIncubationTask *incubationTask, QObject *o);
+
+ QQuickVisualAdaptorModel *m_adaptorModel;
+ QDeclarativeComponent *m_delegate;
+ QQuickVisualDataModelCacheMetaType *m_cacheMetaType;
+ QDeclarativeGuard<QDeclarativeContext> m_context;
+
+ QList<QQuickVisualDataModelCacheItem *> m_cache;
+ QQuickVisualDataModelParts *m_parts;
+ QQuickVisualDataGroupEmitterList m_pendingParts;
+
+ QDeclarativeListCompositor m_compositor;
+ QDeclarativeListCompositor::Group m_compositorGroup;
+ bool m_complete : 1;
+ bool m_delegateValidated : 1;
+ bool m_reset : 1;
+ bool m_transaction : 1;
+ bool m_incubatorCleanupScheduled : 1;
+
+ QString m_filterGroup;
+ QList<QByteArray> watchedRoles;
+
+ union {
+ struct {
+ QQuickVisualDataGroup *m_cacheItems;
+ QQuickVisualDataGroup *m_items;
+ QQuickVisualDataGroup *m_persistedItems;
+ };
+ QQuickVisualDataGroup *m_groups[Compositor::MaximumGroupCount];
+ };
+ int m_groupCount;
+
+ QList<QVDMIncubationTask *> m_finishedIncubating;
+};
+
+//---------------------------------------------------------------------------
+
+class QQuickVisualPartsModel : public QQuickVisualModel, public QQuickVisualDataGroupEmitter
+{
+ Q_OBJECT
+ Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
+public:
+ QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent = 0);
+ ~QQuickVisualPartsModel();
+
+ QString filterGroup() const;
+ void setFilterGroup(const QString &group);
+ void resetFilterGroup();
+ void updateFilterGroup();
+ void updateFilterGroup(Compositor::Group group, const QDeclarativeChangeSet &changeSet);
+
+ int count() const;
+ bool isValid() const;
+ QQuickItem *item(int index, bool asynchronous=false);
+ ReleaseFlags release(QQuickItem *item);
+ QString stringValue(int index, const QString &role);
+ void setWatchedRoles(QList<QByteArray> roles);
+
+ int indexOf(QQuickItem *item, QObject *objectContext) const;
+
+ void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
+
+ void createdPackage(int index, QDeclarativePackage *package);
+ void initPackage(int index, QDeclarativePackage *package);
+ void destroyingPackage(QDeclarativePackage *package);
+
+Q_SIGNALS:
+ void filterGroupChanged();
+
+private:
+ QQuickVisualDataModel *m_model;
+ QHash<QObject *, QDeclarativePackage *> m_packaged;
+ QString m_part;
+ QString m_filterGroup;
+ QList<QByteArray> m_watchedRoles;
+ Compositor::Group m_compositorGroup;
+ bool m_inheritGroup;
+};
+
+class QQuickVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ QQuickVisualDataModelPartsMetaObject(QObject *parent)
+ : QDeclarativeOpenMetaObject(parent) {}
+
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+ virtual QVariant initialValue(int);
+};
+
+class QQuickVisualDataModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QQuickVisualDataModelParts(QQuickVisualDataModel *parent);
+
+ QQuickVisualDataModel *model;
+ QList<QQuickVisualPartsModel *> models;
+};
+
+void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+}
+
+QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
+{
+ QQuickVisualDataModelParts *parts = static_cast<QQuickVisualDataModelParts *>(object());
+ QQuickVisualPartsModel *m = new QQuickVisualPartsModel(
+ parts->model, QString::fromUtf8(name(id)), parts);
+ parts->models.append(m);
+ return QVariant::fromValue(static_cast<QObject *>(m));
+}
+
+QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
+: QObject(parent), model(parent)
+{
+ new QQuickVisualDataModelPartsMetaObject(this);
+}
+
+class QQuickVisualDataModelAttachedMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QQuickVisualDataModelAttachedMetaObject(
+ QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType);
+ ~QQuickVisualDataModelAttachedMetaObject();
+
+ int metaCall(QMetaObject::Call, int _id, void **);
+
+private:
+ QQuickVisualDataModelAttached *attached;
+ QQuickVisualDataModelCacheMetaType *metaType;
+};
+
+//---------------------------------------------------------------------------
+
+QHash<QObject*, QQuickVisualDataModelAttached*> QQuickVisualDataModelAttached::attachedProperties;
+
+/*!
+ \qmlclass VisualDataModel QQuickVisualDataModel
+ \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
+*/
+
+QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QDeclarativeContext *ctxt)
+ : m_adaptorModel(0)
+ , m_delegate(0)
+ , m_cacheMetaType(0)
+ , m_context(ctxt)
+ , m_parts(0)
+ , m_compositorGroup(Compositor::Cache)
+ , m_complete(false)
+ , m_delegateValidated(false)
+ , m_reset(false)
+ , m_transaction(false)
+ , m_incubatorCleanupScheduled(false)
+ , m_filterGroup(QStringLiteral("items"))
+ , m_cacheItems(0)
+ , m_items(0)
+ , m_groupCount(3)
+{
+}
+
+QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
+{
+ qDeleteAll(m_finishedIncubating);
+}
+
+void QQuickVisualDataModelPrivate::connectModel(QQuickVisualAdaptorModel *model)
+{
+ Q_Q(QQuickVisualDataModel);
+
+ 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 QQuickVisualDataModelPrivate::init()
+{
+ Q_Q(QQuickVisualDataModel);
+ m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
+
+ m_adaptorModel = new QQuickVisualAdaptorModel;
+ QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged()));
+
+ m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
+ m_items->setDefaultInclude(true);
+ m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
+ QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
+}
+
+QQuickVisualDataModel::QQuickVisualDataModel()
+: QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
+{
+ Q_D(QQuickVisualDataModel);
+ d->init();
+}
+
+QQuickVisualDataModel::QQuickVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
+: QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
+{
+ Q_D(QQuickVisualDataModel);
+ d->init();
+}
+
+QQuickVisualDataModel::~QQuickVisualDataModel()
+{
+ Q_D(QQuickVisualDataModel);
+
+ foreach (QQuickVisualDataModelCacheItem *cacheItem, d->m_cache) {
+ delete cacheItem->object;
+ cacheItem->object = 0;
+ cacheItem->objectRef = 0;
+ if (!cacheItem->isReferenced())
+ delete cacheItem;
+ }
+
+ delete d->m_adaptorModel;
+ if (d->m_cacheMetaType)
+ d->m_cacheMetaType->release();
+}
+
+
+void QQuickVisualDataModel::classBegin()
+{
+}
+
+void QQuickVisualDataModel::componentComplete()
+{
+ Q_D(QQuickVisualDataModel);
+ d->m_complete = true;
+
+ int defaultGroups = 0;
+ QStringList groupNames;
+ groupNames.append(QStringLiteral("items"));
+ groupNames.append(QStringLiteral("persistedItems"));
+ if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
+ defaultGroups |= Compositor::DefaultFlag;
+ if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
+ defaultGroups |= Compositor::PersistedFlag;
+ for (int i = 3; i < d->m_groupCount; ++i) {
+ QString name = d->m_groups[i]->name();
+ if (name.isEmpty()) {
+ d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
+ --d->m_groupCount;
+ --i;
+ } else if (name.at(0).isUpper()) {
+ qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
+ d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
+ --d->m_groupCount;
+ --i;
+ } else {
+ groupNames.append(name);
+
+ QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
+ group->setModel(this, Compositor::Group(i));
+ if (group->defaultInclude)
+ defaultGroups |= (1 << i);
+ }
+ }
+ if (!d->m_context)
+ d->m_context = qmlContext(this);
+
+ d->m_cacheMetaType = new QQuickVisualDataModelCacheMetaType(
+ QDeclarativeEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
+
+ d->m_compositor.setGroupCount(d->m_groupCount);
+ d->m_compositor.setDefaultGroups(defaultGroups);
+ d->updateFilterGroup();
+
+ while (!d->m_pendingParts.isEmpty())
+ static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
+
+ d->connectModel(d->m_adaptorModel);
+ QVector<Compositor::Insert> inserts;
+ d->m_reset = true;
+ d->m_compositor.append(
+ d->m_adaptorModel,
+ 0,
+ qMax(0, d->m_adaptorModel->count()),
+ defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
+ &inserts);
+ d->itemsInserted(inserts);
+ d->emitChanges();
+
+ if (d->m_adaptorModel->canFetchMore())
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+}
+
+/*!
+ \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 QQuickVisualDataModel::model() const
+{
+ Q_D(const QQuickVisualDataModel);
+ return d->m_adaptorModel->model();
+}
+
+void QQuickVisualDataModel::setModel(const QVariant &model)
+{
+ Q_D(QQuickVisualDataModel);
+ d->m_adaptorModel->setModel(model, d->m_context ? d->m_context->engine() : qmlEngine(this));
+ if (d->m_complete && 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 *QQuickVisualDataModel::delegate() const
+{
+ Q_D(const QQuickVisualDataModel);
+ return d->m_delegate;
+}
+
+void QQuickVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
+{
+ Q_D(QQuickVisualDataModel);
+ if (d->m_transaction) {
+ qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
+ return;
+ }
+ bool wasValid = d->m_delegate != 0;
+ d->m_delegate = delegate;
+ d->m_delegateValidated = false;
+ if (wasValid && d->m_complete) {
+ for (int i = 1; i < d->m_groupCount; ++i) {
+ QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
+ 0, d->m_compositor.count(Compositor::Group(i)));
+ }
+ }
+ if (d->m_complete && d->m_delegate) {
+ for (int i = 1; i < d->m_groupCount; ++i) {
+ QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
+ 0, d->m_compositor.count(Compositor::Group(i)));
+ }
+ }
+ d->emitChanges();
+}
+
+/*!
+ \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 QQuickVisualDataModel::rootIndex() const
+{
+ Q_D(const QQuickVisualDataModel);
+ return d->m_adaptorModel->rootIndex();
+}
+
+void QQuickVisualDataModel::setRootIndex(const QVariant &root)
+{
+ Q_D(QQuickVisualDataModel);
+ 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 QQuickVisualDataModel::modelIndex(int idx) const
+{
+ Q_D(const QQuickVisualDataModel);
+ 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 QQuickVisualDataModel::parentModelIndex() const
+{
+ Q_D(const QQuickVisualDataModel);
+ return d->m_adaptorModel->parentModelIndex();
+}
+
+/*!
+ \qmlproperty int QtQuick2::VisualDataModel::count
+*/
+
+int QQuickVisualDataModel::count() const
+{
+ Q_D(const QQuickVisualDataModel);
+ if (!d->m_delegate)
+ return 0;
+ return d->m_compositor.count(d->m_compositorGroup);
+}
+
+void QQuickVisualDataModelPrivate::destroy(QObject *object)
+{
+ QObjectPrivate *p = QObjectPrivate::get(object);
+ Q_ASSERT(p->declarativeData);
+ QDeclarativeData *data = static_cast<QDeclarativeData*>(p->declarativeData);
+ if (data->ownContext && data->context)
+ data->context->clearContext();
+ object->deleteLater();
+}
+
+QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
+{
+ QQuickVisualDataModel::ReleaseFlags stat = 0;
+ if (!object)
+ return stat;
+
+ int cacheIndex = cacheIndexOf(object);
+ if (cacheIndex != -1) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (cacheItem->releaseObject()) {
+ destroy(object);
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
+ emitDestroyingItem(item);
+ cacheItem->object = 0;
+ stat |= QQuickVisualModel::Destroyed;
+ if (!cacheItem->isReferenced()) {
+ m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
+ m_cache.removeAt(cacheIndex);
+ delete cacheItem;
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
+ } else {
+ stat |= QQuickVisualDataModel::Referenced;
+ }
+ }
+ return stat;
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+
+QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
+{
+ Q_D(QQuickVisualDataModel);
+ QQuickVisualModel::ReleaseFlags stat = d->release(item);
+ if (stat & Destroyed)
+ item->setParentItem(0);
+ return stat;
+}
+
+void QQuickVisualDataModelPrivate::group_append(
+ QDeclarativeListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
+{
+ QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
+ if (d->m_complete)
+ return;
+ if (d->m_groupCount == 11) {
+ qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
+ return;
+ }
+ d->m_groups[d->m_groupCount] = group;
+ d->m_groupCount += 1;
+}
+
+int QQuickVisualDataModelPrivate::group_count(
+ QDeclarativeListProperty<QQuickVisualDataGroup> *property)
+{
+ QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
+ return d->m_groupCount - 1;
+}
+
+QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
+ QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index)
+{
+ QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
+ return index >= 0 && index < d->m_groupCount - 1
+ ? d->m_groups[index + 1]
+ : 0;
+}
+
+/*!
+ \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
+
+ This property holds a visual data model's group definitions.
+
+ Groups define a sub-set of the items in a visual data model and can be used to filter
+ a model.
+
+ For every group defined in a VisualDataModel two attached properties are added to each
+ delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
+ item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
+ index of the item in that group.
+
+ The following example illustrates using groups to select items in a model.
+
+ \snippet doc/src/snippets/declarative/visualdatagroup.qml 0
+*/
+
+QDeclarativeListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
+{
+ Q_D(QQuickVisualDataModel);
+ return QDeclarativeListProperty<QQuickVisualDataGroup>(
+ this,
+ d,
+ QQuickVisualDataModelPrivate::group_append,
+ QQuickVisualDataModelPrivate::group_count,
+ QQuickVisualDataModelPrivate::group_at);
+}
+
+/*!
+ \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
+
+ This property holds visual data model's default group to which all new items are added.
+*/
+
+QQuickVisualDataGroup *QQuickVisualDataModel::items()
+{
+ Q_D(QQuickVisualDataModel);
+ return d->m_items;
+}
+
+/*!
+ \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
+
+ This property holds visual data model's persisted items group.
+
+ Items in this group are not destroyed when released by a view, instead they are persisted
+ until removed from the group.
+
+ An item can be removed from the persistedItems group by setting the
+ VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
+ at that time it will be destroyed. Adding an item to this group will not create a new
+ instance.
+
+ Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
+ to this group.
+*/
+
+QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
+{
+ Q_D(QQuickVisualDataModel);
+ return d->m_persistedItems;
+}
+
+/*!
+ \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
+
+ This property holds the name of the group used to filter the visual data model.
+
+ Only items which belong to this group are visible to a view.
+
+ By default this is the \l items group.
+*/
+
+QString QQuickVisualDataModel::filterGroup() const
+{
+ Q_D(const QQuickVisualDataModel);
+ return d->m_filterGroup;
+}
+
+void QQuickVisualDataModel::setFilterGroup(const QString &group)
+{
+ Q_D(QQuickVisualDataModel);
+
+ if (d->m_transaction) {
+ qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
+ return;
+ }
+
+ if (d->m_filterGroup != group) {
+ d->m_filterGroup = group;
+ d->updateFilterGroup();
+ emit filterGroupChanged();
+ }
+}
+
+void QQuickVisualDataModel::resetFilterGroup()
+{
+ setFilterGroup(QStringLiteral("items"));
+}
+
+void QQuickVisualDataModelPrivate::updateFilterGroup()
+{
+ Q_Q(QQuickVisualDataModel);
+ if (!m_cacheMetaType)
+ return;
+
+ QDeclarativeListCompositor::Group previousGroup = m_compositorGroup;
+ m_compositorGroup = Compositor::Default;
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
+ m_compositorGroup = Compositor::Group(i);
+ break;
+ }
+ }
+
+ QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
+ if (m_compositorGroup != previousGroup) {
+ QVector<QDeclarativeChangeSet::Remove> removes;
+ QVector<QDeclarativeChangeSet::Insert> inserts;
+ m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
+
+ QDeclarativeChangeSet changeSet;
+ changeSet.apply(removes, inserts);
+ emit q->modelUpdated(changeSet, false);
+
+ if (changeSet.difference() != 0)
+ emit q->countChanged();
+
+ if (m_parts) {
+ foreach (QQuickVisualPartsModel *model, m_parts->models)
+ model->updateFilterGroup(m_compositorGroup, changeSet);
+ }
+ }
+}
+
+/*!
+ \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 *QQuickVisualDataModel::parts()
+{
+ Q_D(QQuickVisualDataModel);
+ if (!d->m_parts)
+ d->m_parts = new QQuickVisualDataModelParts(this);
+ return d->m_parts;
+}
+
+void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
+{
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
+}
+
+void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
+{
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
+}
+
+void QQuickVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *package)
+{
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
+}
+
+void QVDMIncubationTask::statusChanged(Status status)
+{
+ vdm->incubatorStatusChanged(this, status);
+}
+
+void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
+{
+ Q_Q(QQuickVisualDataModel);
+ if (!incubationTask->isError())
+ incubationTask->clear();
+ m_finishedIncubating.append(incubationTask);
+ if (!m_incubatorCleanupScheduled) {
+ m_incubatorCleanupScheduled = true;
+ QCoreApplication::postEvent(q, new QEvent(QEvent::User));
+ }
+}
+
+void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status)
+{
+ Q_Q(QQuickVisualDataModel);
+ if (status != QDeclarativeIncubator::Ready && status != QDeclarativeIncubator::Error)
+ return;
+
+ QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
+ cacheItem->incubationTask = 0;
+
+ if (status == QDeclarativeIncubator::Ready) {
+ incubationTask->incubating = 0;
+ releaseIncubator(incubationTask);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitCreatedPackage(cacheItem, package);
+ else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
+ emitCreatedItem(cacheItem, item);
+ } else if (status == QDeclarativeIncubator::Error) {
+ delete incubationTask->incubatingContext;
+ incubationTask->incubatingContext = 0;
+ if (!cacheItem->isReferenced()) {
+ int cidx = m_cache.indexOf(cacheItem);
+ m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
+ m_cache.removeAt(cidx);
+ delete cacheItem;
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
+ releaseIncubator(incubationTask);
+ qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
+ }
+}
+
+void QVDMIncubationTask::setInitialState(QObject *o)
+{
+ vdm->setInitialState(this, o);
+}
+
+void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
+ cacheItem->object = o;
+ QDeclarative_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
+ incubationTask->incubatingContext = 0;
+
+ cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
+ cacheItem->attached->m_cacheItem = cacheItem;
+ new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
+ cacheItem->attached->emitChanges();
+
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitInitPackage(cacheItem, package);
+ else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
+ emitInitItem(cacheItem, item);
+}
+
+QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
+{
+ Q_Q(QQuickVisualDataModel);
+ if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
+ return 0;
+ }
+
+ Compositor::iterator it = m_compositor.find(group, index);
+ QQuickVisualDataModelCacheItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
+ if (!cacheItem) {
+ cacheItem = new QQuickVisualDataModelCacheItem(m_cacheMetaType);
+ for (int i = 0; i < m_groupCount; ++i)
+ cacheItem->index[i] = it.index[i];
+ cacheItem->groups = it->flags & Compositor::GroupMask;
+ }
+
+ int modelIndex = it.modelIndex();
+
+ if (!it->inCache()) {
+ m_cache.insert(it.cacheIndex, cacheItem);
+ m_compositor.setFlags(it, 1, Compositor::CacheFlag);
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
+
+ if (cacheItem->incubationTask) {
+ if (!asynchronous) {
+ // previously requested async - now needed immediately
+ cacheItem->incubationTask->forceCompletion();
+ }
+ } else if (!cacheItem->object) {
+ QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
+ cacheItem->incubationTask = incubator;
+
+ QObject *data = m_adaptorModel->data(modelIndex);
+
+ QDeclarativeContext *creationContext = m_delegate->creationContext();
+ QDeclarativeContext *rootContext = new QDeclarativeContext(
+ creationContext ? creationContext : m_context.data());
+ QDeclarativeContext *ctxt = rootContext;
+ if (m_adaptorModel->flags() & QQuickVisualAdaptorModel::ProxiedObject) {
+ if (QQuickVisualAdaptorModelProxyInterface *proxy = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(data)) {
+ ctxt->setContextObject(proxy->proxiedObject());
+ ctxt = new QDeclarativeContext(ctxt, ctxt);
+ }
+ }
+
+ QDeclarative_setParent_noEvent(data, ctxt);
+ ctxt->setContextProperty(QLatin1String("model"), data);
+ ctxt->setContextObject(data);
+
+ incubator->incubating = cacheItem;
+ incubator->incubatingContext = rootContext;
+ m_delegate->create(*incubator, ctxt, m_context);
+ }
+
+ if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
+ QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
+ if (cacheItem->object && reference)
+ cacheItem->referenceObject();
+ return cacheItem->object;
+}
+
+/*
+ If asynchronous is true or the component is being loaded asynchronously due
+ to an ancestor being loaded asynchronously, item() may return 0. In this
+ case itemCreated() will be emitted when the item is available. The item
+ at this stage does not have any references, so item() must be called again
+ to ensure a reference is held. Any call to item() which returns a valid item
+ must be matched by a call to release() in order to destroy the item.
+*/
+QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
+{
+ Q_D(QQuickVisualDataModel);
+ if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
+ return 0;
+ }
+
+ QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
+ if (!object)
+ return 0;
+
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
+ return item;
+
+ d->release(object);
+ if (!d->m_delegateValidated) {
+ if (object)
+ qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
+ d->m_delegateValidated = true;
+ }
+ return 0;
+}
+
+QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
+{
+ Compositor::iterator it = m_compositor.find(group, index);
+ if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
+ return model->stringValue(it.modelIndex(), name);
+ }
+ return QString();
+}
+
+QString QQuickVisualDataModel::stringValue(int index, const QString &name)
+{
+ Q_D(QQuickVisualDataModel);
+ return d->stringValue(d->m_compositorGroup, index, name);
+}
+
+int QQuickVisualDataModelPrivate::cacheIndexOf(QObject *object) const
+{
+ for (int cacheIndex = 0; cacheIndex < m_cache.count(); ++cacheIndex) {
+ if (m_cache.at(cacheIndex)->object == object)
+ return cacheIndex;
+ }
+ return -1;
+}
+
+int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
+{
+ Q_D(const QQuickVisualDataModel);
+ const int cacheIndex = d->cacheIndexOf(item);
+ return cacheIndex != -1
+ ? d->m_cache.at(cacheIndex)->index[d->m_compositorGroup]
+ : -1;
+}
+
+void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
+{
+ Q_D(QQuickVisualDataModel);
+ d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles);
+ d->watchedRoles = roles;
+}
+
+void QQuickVisualDataModelPrivate::addGroups(Compositor::Group group, int index, int count, int groupFlags)
+{
+ QVector<Compositor::Insert> inserts;
+ m_compositor.setFlags(group, index, count, groupFlags, &inserts);
+ itemsInserted(inserts);
+ emitChanges();
+}
+
+void QQuickVisualDataModelPrivate::removeGroups(Compositor::Group group, int index, int count, int groupFlags)
+{
+ QVector<Compositor::Remove> removes;
+ m_compositor.clearFlags(group, index, count, groupFlags, &removes);
+ itemsRemoved(removes);
+ emitChanges();
+}
+
+void QQuickVisualDataModelPrivate::setGroups(Compositor::Group group, int index, int count, int groupFlags)
+{
+ QVector<Compositor::Insert> inserts;
+ m_compositor.setFlags(group, index, count, groupFlags, &inserts);
+ itemsInserted(inserts);
+
+ const int removeFlags = ~groupFlags & Compositor::GroupMask;
+ QVector<Compositor::Remove> removes;
+ m_compositor.clearFlags(group, index, count, removeFlags, &removes);
+ itemsRemoved(removes);
+
+ emitChanges();
+}
+
+bool QQuickVisualDataModel::event(QEvent *e)
+{
+ Q_D(QQuickVisualDataModel);
+ if (e->type() == QEvent::UpdateRequest) {
+ d->m_adaptorModel->fetchMore();
+ } else if (e->type() == QEvent::User) {
+ d->m_incubatorCleanupScheduled = false;
+ qDeleteAll(d->m_finishedIncubating);
+ d->m_finishedIncubating.clear();
+ }
+ return QQuickVisualModel::event(e);
+}
+
+void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
+{
+ if (!m_delegate)
+ return;
+
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
+
+ foreach (const Compositor::Change &change, changes) {
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (change.inGroup(i)) {
+ translatedChanges[i].append(
+ QDeclarativeChangeSet::Change(change.index[i], change.count));
+ }
+ }
+ }
+
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
+}
+
+void QQuickVisualDataModel::_q_itemsChanged(int index, int count)
+{
+ Q_D(QQuickVisualDataModel);
+ if (count <= 0)
+ return;
+ QVector<Compositor::Change> changes;
+ d->m_compositor.listItemsChanged(d->m_adaptorModel, index, count, &changes);
+ d->itemsChanged(changes);
+ d->emitChanges();
+}
+
+void QQuickVisualDataModelPrivate::itemsInserted(
+ const QVector<Compositor::Insert> &inserts,
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
+ QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
+{
+ int cacheIndex = 0;
+
+ int inserted[Compositor::MaximumGroupCount];
+ for (int i = 1; i < m_groupCount; ++i)
+ inserted[i] = 0;
+
+ foreach (const Compositor::Insert &insert, inserts) {
+ for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (!cacheItem->groups)
+ continue;
+ for (int i = 1; i < m_groupCount; ++i)
+ cacheItem->index[i] += inserted[i];
+ }
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (insert.inGroup(i)) {
+ (*translatedInserts)[i].append(
+ QDeclarativeChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
+ inserted[i] += insert.count;
+ }
+ }
+
+ if (!insert.inCache())
+ continue;
+
+ if (movedItems && insert.isMove()) {
+ QList<QQuickVisualDataModelCacheItem *> items = movedItems->take(insert.moveId);
+ Q_ASSERT(items.count() == insert.count);
+ m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
+ }
+ if (insert.inGroup()) {
+ for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ cacheItem->groups |= insert.flags & Compositor::GroupMask;
+ for (int i = 1; i < m_groupCount; ++i) {
+ cacheItem->index[i] = cacheItem->groups & (1 << i)
+ ? insert.index[i] + offset
+ : insert.index[i];
+ }
+ }
+ } else {
+ cacheIndex = insert.cacheIndex + insert.count;
+ }
+ }
+ for (; cacheIndex < m_cache.count(); ++cacheIndex) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (!cacheItem->groups)
+ continue;
+ for (int i = 1; i < m_groupCount; ++i)
+ cacheItem->index[i] += inserted[i];
+ }
+}
+
+void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
+{
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
+ itemsInserted(inserts, &translatedInserts);
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ if (!m_delegate)
+ return;
+
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
+}
+
+void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
+{
+
+ Q_D(QQuickVisualDataModel);
+ if (count <= 0)
+ return;
+ QVector<Compositor::Insert> inserts;
+ d->m_compositor.listItemsInserted(d->m_adaptorModel, index, count, &inserts);
+ d->itemsInserted(inserts);
+ d->emitChanges();
+}
+
+void QQuickVisualDataModelPrivate::itemsRemoved(
+ const QVector<Compositor::Remove> &removes,
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
+ QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
+{
+ int cacheIndex = 0;
+ int removedCache = 0;
+
+ int removed[Compositor::MaximumGroupCount];
+ for (int i = 1; i < m_groupCount; ++i)
+ removed[i] = 0;
+
+ foreach (const Compositor::Remove &remove, removes) {
+ for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (!cacheItem->groups)
+ continue;
+ for (int i = 1; i < m_groupCount; ++i)
+ cacheItem->index[i] -= removed[i];
+ }
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (remove.inGroup(i)) {
+ (*translatedRemoves)[i].append(
+ QDeclarativeChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
+ removed[i] += remove.count;
+ }
+ }
+
+ if (!remove.inCache())
+ continue;
+
+ if (movedItems && remove.isMove()) {
+ movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
+ QList<QQuickVisualDataModelCacheItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
+ QList<QQuickVisualDataModelCacheItem *>::iterator end = begin + remove.count;
+ m_cache.erase(begin, end);
+ } else {
+ for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0) {
+ destroy(cacheItem->object);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitDestroyingPackage(package);
+ else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
+ emitDestroyingItem(item);
+ cacheItem->object = 0;
+ }
+ if (remove.groups() == cacheItem->groups && !cacheItem->isReferenced()) {
+ m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
+ m_cache.removeAt(cacheIndex);
+ delete cacheItem;
+ --cacheIndex;
+ ++removedCache;
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ } else if (remove.groups() == cacheItem->groups) {
+ cacheItem->groups = 0;
+ for (int i = 1; i < m_groupCount; ++i)
+ cacheItem->index[i] = -1;
+ } else {
+ for (int i = 1; i < m_groupCount; ++i) {
+ if (remove.inGroup(i))
+ cacheItem->index[i] = remove.index[i];
+ }
+ cacheItem->groups &= ~remove.flags & Compositor::GroupMask;
+ }
+ }
+ }
+ }
+
+ for (; cacheIndex < m_cache.count(); ++cacheIndex) {
+ QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (!cacheItem->groups)
+ continue;
+ for (int i = 1; i < m_groupCount; ++i)
+ cacheItem->index[i] -= removed[i];
+ }
+}
+
+void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
+{
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
+ itemsRemoved(removes, &translatedRemoves);
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ if (!m_delegate)
+ return;
+
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
+}
+
+void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QQuickVisualDataModel);
+ if (count <= 0)
+ return;
+
+ QVector<Compositor::Remove> removes;
+ d->m_compositor.listItemsRemoved(d->m_adaptorModel, index, count, &removes);
+ d->itemsRemoved(removes);
+ d->emitChanges();
+}
+
+void QQuickVisualDataModelPrivate::itemsMoved(
+ const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
+{
+ QHash<int, QList<QQuickVisualDataModelCacheItem *> > movedItems;
+
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
+ itemsRemoved(removes, &translatedRemoves, &movedItems);
+
+ QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
+ itemsInserted(inserts, &translatedInserts, &movedItems);
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ Q_ASSERT(movedItems.isEmpty());
+ if (!m_delegate)
+ return;
+
+ for (int i = 1; i < m_groupCount; ++i) {
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
+ translatedRemoves.at(i),
+ translatedInserts.at(i));
+ }
+}
+
+void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QQuickVisualDataModel);
+ if (count <= 0)
+ return;
+
+ QVector<Compositor::Remove> removes;
+ QVector<Compositor::Insert> inserts;
+ d->m_compositor.listItemsMoved(d->m_adaptorModel, from, to, count, &removes, &inserts);
+ d->itemsMoved(removes, inserts);
+ d->emitChanges();
+}
+
+template <typename T> v8::Local<v8::Array>
+QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
+{
+ v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
+ v8::Local<v8::String> indexKey = v8::String::New("index");
+ v8::Local<v8::String> countKey = v8::String::New("count");
+ v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
+
+ for (int i = 0; i < changes.count(); ++i) {
+ v8::Local<v8::Object> object = v8::Object::New();
+ object->Set(indexKey, v8::Integer::New(changes.at(i).index));
+ object->Set(countKey, v8::Integer::New(changes.at(i).count));
+ object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
+ indexes->Set(i, object);
+ }
+ return indexes;
+}
+
+void QQuickVisualDataModelPrivate::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
+{
+ Q_Q(QQuickVisualDataModel);
+ emit q->modelUpdated(changeSet, reset);
+ if (changeSet.difference() != 0)
+ emit q->countChanged();
+}
+
+void QQuickVisualDataModelPrivate::emitChanges()
+{
+ if (m_transaction || !m_complete)
+ return;
+
+ m_transaction = true;
+ QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(m_context->engine());
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
+ m_transaction = false;
+
+ const bool reset = m_reset;
+ m_reset = false;
+ for (int i = 1; i < m_groupCount; ++i)
+ QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
+
+ foreach (QQuickVisualDataModelCacheItem *cacheItem, m_cache) {
+ if (cacheItem->object && cacheItem->attached)
+ cacheItem->attached->emitChanges();
+ }
+}
+
+void QQuickVisualDataModel::_q_modelReset(int oldCount, int newCount)
+{
+ Q_D(QQuickVisualDataModel);
+ if (!d->m_delegate)
+ return;
+
+ QVector<Compositor::Remove> removes;
+ QVector<Compositor::Insert> inserts;
+ if (oldCount)
+ d->m_compositor.listItemsRemoved(d->m_adaptorModel, 0, oldCount, &removes);
+ if (newCount)
+ d->m_compositor.listItemsInserted(d->m_adaptorModel, 0, newCount, &inserts);
+ d->itemsMoved(removes, inserts);
+ d->m_reset = true;
+ d->emitChanges();
+}
+
+QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
+{
+ return QQuickVisualDataModelAttached::properties(obj);
+}
+
+//============================================================================
+
+QQuickVisualDataModelCacheMetaType::QQuickVisualDataModelCacheMetaType(
+ QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
+ : model(model)
+ , groupCount(groupNames.count() + 1)
+ , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
+ , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
+ , v8Engine(engine)
+ , metaObject(0)
+ , groupNames(groupNames)
+{
+ QMetaObjectBuilder builder;
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
+ builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
+
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(engine->context());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("model"), get_model);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
+
+ int notifierId = 0;
+ for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
+ QString propertyName = QStringLiteral("in") + groupNames.at(i);
+ propertyName.replace(2, 1, propertyName.at(2).toUpper());
+ builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
+ QMetaPropertyBuilder propertyBuilder = builder.addProperty(
+ propertyName.toUtf8(), "bool", notifierId);
+ propertyBuilder.setWritable(true);
+
+ ft->PrototypeTemplate()->SetAccessor(
+ engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
+ }
+ for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
+ const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
+ builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
+ QMetaPropertyBuilder propertyBuilder = builder.addProperty(
+ propertyName.toUtf8(), "int", notifierId);
+ propertyBuilder.setWritable(true);
+
+ ft->PrototypeTemplate()->SetAccessor(
+ engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
+ }
+
+ metaObject = builder.toMetaObject();
+
+ constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+QQuickVisualDataModelCacheMetaType::~QQuickVisualDataModelCacheMetaType()
+{
+ qFree(metaObject);
+ qPersistentDispose(constructor);
+}
+
+int QQuickVisualDataModelCacheMetaType::parseGroups(const QStringList &groups) const
+{
+ int groupFlags = 0;
+ foreach (const QString &groupName, groups) {
+ int index = groupNames.indexOf(groupName);
+ if (index != -1)
+ groupFlags |= 2 << index;
+ }
+ return groupFlags;
+}
+
+int QQuickVisualDataModelCacheMetaType::parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groups) const
+{
+ int groupFlags = 0;
+ if (groups->IsString()) {
+ const QString groupName = engine->toString(groups);
+ int index = groupNames.indexOf(groupName);
+ if (index != -1)
+ groupFlags |= 2 << index;
+ } else if (groups->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
+ for (uint i = 0; i < array->Length(); ++i) {
+ const QString groupName = engine->toString(array->Get(i));
+ int index = groupNames.indexOf(groupName);
+ if (index != -1)
+ groupFlags |= 2 << index;
+ }
+ }
+ return groupFlags;
+}
+
+v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_model(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+ if (!cacheItem->metaType->model)
+ return v8::Undefined();
+ QObject *data = 0;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ Compositor::iterator it = model->m_compositor.find(
+ Compositor::Group(i), cacheItem->index[i]);
+ if (QQuickVisualAdaptorModel *list = it.list<QQuickVisualAdaptorModel>())
+ data = list->data(it.modelIndex());
+ break;
+ }
+ }
+ if (!data)
+ return v8::Undefined();
+ return cacheItem->engine->newQObject(data);
+}
+
+v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_groups(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ QStringList groups;
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i))
+ groups.append(cacheItem->metaType->groupNames.at(i - 1));
+ }
+
+ return cacheItem->engine->fromVariant(groups);
+}
+
+void QQuickVisualDataModelCacheMetaType::set_groups(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR_SETTER("Not a valid VisualData object");
+
+ if (!cacheItem->metaType->model)
+ return;
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
+
+ const int groupFlags = model->m_cacheMetaType->parseGroups(cacheItem->engine, value);
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ model->setGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlags);
+ break;
+ }
+ }
+}
+
+v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_member(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
+}
+
+void QQuickVisualDataModelCacheMetaType::set_member(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR_SETTER("Not a valid VisualData object");
+
+ if (!cacheItem->metaType->model)
+ return;
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
+
+ Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
+ const bool member = value->BooleanValue();
+ const int groupFlag = (1 << group);
+ if (member == ((cacheItem->groups & groupFlag) != 0))
+ return;
+
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ if (member)
+ model->addGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
+ else
+ model->removeGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
+ break;
+ }
+ }
+}
+
+v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_index(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
+}
+
+
+//---------------------------------------------------------------------------
+
+QQuickVisualDataModelCacheItem::~QQuickVisualDataModelCacheItem()
+{
+ Q_ASSERT(scriptRef == 0);
+ Q_ASSERT(objectRef == 0);
+ Q_ASSERT(!object);
+ if (incubationTask && metaType->model)
+ QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
+
+ metaType->release();
+}
+
+void QQuickVisualDataModelCacheItem::Dispose()
+{
+ --scriptRef;
+ if (isReferenced())
+ return;
+
+ if (metaType->model) {
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
+ const int cacheIndex = model->m_cache.indexOf(this);
+ if (cacheIndex != -1) {
+ model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
+ model->m_cache.removeAt(cacheIndex);
+ }
+ }
+ delete this;
+}
+
+//---------------------------------------------------------------------------
+
+QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
+ QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType)
+ : attached(attached)
+ , metaType(metaType)
+{
+ metaType->addref();
+ *static_cast<QMetaObject *>(this) = *metaType->metaObject;
+ QObjectPrivate::get(attached)->metaObject = this;
+}
+
+QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
+{
+ metaType->release();
+}
+
+int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
+{
+ if (call == QMetaObject::ReadProperty) {
+ if (_id >= metaType->indexPropertyOffset) {
+ Compositor::Group group = Compositor::Group(_id - metaType->indexPropertyOffset + 1);
+ *static_cast<int *>(arguments[0]) = attached->m_cacheItem->index[group];
+ return -1;
+ } else if (_id >= metaType->memberPropertyOffset) {
+ Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
+ *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
+ return -1;
+ }
+ } else if (call == QMetaObject::WriteProperty) {
+ if (_id >= metaType->memberPropertyOffset) {
+ if (!metaType->model)
+ return -1;
+ Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
+ const bool member = attached->m_cacheItem->groups & (1 << group);
+ if (member != *static_cast<bool *>(arguments[0])) {
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
+ const int cacheIndex = model->m_cache.indexOf(attached->m_cacheItem);
+ if (member)
+ model->removeGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
+ else
+ model->addGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
+ }
+ return -1;
+ }
+ }
+ return attached->qt_metacall(call, _id, arguments);
+}
+
+void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelCacheItem *item)
+{
+ m_cacheItem = item;
+ for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
+ m_previousIndex[i] = m_cacheItem->index[i];
+}
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::model
+
+ This attached property holds the visual data model this delegate instance belongs to.
+
+ It is attached to each instance of the delegate.
+*/
+
+QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
+{
+ return m_cacheItem ? m_cacheItem->metaType->model : 0;
+}
+
+/*!
+ \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
+
+ This attached property holds the name of VisualDataGroups the item belongs to.
+
+ It is attached to each instance of the delegate.
+*/
+
+QStringList QQuickVisualDataModelAttached::groups() const
+{
+ QStringList groups;
+
+ if (!m_cacheItem)
+ return groups;
+ for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
+ if (m_cacheItem->groups & (1 << i))
+ groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
+ }
+ return groups;
+}
+
+void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
+{
+ if (!m_cacheItem)
+ return;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
+
+ const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
+ const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
+ model->setGroups(Compositor::Cache, cacheIndex, 1, groupFlags);
+}
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
+
+ This attached property holds whether the item belongs to the default \l items VisualDataGroup.
+
+ Changing this property will add or remove the item from the items group.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
+
+ This attached property holds the index of the item in the default \l items VisualDataGroup.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
+
+ This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
+
+ Changing this property will add or remove the item from the items group. Change with caution
+ as removing an item from the persistedItems group will destroy the current instance if it is
+ not referenced by a model.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
+
+ This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
+
+ It is attached to each instance of the delegate.
+*/
+
+void QQuickVisualDataModelAttached::emitChanges()
+{
+ if (m_modelChanged) {
+ m_modelChanged = false;
+ emit modelChanged();
+ }
+
+ const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
+ m_previousGroups = m_cacheItem->groups;
+
+ int indexChanges = 0;
+ for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
+ if (m_previousIndex[i] != m_cacheItem->index[i]) {
+ m_previousIndex[i] = m_cacheItem->index[i];
+ indexChanges |= (1 << i);
+ }
+ }
+
+ int notifierId = 0;
+ const QMetaObject *meta = metaObject();
+ for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ if (groupChanges & (1 << i))
+ QMetaObject::activate(this, meta, notifierId, 0);
+ }
+ for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ if (indexChanges & (1 << i))
+ QMetaObject::activate(this, meta, notifierId, 0);
+ }
+
+ if (groupChanges)
+ emit groupsChanged();
+}
+
+//============================================================================
+
+void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
+{
+ Q_ASSERT(!model);
+ model = m;
+ group = g;
+}
+
+void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
+{
+ Q_Q(QQuickVisualDataGroup);
+ static int idx = signalIndex("changed(QDeclarativeV8Handle,QDeclarativeV8Handle)");
+ if (isSignalConnected(idx) && !changeSet.isEmpty()) {
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(engine->context());
+ v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes());
+ v8::Local<v8::Array> inserted = QQuickVisualDataModelPrivate::buildChangeList(changeSet.inserts());
+ emit q->changed(
+ QDeclarativeV8Handle::fromHandle(removed), QDeclarativeV8Handle::fromHandle(inserted));
+ }
+ if (changeSet.difference() != 0)
+ emit q->countChanged();
+}
+
+void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
+{
+ for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
+ it->emitModelUpdated(changeSet, reset);
+ changeSet.clear();
+}
+
+void QQuickVisualDataGroupPrivate::createdPackage(int index, QDeclarativePackage *package)
+{
+ for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
+ it->createdPackage(index, package);
+}
+
+void QQuickVisualDataGroupPrivate::initPackage(int index, QDeclarativePackage *package)
+{
+ for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
+ it->initPackage(index, package);
+}
+
+void QQuickVisualDataGroupPrivate::destroyingPackage(QDeclarativePackage *package)
+{
+ for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
+ it->destroyingPackage(package);
+}
+
+/*!
+ \qmlclass VisualDataGroup QQuickVisualDataGroup
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief The VisualDataGroup encapsulates a filtered set of visual data items.
+
+*/
+
+QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
+ : QObject(*new QQuickVisualDataGroupPrivate, parent)
+{
+}
+
+QQuickVisualDataGroup::QQuickVisualDataGroup(
+ const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
+ : QObject(*new QQuickVisualDataGroupPrivate, parent)
+{
+ Q_D(QQuickVisualDataGroup);
+ d->name = name;
+ d->setModel(model, Compositor::Group(index));
+}
+
+QQuickVisualDataGroup::~QQuickVisualDataGroup()
+{
+}
+
+/*!
+ \qmlproperty string QtQuick2::VisualDataGroup::name
+
+ This property holds the name of the group.
+
+ Each group in a model must have a unique name starting with a lower case letter.
+*/
+
+QString QQuickVisualDataGroup::name() const
+{
+ Q_D(const QQuickVisualDataGroup);
+ return d->name;
+}
+
+void QQuickVisualDataGroup::setName(const QString &name)
+{
+ Q_D(QQuickVisualDataGroup);
+ if (d->model)
+ return;
+ if (d->name != name) {
+ d->name = name;
+ emit nameChanged();
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick2::VisualDataGroup::count
+
+ This property holds the number of items in the group.
+*/
+
+int QQuickVisualDataGroup::count() const
+{
+ Q_D(const QQuickVisualDataGroup);
+ if (!d->model)
+ return 0;
+ return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
+}
+
+/*!
+ \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
+
+ This property holds whether new items are assigned to this group by default.
+*/
+
+bool QQuickVisualDataGroup::defaultInclude() const
+{
+ Q_D(const QQuickVisualDataGroup);
+ return d->defaultInclude;
+}
+
+void QQuickVisualDataGroup::setDefaultInclude(bool include)
+{
+ Q_D(QQuickVisualDataGroup);
+ if (d->defaultInclude != include) {
+ d->defaultInclude = include;
+
+ if (d->model) {
+ if (include)
+ QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
+ else
+ QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
+ }
+ emit defaultIncludeChanged();
+ }
+}
+
+/*!
+ \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
+
+ Returns a javascript object describing the item at \a index in the group.
+
+ The returned object contains the same information that is available to a delegate from the
+ VisualDataModel attached as well as the model for that item. It has the properties:
+
+ \list
+ \o \b model The model data of the item. This is the same as the model context property in
+ a delegate
+ \o \b groups A list the of names of groups the item is a member of. This property can be
+ written to change the item's membership.
+ \o \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
+ Writing to this property will add or remove the item from the group.
+ \o \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
+ \o \b {in\i{GroupName}} Whether the item belongs to the dynamic group \i groupName. Writing to
+ this property will add or remove the item from the group.
+ \o \b {\i{groupName}Index} The index of the item within the dynamic group \i groupName.
+ \endlist
+*/
+
+QDeclarativeV8Handle QQuickVisualDataGroup::get(int index)
+{
+ Q_D(QQuickVisualDataGroup);
+ if (!d->model)
+ return QDeclarativeV8Handle::fromHandle(v8::Undefined());;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (index < 0 || index >= model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("get: index out of range");
+ return QDeclarativeV8Handle::fromHandle(v8::Undefined());
+ }
+
+ Compositor::iterator it = model->m_compositor.find(d->group, index);
+ QQuickVisualDataModelCacheItem *cacheItem = it->inCache()
+ ? model->m_cache.at(it.cacheIndex)
+ : 0;
+
+ if (!cacheItem) {
+ cacheItem = new QQuickVisualDataModelCacheItem(model->m_cacheMetaType);
+ for (int i = 0; i < model->m_groupCount; ++i)
+ cacheItem->index[i] = it.index[i];
+ cacheItem->groups = it->flags & Compositor::GroupMask;
+
+ model->m_cache.insert(it.cacheIndex, cacheItem);
+ model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
+ }
+
+ ++cacheItem->scriptRef;
+
+ v8::Local<v8::Object> rv = model->m_cacheMetaType->constructor->NewInstance();
+ rv->SetExternalResource(cacheItem);
+ return QDeclarativeV8Handle::fromHandle(rv);
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::create(int index)
+
+ Returns a reference to the instantiated item at \a index in the group.
+
+ All items returned by create are added to the persistedItems group. Items in this
+ group remain instantiated when not referenced by any view.
+*/
+
+QObject *QQuickVisualDataGroup::create(int index)
+{
+ Q_D(QQuickVisualDataGroup);
+ if (!d->model)
+ return 0;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (index < 0 || index >= model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("create: index out of range");
+ return 0;
+ }
+
+ QObject *object = model->object(d->group, index, false, false);
+ if (object)
+ model->addGroups(d->group, index, 1, Compositor::PersistedFlag);
+ return object;
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
+
+ Removes \a count items starting at \a index from the group.
+*/
+
+void QQuickVisualDataGroup::remove(QDeclarativeV8Function *args)
+{
+ Q_D(QQuickVisualDataGroup);
+ if (!d->model)
+ return;
+ int index = -1;
+ int count = 1;
+
+ if (args->Length() == 0)
+ return;
+
+ int i = 0;
+ v8::Local<v8::Value> v = (*args)[i];
+ if (!v->IsInt32())
+ return;
+ index = v->Int32Value();
+
+ if (++i < args->Length()) {
+ v = (*args)[i];
+ if (v->IsInt32())
+ count = v->Int32Value();
+ }
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (count < 0) {
+ qmlInfo(this) << tr("remove: invalid count");
+ } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("remove: index out of range");
+ } else if (count > 0) {
+ model->removeGroups(d->group, index, count, 1 << d->group);
+ }
+}
+
+bool QQuickVisualDataGroupPrivate::parseGroupArgs(
+ QDeclarativeV8Function *args, int *index, int *count, int *groups) const
+{
+ if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
+ return false;
+
+ if (args->Length() < 2)
+ return false;
+
+ int i = 0;
+ v8::Local<v8::Value> v = (*args)[i];
+ if (!v->IsInt32())
+ return false;
+ *index = v->Int32Value();
+
+ v = (*args)[++i];
+ if (v->IsInt32()) {
+ *count = v->Int32Value();
+
+ if (++i == args->Length())
+ return false;
+ v = (*args)[i];
+ }
+
+ *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(args->engine(), v);
+
+ return true;
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
+
+ Adds \a count items starting at \a index to \a groups.
+*/
+
+void QQuickVisualDataGroup::addGroups(QDeclarativeV8Function *args)
+{
+ Q_D(QQuickVisualDataGroup);
+ int index = -1;
+ int count = 1;
+ int groups = 0;
+
+ if (!d->parseGroupArgs(args, &index, &count, &groups))
+ return;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (count < 0) {
+ qmlInfo(this) << tr("addGroups: invalid count");
+ } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("addGroups: index out of range");
+ } else if (count > 0 && groups) {
+ model->addGroups(d->group, index, count, groups);
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
+
+ Removes \a count items starting at \a index from \a groups.
+*/
+
+void QQuickVisualDataGroup::removeGroups(QDeclarativeV8Function *args)
+{
+ Q_D(QQuickVisualDataGroup);
+ int index = -1;
+ int count = 1;
+ int groups = 0;
+
+ if (!d->parseGroupArgs(args, &index, &count, &groups))
+ return;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (count < 0) {
+ qmlInfo(this) << tr("removeGroups: invalid count");
+ } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("removeGroups: index out of range");
+ } else if (count > 0 && groups) {
+ model->removeGroups(d->group, index, count, groups);
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
+
+ Sets the \a groups \a count items starting at \a index belong to.
+*/
+
+void QQuickVisualDataGroup::setGroups(QDeclarativeV8Function *args)
+{
+ Q_D(QQuickVisualDataGroup);
+ int index = -1;
+ int count = 1;
+ int groups = 0;
+
+ if (!d->parseGroupArgs(args, &index, &count, &groups))
+ return;
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+ if (count < 0) {
+ qmlInfo(this) << tr("setGroups: invalid count");
+ } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("setGroups: index out of range");
+ } else if (count > 0) {
+ model->setGroups(d->group, index, count, groups);
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
+
+ Sets the \a groups \a count items starting at \a index belong to.
+*/
+
+/*!
+ \qmlmethod QtQuick2::VisualDataGroup::move(int from, int to, int count)
+
+ Moves \a count at \a from in a group \a to a new position.
+*/
+
+void QQuickVisualDataGroup::move(QDeclarativeV8Function *args)
+{
+ Q_D(QQuickVisualDataGroup);
+
+ if (args->Length() < 2)
+ return;
+
+ Compositor::Group fromGroup = d->group;
+ Compositor::Group toGroup = d->group;
+ int from = -1;
+ int to = -1;
+ int count = 1;
+
+ int i = 0;
+ v8::Local<v8::Value> v = (*args)[i];
+ if (QQuickVisualDataGroup *group = qobject_cast<QQuickVisualDataGroup *>(args->engine()->toQObject(v))) {
+ QQuickVisualDataGroupPrivate *g_d = QQuickVisualDataGroupPrivate::get(group);
+ if (g_d->model != d->model)
+ return;
+ fromGroup = g_d->group;
+ v = (*args)[++i];
+ }
+
+ if (!v->IsInt32())
+ return;
+ from = v->Int32Value();
+
+ if (++i == args->Length())
+ return;
+ v = (*args)[i];
+
+ if (QQuickVisualDataGroup *group = qobject_cast<QQuickVisualDataGroup *>(args->engine()->toQObject(v))) {
+ QQuickVisualDataGroupPrivate *g_d = QQuickVisualDataGroupPrivate::get(group);
+ if (g_d->model != d->model)
+ return;
+ toGroup = g_d->group;
+
+ if (++i == args->Length())
+ return;
+ v = (*args)[i];
+ }
+
+ if (!v->IsInt32())
+ return;
+ to = v->Int32Value();
+
+ if (++i < args->Length()) {
+ v = (*args)[i];
+ if (v->IsInt32())
+ count = v->Int32Value();
+ }
+
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
+
+ if (count < 0) {
+ qmlInfo(this) << tr("move: invalid count");
+ } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
+ qmlInfo(this) << tr("move: from index out of range");
+ } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count)) {
+ qmlInfo(this) << tr("move: to index out of range");
+ } else if (count > 0) {
+ QVector<Compositor::Remove> removes;
+ QVector<Compositor::Insert> inserts;
+
+ model->m_compositor.move(fromGroup, from, toGroup, to, count, &removes, &inserts);
+ model->itemsMoved(removes, inserts);
+ model->emitChanges();
+ }
+
+}
+
+/*!
+ \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
+
+ This handler is called when items have been removed from or inserted into the group.
+
+ Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
+ item inserted or removed and a \e count of the number of consecutive items inserted or removed.
+
+ Each index is adjusted for previous changes with all removed items preceding any inserted
+ items.
+*/
+
+//============================================================================
+
+QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
+ : QQuickVisualModel(*new QObjectPrivate, parent)
+ , m_model(model)
+ , m_part(part)
+ , m_compositorGroup(Compositor::Cache)
+ , m_inheritGroup(true)
+{
+ QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
+ if (d->m_cacheMetaType) {
+ QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
+ m_compositorGroup = Compositor::Default;
+ } else {
+ d->m_pendingParts.insert(this);
+ }
+}
+
+QQuickVisualPartsModel::~QQuickVisualPartsModel()
+{
+}
+
+QString QQuickVisualPartsModel::filterGroup() const
+{
+ if (m_inheritGroup)
+ return m_model->filterGroup();
+ return m_filterGroup;
+}
+
+void QQuickVisualPartsModel::setFilterGroup(const QString &group)
+{
+ if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
+ qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
+ return;
+ }
+
+ if (m_filterGroup != group || m_inheritGroup) {
+ m_filterGroup = group;
+ m_inheritGroup = false;
+ updateFilterGroup();
+
+ emit filterGroupChanged();
+ }
+}
+
+void QQuickVisualPartsModel::resetFilterGroup()
+{
+ if (!m_inheritGroup) {
+ m_inheritGroup = true;
+ updateFilterGroup();
+ emit filterGroupChanged();
+ }
+}
+
+void QQuickVisualPartsModel::updateFilterGroup()
+{
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+ if (!model->m_cacheMetaType)
+ return;
+
+ if (m_inheritGroup) {
+ if (m_filterGroup == model->m_filterGroup)
+ return;
+ m_filterGroup = model->m_filterGroup;
+ }
+
+ QDeclarativeListCompositor::Group previousGroup = m_compositorGroup;
+ m_compositorGroup = Compositor::Default;
+ QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
+ for (int i = 1; i < model->m_groupCount; ++i) {
+ if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
+ m_compositorGroup = Compositor::Group(i);
+ break;
+ }
+ }
+
+ QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
+ if (m_compositorGroup != previousGroup) {
+ QVector<QDeclarativeChangeSet::Remove> removes;
+ QVector<QDeclarativeChangeSet::Insert> inserts;
+ model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
+
+ QDeclarativeChangeSet changeSet;
+ changeSet.apply(removes, inserts);
+ if (!changeSet.isEmpty())
+ emit modelUpdated(changeSet, false);
+
+ if (changeSet.difference() != 0)
+ emit countChanged();
+ }
+}
+
+void QQuickVisualPartsModel::updateFilterGroup(
+ Compositor::Group group, const QDeclarativeChangeSet &changeSet)
+{
+ if (!m_inheritGroup)
+ return;
+
+ m_compositorGroup = group;
+ QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
+
+ if (!changeSet.isEmpty())
+ emit modelUpdated(changeSet, false);
+
+ if (changeSet.difference() != 0)
+ emit countChanged();
+
+ emit filterGroupChanged();
+}
+
+int QQuickVisualPartsModel::count() const
+{
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+ return model->m_delegate
+ ? model->m_compositor.count(m_compositorGroup)
+ : 0;
+}
+
+bool QQuickVisualPartsModel::isValid() const
+{
+ return m_model->isValid();
+}
+
+QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
+{
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+
+ if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
+ return 0;
+ }
+
+ QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
+
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) {
+ QObject *part = package->part(m_part);
+ if (!part)
+ return 0;
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
+ m_packaged.insertMulti(item, package);
+ return item;
+ }
+ }
+
+ model->release(object);
+ if (!model->m_delegateValidated) {
+ if (object)
+ qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
+ model->m_delegateValidated = true;
+ }
+
+ return 0;
+}
+
+QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
+{
+ QQuickVisualModel::ReleaseFlags flags = 0;
+
+ QHash<QObject *, QDeclarativePackage *>::iterator it = m_packaged.find(item);
+ if (it != m_packaged.end()) {
+ QDeclarativePackage *package = *it;
+ QDeclarative_setParent_noEvent(item, package);
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+ flags = model->release(package);
+ m_packaged.erase(it);
+ if (!m_packaged.contains(item))
+ flags &= ~Referenced;
+ if (flags & Destroyed) {
+ QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
+ item->setParentItem(0);
+ }
+ }
+ return flags;
+}
+
+QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
+{
+ return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
+}
+
+void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
+{
+ QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+ model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles);
+ m_watchedRoles = roles;
+}
+
+int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
+{
+ QHash<QObject *, QDeclarativePackage *>::const_iterator it = m_packaged.find(item);
+ if (it != m_packaged.end()) {
+ const QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
+ const int cacheIndex = model->cacheIndexOf(*it);
+ return cacheIndex != -1
+ ? model->m_cache.at(cacheIndex)->index[m_compositorGroup]
+ : -1;
+ }
+ return -1;
+}
+
+void QQuickVisualPartsModel::createdPackage(int index, QDeclarativePackage *package)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
+ emit createdItem(index, item);
+}
+
+void QQuickVisualPartsModel::initPackage(int index, QDeclarativePackage *package)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
+ emit initItem(index, item);
+}
+
+void QQuickVisualPartsModel::destroyingPackage(QDeclarativePackage *package)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
+ Q_ASSERT(!m_packaged.contains(item));
+ emit destroyingItem(item);
+ }
+}
+
+void QQuickVisualPartsModel::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
+{
+ emit modelUpdated(changeSet, reset);
+ if (changeSet.difference() != 0)
+ emit countChanged();
+}
+
+
+QT_END_NAMESPACE
+
+#include <qquickvisualdatamodel.moc>