1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickvisualdatamodel_p.h"
43 #include "qquickitem.h"
45 #include <QtCore/qcoreapplication.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
49 #include <QtDeclarative/qdeclarativeinfo.h>
50 #include <QtDeclarative/qdeclarativeincubator.h>
52 #include <private/qdeclarativecontext_p.h>
53 #include <private/qdeclarativepackage_p.h>
54 #include <private/qdeclarativeopenmetaobject_p.h>
55 #include <private/qdeclarativelistaccessor_p.h>
56 #include <private/qdeclarativedata_p.h>
57 #include <private/qdeclarativepropertycache_p.h>
58 #include <private/qdeclarativeguard_p.h>
59 #include <private/qdeclarativeglobal_p.h>
60 #include <private/qmetaobjectbuilder_p.h>
61 #include <private/qdeclarativeproperty_p.h>
62 #include <private/qquickvisualadaptormodel_p.h>
63 #include <private/qdeclarativechangeset_p.h>
64 #include <private/qdeclarativelistcompositor_p.h>
65 #include <private/qdeclarativeengine_p.h>
66 #include <private/qquickitem_p.h>
67 #include <private/qobject_p.h>
69 #include <QtCore/qhash.h>
70 #include <QtCore/qlist.h>
74 typedef QDeclarativeListCompositor Compositor;
76 class QQuickVisualDataModelPrivate;
77 class QVDMIncubationTask : public QDeclarativeIncubator
80 QVDMIncubationTask(QQuickVisualDataModelPrivate *l, IncubationMode mode)
81 : QDeclarativeIncubator(mode)
83 , incubatingContext(0)
86 virtual void statusChanged(Status);
87 virtual void setInitialState(QObject *);
89 QQuickVisualDataModelCacheItem *incubating;
90 QDeclarativeContext *incubatingContext;
93 QQuickVisualDataModelPrivate *vdm;
97 class QQuickVisualDataGroupEmitter
100 virtual void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset) = 0;
101 virtual void createdPackage(int, QDeclarativePackage *) {}
102 virtual void initPackage(int, QDeclarativePackage *) {}
103 virtual void destroyingPackage(QDeclarativePackage *) {}
105 QIntrusiveListNode emitterNode;
108 typedef QIntrusiveList<QQuickVisualDataGroupEmitter, &QQuickVisualDataGroupEmitter::emitterNode> QQuickVisualDataGroupEmitterList;
110 //---------------------------------------------------------------------------
112 class QQuickVisualDataGroupPrivate : public QObjectPrivate
115 Q_DECLARE_PUBLIC(QQuickVisualDataGroup)
117 QQuickVisualDataGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
119 static QQuickVisualDataGroupPrivate *get(QQuickVisualDataGroup *group) {
120 return static_cast<QQuickVisualDataGroupPrivate *>(QObjectPrivate::get(group)); }
122 void setModel(QQuickVisualDataModel *model, Compositor::Group group);
123 void emitChanges(QV8Engine *engine);
124 void emitModelUpdated(bool reset);
126 void createdPackage(int index, QDeclarativePackage *package);
127 void initPackage(int index, QDeclarativePackage *package);
128 void destroyingPackage(QDeclarativePackage *package);
130 bool parseGroupArgs(QDeclarativeV8Function *args, int *index, int *count, int *groups) const;
132 Compositor::Group group;
133 QDeclarativeGuard<QQuickVisualDataModel> model;
134 QQuickVisualDataGroupEmitterList emitters;
135 QDeclarativeChangeSet changeSet;
140 //---------------------------------------------------------------------------
142 class QQuickVisualDataModelCacheItem;
143 class QQuickVisualDataModelCacheMetaType;
144 class QQuickVisualDataModelParts;
146 class QQuickVisualDataModelCacheMetaType : public QDeclarativeRefCount
149 QQuickVisualDataModelCacheMetaType(QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames);
150 ~QQuickVisualDataModelCacheMetaType();
152 int parseGroups(const QStringList &groupNames) const;
153 int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
155 static v8::Handle<v8::Value> get_model(v8::Local<v8::String>, const v8::AccessorInfo &info);
156 static v8::Handle<v8::Value> get_groups(v8::Local<v8::String>, const v8::AccessorInfo &info);
157 static void set_groups(
158 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
159 static v8::Handle<v8::Value> get_member(v8::Local<v8::String>, const v8::AccessorInfo &info);
160 static void set_member(
161 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
162 static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info);
164 QDeclarativeGuard<QQuickVisualDataModel> model;
165 const int groupCount;
166 const int memberPropertyOffset;
167 const int indexPropertyOffset;
168 QV8Engine * const v8Engine;
169 QMetaObject *metaObject;
170 const QStringList groupNames;
171 v8::Persistent<v8::Function> constructor;
174 class QQuickVisualDataModelCacheItem : public QV8ObjectResource
176 V8_RESOURCE_TYPE(VisualDataItemType)
178 QQuickVisualDataModelCacheItem(QQuickVisualDataModelCacheMetaType *metaType)
179 : QV8ObjectResource(metaType->v8Engine)
191 ~QQuickVisualDataModelCacheItem();
193 void referenceObject() { ++objectRef; }
194 bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
195 bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
197 bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag) || incubationTask; }
201 QQuickVisualDataModelCacheMetaType * const metaType;
202 QDeclarativeGuard<QObject> object;
203 QQuickVisualDataModelAttached *attached;
207 int index[Compositor::MaximumGroupCount];
208 QVDMIncubationTask *incubationTask;
212 class QQuickVisualDataModelPrivate : public QObjectPrivate, public QQuickVisualDataGroupEmitter
214 Q_DECLARE_PUBLIC(QQuickVisualDataModel)
216 QQuickVisualDataModelPrivate(QDeclarativeContext *);
217 ~QQuickVisualDataModelPrivate();
219 static QQuickVisualDataModelPrivate *get(QQuickVisualDataModel *m) {
220 return static_cast<QQuickVisualDataModelPrivate *>(QObjectPrivate::get(m));
224 void connectModel(QQuickVisualAdaptorModel *model);
226 QObject *object(Compositor::Group group, int index, bool asynchronous, bool reference);
227 void destroy(QObject *object);
228 QQuickVisualDataModel::ReleaseFlags release(QObject *object);
229 QString stringValue(Compositor::Group group, int index, const QString &name);
230 int cacheIndexOf(QObject *object) const;
231 void emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
232 void emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package);
233 void emitCreatedItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
234 emit q_func()->createdItem(cacheItem->index[m_compositorGroup], item); }
235 void emitInitItem(QQuickVisualDataModelCacheItem *cacheItem, QQuickItem *item) {
236 emit q_func()->initItem(cacheItem->index[m_compositorGroup], item); }
237 void emitDestroyingPackage(QDeclarativePackage *package);
238 void emitDestroyingItem(QQuickItem *item) { emit q_func()->destroyingItem(item); }
240 void updateFilterGroup();
242 void addGroups(Compositor::Group group, int index, int count, int groupFlags);
243 void removeGroups(Compositor::Group group, int index, int count, int groupFlags);
244 void setGroups(Compositor::Group group, int index, int count, int groupFlags);
247 const QVector<Compositor::Insert> &inserts,
248 QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
249 QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems = 0);
250 void itemsInserted(const QVector<Compositor::Insert> &inserts);
252 const QVector<Compositor::Remove> &removes,
253 QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
254 QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems = 0);
255 void itemsRemoved(const QVector<Compositor::Remove> &removes);
257 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts);
258 void itemsChanged(const QVector<Compositor::Change> &changes);
259 template <typename T> static v8::Local<v8::Array> buildChangeList(const QVector<T> &changes);
261 void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
264 static void group_append(QDeclarativeListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group);
265 static int group_count(QDeclarativeListProperty<QQuickVisualDataGroup> *property);
266 static QQuickVisualDataGroup *group_at(QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index);
268 void releaseIncubator(QVDMIncubationTask *incubationTask);
269 void incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status);
270 void setInitialState(QVDMIncubationTask *incubationTask, QObject *o);
272 QQuickVisualAdaptorModel *m_adaptorModel;
273 QDeclarativeComponent *m_delegate;
274 QQuickVisualDataModelCacheMetaType *m_cacheMetaType;
275 QDeclarativeGuard<QDeclarativeContext> m_context;
277 QList<QQuickVisualDataModelCacheItem *> m_cache;
278 QQuickVisualDataModelParts *m_parts;
279 QQuickVisualDataGroupEmitterList m_pendingParts;
281 QDeclarativeListCompositor m_compositor;
282 QDeclarativeListCompositor::Group m_compositorGroup;
284 bool m_delegateValidated : 1;
286 bool m_transaction : 1;
287 bool m_incubatorCleanupScheduled : 1;
289 QString m_filterGroup;
290 QList<QByteArray> watchedRoles;
294 QQuickVisualDataGroup *m_cacheItems;
295 QQuickVisualDataGroup *m_items;
296 QQuickVisualDataGroup *m_persistedItems;
298 QQuickVisualDataGroup *m_groups[Compositor::MaximumGroupCount];
302 QList<QVDMIncubationTask *> m_finishedIncubating;
305 //---------------------------------------------------------------------------
307 class QQuickVisualPartsModel : public QQuickVisualModel, public QQuickVisualDataGroupEmitter
310 Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
312 QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent = 0);
313 ~QQuickVisualPartsModel();
315 QString filterGroup() const;
316 void setFilterGroup(const QString &group);
317 void resetFilterGroup();
318 void updateFilterGroup();
319 void updateFilterGroup(Compositor::Group group, const QDeclarativeChangeSet &changeSet);
322 bool isValid() const;
323 QQuickItem *item(int index, bool asynchronous=false);
324 ReleaseFlags release(QQuickItem *item);
325 QString stringValue(int index, const QString &role);
326 void setWatchedRoles(QList<QByteArray> roles);
328 int indexOf(QQuickItem *item, QObject *objectContext) const;
330 void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
332 void createdPackage(int index, QDeclarativePackage *package);
333 void initPackage(int index, QDeclarativePackage *package);
334 void destroyingPackage(QDeclarativePackage *package);
337 void filterGroupChanged();
340 QQuickVisualDataModel *m_model;
341 QHash<QObject *, QDeclarativePackage *> m_packaged;
343 QString m_filterGroup;
344 QList<QByteArray> m_watchedRoles;
345 Compositor::Group m_compositorGroup;
349 class QQuickVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
352 QQuickVisualDataModelPartsMetaObject(QObject *parent)
353 : QDeclarativeOpenMetaObject(parent) {}
355 virtual void propertyCreated(int, QMetaPropertyBuilder &);
356 virtual QVariant initialValue(int);
359 class QQuickVisualDataModelParts : public QObject
363 QQuickVisualDataModelParts(QQuickVisualDataModel *parent);
365 QQuickVisualDataModel *model;
366 QList<QQuickVisualPartsModel *> models;
369 void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
371 prop.setWritable(false);
374 QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
376 QQuickVisualDataModelParts *parts = static_cast<QQuickVisualDataModelParts *>(object());
377 QQuickVisualPartsModel *m = new QQuickVisualPartsModel(
378 parts->model, QString::fromUtf8(name(id)), parts);
379 parts->models.append(m);
380 return QVariant::fromValue(static_cast<QObject *>(m));
383 QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
384 : QObject(parent), model(parent)
386 new QQuickVisualDataModelPartsMetaObject(this);
389 class QQuickVisualDataModelAttachedMetaObject : public QAbstractDynamicMetaObject
392 QQuickVisualDataModelAttachedMetaObject(
393 QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType);
394 ~QQuickVisualDataModelAttachedMetaObject();
396 int metaCall(QMetaObject::Call, int _id, void **);
399 QQuickVisualDataModelAttached *attached;
400 QQuickVisualDataModelCacheMetaType *metaType;
403 //---------------------------------------------------------------------------
405 QHash<QObject*, QQuickVisualDataModelAttached*> QQuickVisualDataModelAttached::attachedProperties;
408 \qmlclass VisualDataModel QQuickVisualDataModel
409 \inqmlmodule QtQuick 2
410 \ingroup qml-working-with-data
411 \brief The VisualDataModel encapsulates a model and delegate
413 A VisualDataModel encapsulates a model and the delegate that will
414 be instantiated for items in the model.
416 It is usually not necessary to create VisualDataModel elements.
417 However, it can be useful for manipulating and accessing the \l modelIndex
418 when a QAbstractItemModel subclass is used as the
419 model. Also, VisualDataModel is used together with \l Package to
420 provide delegates to multiple views.
422 The example below illustrates using a VisualDataModel with a ListView.
424 \snippet doc/src/snippets/declarative/visualdatamodel.qml 0
427 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QDeclarativeContext *ctxt)
433 , m_compositorGroup(Compositor::Cache)
435 , m_delegateValidated(false)
437 , m_transaction(false)
438 , m_incubatorCleanupScheduled(false)
439 , m_filterGroup(QStringLiteral("items"))
446 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
448 qDeleteAll(m_finishedIncubating);
451 void QQuickVisualDataModelPrivate::connectModel(QQuickVisualAdaptorModel *model)
453 Q_Q(QQuickVisualDataModel);
455 QObject::connect(model, SIGNAL(itemsInserted(int,int)), q, SLOT(_q_itemsInserted(int,int)));
456 QObject::connect(model, SIGNAL(itemsRemoved(int,int)), q, SLOT(_q_itemsRemoved(int,int)));
457 QObject::connect(model, SIGNAL(itemsMoved(int,int,int)), q, SLOT(_q_itemsMoved(int,int,int)));
458 QObject::connect(model, SIGNAL(itemsChanged(int,int)), q, SLOT(_q_itemsChanged(int,int)));
459 QObject::connect(model, SIGNAL(modelReset(int,int)), q, SLOT(_q_modelReset(int,int)));
462 void QQuickVisualDataModelPrivate::init()
464 Q_Q(QQuickVisualDataModel);
465 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
467 m_adaptorModel = new QQuickVisualAdaptorModel;
468 QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged()));
470 m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
471 m_items->setDefaultInclude(true);
472 m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
473 QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
476 QQuickVisualDataModel::QQuickVisualDataModel()
477 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
479 Q_D(QQuickVisualDataModel);
483 QQuickVisualDataModel::QQuickVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
484 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
486 Q_D(QQuickVisualDataModel);
490 QQuickVisualDataModel::~QQuickVisualDataModel()
492 Q_D(QQuickVisualDataModel);
494 foreach (QQuickVisualDataModelCacheItem *cacheItem, d->m_cache) {
495 delete cacheItem->object;
496 cacheItem->object = 0;
497 cacheItem->objectRef = 0;
498 if (!cacheItem->isReferenced())
502 delete d->m_adaptorModel;
503 if (d->m_cacheMetaType)
504 d->m_cacheMetaType->release();
508 void QQuickVisualDataModel::classBegin()
512 void QQuickVisualDataModel::componentComplete()
514 Q_D(QQuickVisualDataModel);
515 d->m_complete = true;
517 int defaultGroups = 0;
518 QStringList groupNames;
519 groupNames.append(QStringLiteral("items"));
520 groupNames.append(QStringLiteral("persistedItems"));
521 if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
522 defaultGroups |= Compositor::DefaultFlag;
523 if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
524 defaultGroups |= Compositor::PersistedFlag;
525 for (int i = 3; i < d->m_groupCount; ++i) {
526 QString name = d->m_groups[i]->name();
527 if (name.isEmpty()) {
528 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
531 } else if (name.at(0).isUpper()) {
532 qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
533 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
537 groupNames.append(name);
539 QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
540 group->setModel(this, Compositor::Group(i));
541 if (group->defaultInclude)
542 defaultGroups |= (1 << i);
546 d->m_context = qmlContext(this);
548 d->m_cacheMetaType = new QQuickVisualDataModelCacheMetaType(
549 QDeclarativeEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
551 d->m_compositor.setGroupCount(d->m_groupCount);
552 d->m_compositor.setDefaultGroups(defaultGroups);
553 d->updateFilterGroup();
555 while (!d->m_pendingParts.isEmpty())
556 static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
558 d->connectModel(d->m_adaptorModel);
559 QVector<Compositor::Insert> inserts;
561 d->m_compositor.append(
564 qMax(0, d->m_adaptorModel->count()),
565 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
567 d->itemsInserted(inserts);
570 if (d->m_adaptorModel->canFetchMore())
571 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
575 \qmlproperty model QtQuick2::VisualDataModel::model
576 This property holds the model providing data for the VisualDataModel.
578 The model provides a set of data that is used to create the items
579 for a view. For large or dynamic datasets the model is usually
580 provided by a C++ model object. The C++ model object must be a \l
581 {QAbstractItemModel} subclass or a simple list.
583 Models can also be created directly in QML, using a \l{ListModel} or
586 \sa {qmlmodels}{Data Models}
588 QVariant QQuickVisualDataModel::model() const
590 Q_D(const QQuickVisualDataModel);
591 return d->m_adaptorModel->model();
594 void QQuickVisualDataModel::setModel(const QVariant &model)
596 Q_D(QQuickVisualDataModel);
597 d->m_adaptorModel->setModel(model, d->m_context ? d->m_context->engine() : qmlEngine(this));
598 if (d->m_complete && d->m_adaptorModel->canFetchMore())
599 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
603 \qmlproperty Component QtQuick2::VisualDataModel::delegate
605 The delegate provides a template defining each item instantiated by a view.
606 The index is exposed as an accessible \c index property. Properties of the
607 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
609 QDeclarativeComponent *QQuickVisualDataModel::delegate() const
611 Q_D(const QQuickVisualDataModel);
612 return d->m_delegate;
615 void QQuickVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
617 Q_D(QQuickVisualDataModel);
618 if (d->m_transaction) {
619 qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
622 bool wasValid = d->m_delegate != 0;
623 d->m_delegate = delegate;
624 d->m_delegateValidated = false;
625 if (wasValid && d->m_complete) {
626 for (int i = 1; i < d->m_groupCount; ++i) {
627 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
628 0, d->m_compositor.count(Compositor::Group(i)));
631 if (d->m_complete && d->m_delegate) {
632 for (int i = 1; i < d->m_groupCount; ++i) {
633 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
634 0, d->m_compositor.count(Compositor::Group(i)));
641 \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
643 QAbstractItemModel provides a hierarchical tree of data, whereas
644 QML only operates on list data. \c rootIndex allows the children of
645 any node in a QAbstractItemModel to be provided by this model.
647 This property only affects models of type QAbstractItemModel that
648 are hierarchical (e.g, a tree model).
650 For example, here is a simple interactive file system browser.
651 When a directory name is clicked, the view's \c rootIndex is set to the
652 QModelIndex node of the clicked directory, thus updating the view to show
653 the new directory's contents.
656 \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0
659 \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0
661 If the \l model is a QAbstractItemModel subclass, the delegate can also
662 reference a \c hasModelChildren property (optionally qualified by a
663 \e model. prefix) that indicates whether the delegate's model item has
667 \sa modelIndex(), parentModelIndex()
669 QVariant QQuickVisualDataModel::rootIndex() const
671 Q_D(const QQuickVisualDataModel);
672 return d->m_adaptorModel->rootIndex();
675 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
677 Q_D(QQuickVisualDataModel);
678 d->m_adaptorModel->setRootIndex(root);
682 \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
684 QAbstractItemModel provides a hierarchical tree of data, whereas
685 QML only operates on list data. This function assists in using
688 Returns a QModelIndex for the specified index.
689 This value can be assigned to rootIndex.
693 QVariant QQuickVisualDataModel::modelIndex(int idx) const
695 Q_D(const QQuickVisualDataModel);
696 return d->m_adaptorModel->modelIndex(idx);
700 \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
702 QAbstractItemModel provides a hierarchical tree of data, whereas
703 QML only operates on list data. This function assists in using
706 Returns a QModelIndex for the parent of the current rootIndex.
707 This value can be assigned to rootIndex.
711 QVariant QQuickVisualDataModel::parentModelIndex() const
713 Q_D(const QQuickVisualDataModel);
714 return d->m_adaptorModel->parentModelIndex();
718 \qmlproperty int QtQuick2::VisualDataModel::count
721 int QQuickVisualDataModel::count() const
723 Q_D(const QQuickVisualDataModel);
726 return d->m_compositor.count(d->m_compositorGroup);
729 void QQuickVisualDataModelPrivate::destroy(QObject *object)
731 QObjectPrivate *p = QObjectPrivate::get(object);
732 Q_ASSERT(p->declarativeData);
733 QDeclarativeData *data = static_cast<QDeclarativeData*>(p->declarativeData);
734 if (data->ownContext && data->context)
735 data->context->clearContext();
736 object->deleteLater();
739 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
741 QQuickVisualDataModel::ReleaseFlags stat = 0;
745 int cacheIndex = cacheIndexOf(object);
746 if (cacheIndex != -1) {
747 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
748 if (cacheItem->releaseObject()) {
750 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
751 emitDestroyingItem(item);
752 cacheItem->object = 0;
753 stat |= QQuickVisualModel::Destroyed;
754 if (!cacheItem->isReferenced()) {
755 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
756 m_cache.removeAt(cacheIndex);
758 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
761 stat |= QQuickVisualDataModel::Referenced;
768 Returns ReleaseStatus flags.
771 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
773 Q_D(QQuickVisualDataModel);
774 QQuickVisualModel::ReleaseFlags stat = d->release(item);
775 if (stat & Destroyed)
776 item->setParentItem(0);
780 void QQuickVisualDataModelPrivate::group_append(
781 QDeclarativeListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
783 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
786 if (d->m_groupCount == 11) {
787 qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
790 d->m_groups[d->m_groupCount] = group;
791 d->m_groupCount += 1;
794 int QQuickVisualDataModelPrivate::group_count(
795 QDeclarativeListProperty<QQuickVisualDataGroup> *property)
797 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
798 return d->m_groupCount - 1;
801 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
802 QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index)
804 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
805 return index >= 0 && index < d->m_groupCount - 1
806 ? d->m_groups[index + 1]
811 \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
813 This property holds a visual data model's group definitions.
815 Groups define a sub-set of the items in a visual data model and can be used to filter
818 For every group defined in a VisualDataModel two attached properties are added to each
819 delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
820 item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
821 index of the item in that group.
823 The following example illustrates using groups to select items in a model.
825 \snippet doc/src/snippets/declarative/visualdatagroup.qml 0
828 QDeclarativeListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
830 Q_D(QQuickVisualDataModel);
831 return QDeclarativeListProperty<QQuickVisualDataGroup>(
834 QQuickVisualDataModelPrivate::group_append,
835 QQuickVisualDataModelPrivate::group_count,
836 QQuickVisualDataModelPrivate::group_at);
840 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
842 This property holds visual data model's default group to which all new items are added.
845 QQuickVisualDataGroup *QQuickVisualDataModel::items()
847 Q_D(QQuickVisualDataModel);
852 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
854 This property holds visual data model's persisted items group.
856 Items in this group are not destroyed when released by a view, instead they are persisted
857 until removed from the group.
859 An item can be removed from the persistedItems group by setting the
860 VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
861 at that time it will be destroyed. Adding an item to this group will not create a new
864 Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
868 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
870 Q_D(QQuickVisualDataModel);
871 return d->m_persistedItems;
875 \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
877 This property holds the name of the group used to filter the visual data model.
879 Only items which belong to this group are visible to a view.
881 By default this is the \l items group.
884 QString QQuickVisualDataModel::filterGroup() const
886 Q_D(const QQuickVisualDataModel);
887 return d->m_filterGroup;
890 void QQuickVisualDataModel::setFilterGroup(const QString &group)
892 Q_D(QQuickVisualDataModel);
894 if (d->m_transaction) {
895 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
899 if (d->m_filterGroup != group) {
900 d->m_filterGroup = group;
901 d->updateFilterGroup();
902 emit filterGroupChanged();
906 void QQuickVisualDataModel::resetFilterGroup()
908 setFilterGroup(QStringLiteral("items"));
911 void QQuickVisualDataModelPrivate::updateFilterGroup()
913 Q_Q(QQuickVisualDataModel);
914 if (!m_cacheMetaType)
917 QDeclarativeListCompositor::Group previousGroup = m_compositorGroup;
918 m_compositorGroup = Compositor::Default;
919 for (int i = 1; i < m_groupCount; ++i) {
920 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
921 m_compositorGroup = Compositor::Group(i);
926 QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
927 if (m_compositorGroup != previousGroup) {
928 QVector<QDeclarativeChangeSet::Remove> removes;
929 QVector<QDeclarativeChangeSet::Insert> inserts;
930 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
932 QDeclarativeChangeSet changeSet;
933 changeSet.apply(removes, inserts);
934 emit q->modelUpdated(changeSet, false);
936 if (changeSet.difference() != 0)
937 emit q->countChanged();
940 foreach (QQuickVisualPartsModel *model, m_parts->models)
941 model->updateFilterGroup(m_compositorGroup, changeSet);
947 \qmlproperty object QtQuick2::VisualDataModel::parts
949 The \a parts property selects a VisualDataModel which creates
950 delegates from the part named. This is used in conjunction with
951 the \l Package element.
953 For example, the code below selects a model which creates
954 delegates named \e list from a \l Package:
960 Item { Package.name: "list" }
966 width: 200; height:200
967 model: visualModel.parts.list
974 QObject *QQuickVisualDataModel::parts()
976 Q_D(QQuickVisualDataModel);
978 d->m_parts = new QQuickVisualDataModelParts(this);
982 void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
984 for (int i = 1; i < m_groupCount; ++i)
985 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
988 void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
990 for (int i = 1; i < m_groupCount; ++i)
991 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
994 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *package)
996 for (int i = 1; i < m_groupCount; ++i)
997 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
1000 void QVDMIncubationTask::statusChanged(Status status)
1002 vdm->incubatorStatusChanged(this, status);
1005 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
1007 Q_Q(QQuickVisualDataModel);
1008 if (!incubationTask->isError())
1009 incubationTask->clear();
1010 m_finishedIncubating.append(incubationTask);
1011 if (!m_incubatorCleanupScheduled) {
1012 m_incubatorCleanupScheduled = true;
1013 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
1017 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status)
1019 Q_Q(QQuickVisualDataModel);
1020 if (status != QDeclarativeIncubator::Ready && status != QDeclarativeIncubator::Error)
1023 QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
1024 cacheItem->incubationTask = 0;
1026 if (status == QDeclarativeIncubator::Ready) {
1027 incubationTask->incubating = 0;
1028 releaseIncubator(incubationTask);
1029 if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
1030 emitCreatedPackage(cacheItem, package);
1031 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
1032 emitCreatedItem(cacheItem, item);
1033 } else if (status == QDeclarativeIncubator::Error) {
1034 delete incubationTask->incubatingContext;
1035 incubationTask->incubatingContext = 0;
1036 if (!cacheItem->isReferenced()) {
1037 int cidx = m_cache.indexOf(cacheItem);
1038 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
1039 m_cache.removeAt(cidx);
1041 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1043 releaseIncubator(incubationTask);
1044 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
1048 void QVDMIncubationTask::setInitialState(QObject *o)
1050 vdm->setInitialState(this, o);
1053 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
1055 QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
1056 cacheItem->object = o;
1057 QDeclarative_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
1058 incubationTask->incubatingContext = 0;
1060 cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
1061 cacheItem->attached->m_cacheItem = cacheItem;
1062 new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
1063 cacheItem->attached->emitChanges();
1065 if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
1066 emitInitPackage(cacheItem, package);
1067 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
1068 emitInitItem(cacheItem, item);
1071 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
1073 Q_Q(QQuickVisualDataModel);
1074 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
1075 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
1079 Compositor::iterator it = m_compositor.find(group, index);
1080 QQuickVisualDataModelCacheItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
1082 cacheItem = new QQuickVisualDataModelCacheItem(m_cacheMetaType);
1083 for (int i = 0; i < m_groupCount; ++i)
1084 cacheItem->index[i] = it.index[i];
1085 cacheItem->groups = it->flags & Compositor::GroupMask;
1088 int modelIndex = it.modelIndex();
1090 if (!it->inCache()) {
1091 m_cache.insert(it.cacheIndex, cacheItem);
1092 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
1093 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1096 if (cacheItem->incubationTask) {
1097 if (!asynchronous) {
1098 // previously requested async - now needed immediately
1099 cacheItem->incubationTask->forceCompletion();
1101 } else if (!cacheItem->object) {
1102 QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
1103 cacheItem->incubationTask = incubator;
1105 QObject *data = m_adaptorModel->data(modelIndex);
1107 QDeclarativeContext *creationContext = m_delegate->creationContext();
1108 QDeclarativeContext *rootContext = new QDeclarativeContext(
1109 creationContext ? creationContext : m_context.data());
1110 QDeclarativeContext *ctxt = rootContext;
1111 if (m_adaptorModel->flags() & QQuickVisualAdaptorModel::ProxiedObject) {
1112 if (QQuickVisualAdaptorModelProxyInterface *proxy = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(data)) {
1113 ctxt->setContextObject(proxy->proxiedObject());
1114 ctxt = new QDeclarativeContext(ctxt, ctxt);
1118 QDeclarative_setParent_noEvent(data, ctxt);
1119 ctxt->setContextProperty(QLatin1String("model"), data);
1120 ctxt->setContextObject(data);
1122 incubator->incubating = cacheItem;
1123 incubator->incubatingContext = rootContext;
1124 m_delegate->create(*incubator, ctxt, m_context);
1127 if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
1128 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
1129 if (cacheItem->object && reference)
1130 cacheItem->referenceObject();
1131 return cacheItem->object;
1135 If asynchronous is true or the component is being loaded asynchronously due
1136 to an ancestor being loaded asynchronously, item() may return 0. In this
1137 case itemCreated() will be emitted when the item is available. The item
1138 at this stage does not have any references, so item() must be called again
1139 to ensure a reference is held. Any call to item() which returns a valid item
1140 must be matched by a call to release() in order to destroy the item.
1142 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
1144 Q_D(QQuickVisualDataModel);
1145 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
1146 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
1150 QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
1154 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
1158 if (!d->m_delegateValidated) {
1160 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
1161 d->m_delegateValidated = true;
1166 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
1168 Compositor::iterator it = m_compositor.find(group, index);
1169 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
1170 return model->stringValue(it.modelIndex(), name);
1175 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
1177 Q_D(QQuickVisualDataModel);
1178 return d->stringValue(d->m_compositorGroup, index, name);
1181 int QQuickVisualDataModelPrivate::cacheIndexOf(QObject *object) const
1183 for (int cacheIndex = 0; cacheIndex < m_cache.count(); ++cacheIndex) {
1184 if (m_cache.at(cacheIndex)->object == object)
1190 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
1192 Q_D(const QQuickVisualDataModel);
1193 const int cacheIndex = d->cacheIndexOf(item);
1194 return cacheIndex != -1
1195 ? d->m_cache.at(cacheIndex)->index[d->m_compositorGroup]
1199 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
1201 Q_D(QQuickVisualDataModel);
1202 d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles);
1203 d->watchedRoles = roles;
1206 void QQuickVisualDataModelPrivate::addGroups(Compositor::Group group, int index, int count, int groupFlags)
1208 QVector<Compositor::Insert> inserts;
1209 m_compositor.setFlags(group, index, count, groupFlags, &inserts);
1210 itemsInserted(inserts);
1214 void QQuickVisualDataModelPrivate::removeGroups(Compositor::Group group, int index, int count, int groupFlags)
1216 QVector<Compositor::Remove> removes;
1217 m_compositor.clearFlags(group, index, count, groupFlags, &removes);
1218 itemsRemoved(removes);
1222 void QQuickVisualDataModelPrivate::setGroups(Compositor::Group group, int index, int count, int groupFlags)
1224 QVector<Compositor::Insert> inserts;
1225 m_compositor.setFlags(group, index, count, groupFlags, &inserts);
1226 itemsInserted(inserts);
1228 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1229 QVector<Compositor::Remove> removes;
1230 m_compositor.clearFlags(group, index, count, removeFlags, &removes);
1231 itemsRemoved(removes);
1236 bool QQuickVisualDataModel::event(QEvent *e)
1238 Q_D(QQuickVisualDataModel);
1239 if (e->type() == QEvent::UpdateRequest) {
1240 d->m_adaptorModel->fetchMore();
1241 } else if (e->type() == QEvent::User) {
1242 d->m_incubatorCleanupScheduled = false;
1243 qDeleteAll(d->m_finishedIncubating);
1244 d->m_finishedIncubating.clear();
1246 return QQuickVisualModel::event(e);
1249 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1254 QVarLengthArray<QVector<QDeclarativeChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1256 foreach (const Compositor::Change &change, changes) {
1257 for (int i = 1; i < m_groupCount; ++i) {
1258 if (change.inGroup(i)) {
1259 translatedChanges[i].append(
1260 QDeclarativeChangeSet::Change(change.index[i], change.count));
1265 for (int i = 1; i < m_groupCount; ++i)
1266 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1269 void QQuickVisualDataModel::_q_itemsChanged(int index, int count)
1271 Q_D(QQuickVisualDataModel);
1274 QVector<Compositor::Change> changes;
1275 d->m_compositor.listItemsChanged(d->m_adaptorModel, index, count, &changes);
1276 d->itemsChanged(changes);
1280 void QQuickVisualDataModelPrivate::itemsInserted(
1281 const QVector<Compositor::Insert> &inserts,
1282 QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1283 QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
1287 int inserted[Compositor::MaximumGroupCount];
1288 for (int i = 1; i < m_groupCount; ++i)
1291 foreach (const Compositor::Insert &insert, inserts) {
1292 for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
1293 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1294 if (!cacheItem->groups)
1296 for (int i = 1; i < m_groupCount; ++i)
1297 cacheItem->index[i] += inserted[i];
1299 for (int i = 1; i < m_groupCount; ++i) {
1300 if (insert.inGroup(i)) {
1301 (*translatedInserts)[i].append(
1302 QDeclarativeChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1303 inserted[i] += insert.count;
1307 if (!insert.inCache())
1310 if (movedItems && insert.isMove()) {
1311 QList<QQuickVisualDataModelCacheItem *> items = movedItems->take(insert.moveId);
1312 Q_ASSERT(items.count() == insert.count);
1313 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1315 if (insert.inGroup()) {
1316 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1317 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1318 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1319 for (int i = 1; i < m_groupCount; ++i) {
1320 cacheItem->index[i] = cacheItem->groups & (1 << i)
1321 ? insert.index[i] + offset
1326 cacheIndex = insert.cacheIndex + insert.count;
1329 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1330 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1331 if (!cacheItem->groups)
1333 for (int i = 1; i < m_groupCount; ++i)
1334 cacheItem->index[i] += inserted[i];
1338 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1340 QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1341 itemsInserted(inserts, &translatedInserts);
1342 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1346 for (int i = 1; i < m_groupCount; ++i)
1347 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1350 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1353 Q_D(QQuickVisualDataModel);
1356 QVector<Compositor::Insert> inserts;
1357 d->m_compositor.listItemsInserted(d->m_adaptorModel, index, count, &inserts);
1358 d->itemsInserted(inserts);
1362 void QQuickVisualDataModelPrivate::itemsRemoved(
1363 const QVector<Compositor::Remove> &removes,
1364 QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1365 QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
1368 int removedCache = 0;
1370 int removed[Compositor::MaximumGroupCount];
1371 for (int i = 1; i < m_groupCount; ++i)
1374 foreach (const Compositor::Remove &remove, removes) {
1375 for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
1376 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1377 if (!cacheItem->groups)
1379 for (int i = 1; i < m_groupCount; ++i)
1380 cacheItem->index[i] -= removed[i];
1382 for (int i = 1; i < m_groupCount; ++i) {
1383 if (remove.inGroup(i)) {
1384 (*translatedRemoves)[i].append(
1385 QDeclarativeChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1386 removed[i] += remove.count;
1390 if (!remove.inCache())
1393 if (movedItems && remove.isMove()) {
1394 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1395 QList<QQuickVisualDataModelCacheItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1396 QList<QQuickVisualDataModelCacheItem *>::iterator end = begin + remove.count;
1397 m_cache.erase(begin, end);
1399 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1400 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1401 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1402 destroy(cacheItem->object);
1403 if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
1404 emitDestroyingPackage(package);
1405 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
1406 emitDestroyingItem(item);
1407 cacheItem->object = 0;
1409 if (remove.groups() == cacheItem->groups && !cacheItem->isReferenced()) {
1410 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1411 m_cache.removeAt(cacheIndex);
1415 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1416 } else if (remove.groups() == cacheItem->groups) {
1417 cacheItem->groups = 0;
1418 for (int i = 1; i < m_groupCount; ++i)
1419 cacheItem->index[i] = -1;
1421 for (int i = 1; i < m_groupCount; ++i) {
1422 if (remove.inGroup(i))
1423 cacheItem->index[i] = remove.index[i];
1425 cacheItem->groups &= ~remove.flags & Compositor::GroupMask;
1431 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1432 QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1433 if (!cacheItem->groups)
1435 for (int i = 1; i < m_groupCount; ++i)
1436 cacheItem->index[i] -= removed[i];
1440 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1442 QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1443 itemsRemoved(removes, &translatedRemoves);
1444 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1448 for (int i = 1; i < m_groupCount; ++i)
1449 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1452 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1454 Q_D(QQuickVisualDataModel);
1458 QVector<Compositor::Remove> removes;
1459 d->m_compositor.listItemsRemoved(d->m_adaptorModel, index, count, &removes);
1460 d->itemsRemoved(removes);
1464 void QQuickVisualDataModelPrivate::itemsMoved(
1465 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1467 QHash<int, QList<QQuickVisualDataModelCacheItem *> > movedItems;
1469 QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1470 itemsRemoved(removes, &translatedRemoves, &movedItems);
1472 QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1473 itemsInserted(inserts, &translatedInserts, &movedItems);
1474 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1475 Q_ASSERT(movedItems.isEmpty());
1479 for (int i = 1; i < m_groupCount; ++i) {
1480 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1481 translatedRemoves.at(i),
1482 translatedInserts.at(i));
1486 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1488 Q_D(QQuickVisualDataModel);
1492 QVector<Compositor::Remove> removes;
1493 QVector<Compositor::Insert> inserts;
1494 d->m_compositor.listItemsMoved(d->m_adaptorModel, from, to, count, &removes, &inserts);
1495 d->itemsMoved(removes, inserts);
1499 template <typename T> v8::Local<v8::Array>
1500 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1502 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1503 v8::Local<v8::String> indexKey = v8::String::New("index");
1504 v8::Local<v8::String> countKey = v8::String::New("count");
1505 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1507 for (int i = 0; i < changes.count(); ++i) {
1508 v8::Local<v8::Object> object = v8::Object::New();
1509 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1510 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1511 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1512 indexes->Set(i, object);
1517 void QQuickVisualDataModelPrivate::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
1519 Q_Q(QQuickVisualDataModel);
1520 emit q->modelUpdated(changeSet, reset);
1521 if (changeSet.difference() != 0)
1522 emit q->countChanged();
1525 void QQuickVisualDataModelPrivate::emitChanges()
1527 if (m_transaction || !m_complete)
1530 m_transaction = true;
1531 QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(m_context->engine());
1532 for (int i = 1; i < m_groupCount; ++i)
1533 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1534 m_transaction = false;
1536 const bool reset = m_reset;
1538 for (int i = 1; i < m_groupCount; ++i)
1539 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1541 foreach (QQuickVisualDataModelCacheItem *cacheItem, m_cache) {
1542 if (cacheItem->object && cacheItem->attached)
1543 cacheItem->attached->emitChanges();
1547 void QQuickVisualDataModel::_q_modelReset(int oldCount, int newCount)
1549 Q_D(QQuickVisualDataModel);
1553 QVector<Compositor::Remove> removes;
1554 QVector<Compositor::Insert> inserts;
1556 d->m_compositor.listItemsRemoved(d->m_adaptorModel, 0, oldCount, &removes);
1558 d->m_compositor.listItemsInserted(d->m_adaptorModel, 0, newCount, &inserts);
1559 d->itemsMoved(removes, inserts);
1564 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1566 return QQuickVisualDataModelAttached::properties(obj);
1569 //============================================================================
1571 QQuickVisualDataModelCacheMetaType::QQuickVisualDataModelCacheMetaType(
1572 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1574 , groupCount(groupNames.count() + 1)
1575 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1576 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
1579 , groupNames(groupNames)
1581 QMetaObjectBuilder builder;
1582 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1583 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1584 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1586 v8::HandleScope handleScope;
1587 v8::Context::Scope contextScope(engine->context());
1588 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
1589 ft->InstanceTemplate()->SetHasExternalResource(true);
1590 ft->PrototypeTemplate()->SetAccessor(v8::String::New("model"), get_model);
1591 ft->PrototypeTemplate()->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
1594 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1595 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1596 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1597 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1598 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1599 propertyName.toUtf8(), "bool", notifierId);
1600 propertyBuilder.setWritable(true);
1602 ft->PrototypeTemplate()->SetAccessor(
1603 engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1605 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1606 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1607 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1608 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1609 propertyName.toUtf8(), "int", notifierId);
1610 propertyBuilder.setWritable(true);
1612 ft->PrototypeTemplate()->SetAccessor(
1613 engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1616 metaObject = builder.toMetaObject();
1618 constructor = qPersistentNew<v8::Function>(ft->GetFunction());
1621 QQuickVisualDataModelCacheMetaType::~QQuickVisualDataModelCacheMetaType()
1624 qPersistentDispose(constructor);
1627 int QQuickVisualDataModelCacheMetaType::parseGroups(const QStringList &groups) const
1630 foreach (const QString &groupName, groups) {
1631 int index = groupNames.indexOf(groupName);
1633 groupFlags |= 2 << index;
1638 int QQuickVisualDataModelCacheMetaType::parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groups) const
1641 if (groups->IsString()) {
1642 const QString groupName = engine->toString(groups);
1643 int index = groupNames.indexOf(groupName);
1645 groupFlags |= 2 << index;
1646 } else if (groups->IsArray()) {
1647 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1648 for (uint i = 0; i < array->Length(); ++i) {
1649 const QString groupName = engine->toString(array->Get(i));
1650 int index = groupNames.indexOf(groupName);
1652 groupFlags |= 2 << index;
1658 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_model(
1659 v8::Local<v8::String>, const v8::AccessorInfo &info)
1661 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1663 V8THROW_ERROR("Not a valid VisualData object");
1664 if (!cacheItem->metaType->model)
1665 return v8::Undefined();
1668 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1669 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1670 if (cacheItem->groups & (1 << i)) {
1671 Compositor::iterator it = model->m_compositor.find(
1672 Compositor::Group(i), cacheItem->index[i]);
1673 if (QQuickVisualAdaptorModel *list = it.list<QQuickVisualAdaptorModel>())
1674 data = list->data(it.modelIndex());
1679 return v8::Undefined();
1680 return cacheItem->engine->newQObject(data);
1683 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_groups(
1684 v8::Local<v8::String>, const v8::AccessorInfo &info)
1686 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1688 V8THROW_ERROR("Not a valid VisualData object");
1691 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1692 if (cacheItem->groups & (1 << i))
1693 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1696 return cacheItem->engine->fromVariant(groups);
1699 void QQuickVisualDataModelCacheMetaType::set_groups(
1700 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1702 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1704 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1706 if (!cacheItem->metaType->model)
1708 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1710 const int groupFlags = model->m_cacheMetaType->parseGroups(cacheItem->engine, value);
1711 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1712 if (cacheItem->groups & (1 << i)) {
1713 model->setGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlags);
1719 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_member(
1720 v8::Local<v8::String>, const v8::AccessorInfo &info)
1722 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1724 V8THROW_ERROR("Not a valid VisualData object");
1726 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1729 void QQuickVisualDataModelCacheMetaType::set_member(
1730 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1732 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1734 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1736 if (!cacheItem->metaType->model)
1738 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1740 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1741 const bool member = value->BooleanValue();
1742 const int groupFlag = (1 << group);
1743 if (member == ((cacheItem->groups & groupFlag) != 0))
1746 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1747 if (cacheItem->groups & (1 << i)) {
1749 model->addGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
1751 model->removeGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
1757 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_index(
1758 v8::Local<v8::String>, const v8::AccessorInfo &info)
1760 QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1762 V8THROW_ERROR("Not a valid VisualData object");
1764 return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
1768 //---------------------------------------------------------------------------
1770 QQuickVisualDataModelCacheItem::~QQuickVisualDataModelCacheItem()
1772 Q_ASSERT(scriptRef == 0);
1773 Q_ASSERT(objectRef == 0);
1775 if (incubationTask && metaType->model)
1776 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1778 metaType->release();
1781 void QQuickVisualDataModelCacheItem::Dispose()
1787 if (metaType->model) {
1788 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1789 const int cacheIndex = model->m_cache.indexOf(this);
1790 if (cacheIndex != -1) {
1791 model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1792 model->m_cache.removeAt(cacheIndex);
1798 //---------------------------------------------------------------------------
1800 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1801 QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType)
1802 : attached(attached)
1803 , metaType(metaType)
1806 *static_cast<QMetaObject *>(this) = *metaType->metaObject;
1807 QObjectPrivate::get(attached)->metaObject = this;
1810 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1812 metaType->release();
1815 int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
1817 if (call == QMetaObject::ReadProperty) {
1818 if (_id >= metaType->indexPropertyOffset) {
1819 Compositor::Group group = Compositor::Group(_id - metaType->indexPropertyOffset + 1);
1820 *static_cast<int *>(arguments[0]) = attached->m_cacheItem->index[group];
1822 } else if (_id >= metaType->memberPropertyOffset) {
1823 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1824 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1827 } else if (call == QMetaObject::WriteProperty) {
1828 if (_id >= metaType->memberPropertyOffset) {
1829 if (!metaType->model)
1831 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1832 const bool member = attached->m_cacheItem->groups & (1 << group);
1833 if (member != *static_cast<bool *>(arguments[0])) {
1834 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1835 const int cacheIndex = model->m_cache.indexOf(attached->m_cacheItem);
1837 model->removeGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
1839 model->addGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
1844 return attached->qt_metacall(call, _id, arguments);
1847 void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelCacheItem *item)
1850 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1851 m_previousIndex[i] = m_cacheItem->index[i];
1855 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1857 This attached property holds the visual data model this delegate instance belongs to.
1859 It is attached to each instance of the delegate.
1862 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1864 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1868 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1870 This attached property holds the name of VisualDataGroups the item belongs to.
1872 It is attached to each instance of the delegate.
1875 QStringList QQuickVisualDataModelAttached::groups() const
1881 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1882 if (m_cacheItem->groups & (1 << i))
1883 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1888 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1893 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1895 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1896 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1897 model->setGroups(Compositor::Cache, cacheIndex, 1, groupFlags);
1901 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1903 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1905 Changing this property will add or remove the item from the items group.
1907 It is attached to each instance of the delegate.
1911 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1913 This attached property holds the index of the item in the default \l items VisualDataGroup.
1915 It is attached to each instance of the delegate.
1919 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1921 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1923 Changing this property will add or remove the item from the items group. Change with caution
1924 as removing an item from the persistedItems group will destroy the current instance if it is
1925 not referenced by a model.
1927 It is attached to each instance of the delegate.
1931 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
1933 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
1935 It is attached to each instance of the delegate.
1938 void QQuickVisualDataModelAttached::emitChanges()
1940 if (m_modelChanged) {
1941 m_modelChanged = false;
1942 emit modelChanged();
1945 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
1946 m_previousGroups = m_cacheItem->groups;
1948 int indexChanges = 0;
1949 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1950 if (m_previousIndex[i] != m_cacheItem->index[i]) {
1951 m_previousIndex[i] = m_cacheItem->index[i];
1952 indexChanges |= (1 << i);
1957 const QMetaObject *meta = metaObject();
1958 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1959 if (groupChanges & (1 << i))
1960 QMetaObject::activate(this, meta, notifierId, 0);
1962 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1963 if (indexChanges & (1 << i))
1964 QMetaObject::activate(this, meta, notifierId, 0);
1968 emit groupsChanged();
1971 //============================================================================
1973 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
1980 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
1982 Q_Q(QQuickVisualDataGroup);
1983 static int idx = signalIndex("changed(QDeclarativeV8Handle,QDeclarativeV8Handle)");
1984 if (isSignalConnected(idx) && !changeSet.isEmpty()) {
1985 v8::HandleScope handleScope;
1986 v8::Context::Scope contextScope(engine->context());
1987 v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes());
1988 v8::Local<v8::Array> inserted = QQuickVisualDataModelPrivate::buildChangeList(changeSet.inserts());
1990 QDeclarativeV8Handle::fromHandle(removed), QDeclarativeV8Handle::fromHandle(inserted));
1992 if (changeSet.difference() != 0)
1993 emit q->countChanged();
1996 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
1998 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1999 it->emitModelUpdated(changeSet, reset);
2003 void QQuickVisualDataGroupPrivate::createdPackage(int index, QDeclarativePackage *package)
2005 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2006 it->createdPackage(index, package);
2009 void QQuickVisualDataGroupPrivate::initPackage(int index, QDeclarativePackage *package)
2011 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2012 it->initPackage(index, package);
2015 void QQuickVisualDataGroupPrivate::destroyingPackage(QDeclarativePackage *package)
2017 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2018 it->destroyingPackage(package);
2022 \qmlclass VisualDataGroup QQuickVisualDataGroup
2023 \inqmlmodule QtQuick 2
2024 \ingroup qml-working-with-data
2025 \brief The VisualDataGroup encapsulates a filtered set of visual data items.
2029 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2030 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2034 QQuickVisualDataGroup::QQuickVisualDataGroup(
2035 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2036 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2038 Q_D(QQuickVisualDataGroup);
2040 d->setModel(model, Compositor::Group(index));
2043 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2048 \qmlproperty string QtQuick2::VisualDataGroup::name
2050 This property holds the name of the group.
2052 Each group in a model must have a unique name starting with a lower case letter.
2055 QString QQuickVisualDataGroup::name() const
2057 Q_D(const QQuickVisualDataGroup);
2061 void QQuickVisualDataGroup::setName(const QString &name)
2063 Q_D(QQuickVisualDataGroup);
2066 if (d->name != name) {
2073 \qmlproperty int QtQuick2::VisualDataGroup::count
2075 This property holds the number of items in the group.
2078 int QQuickVisualDataGroup::count() const
2080 Q_D(const QQuickVisualDataGroup);
2083 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2087 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2089 This property holds whether new items are assigned to this group by default.
2092 bool QQuickVisualDataGroup::defaultInclude() const
2094 Q_D(const QQuickVisualDataGroup);
2095 return d->defaultInclude;
2098 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2100 Q_D(QQuickVisualDataGroup);
2101 if (d->defaultInclude != include) {
2102 d->defaultInclude = include;
2106 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2108 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2110 emit defaultIncludeChanged();
2115 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2117 Returns a javascript object describing the item at \a index in the group.
2119 The returned object contains the same information that is available to a delegate from the
2120 VisualDataModel attached as well as the model for that item. It has the properties:
2123 \o \b model The model data of the item. This is the same as the model context property in
2125 \o \b groups A list the of names of groups the item is a member of. This property can be
2126 written to change the item's membership.
2127 \o \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2128 Writing to this property will add or remove the item from the group.
2129 \o \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2130 \o \b {in\i{GroupName}} Whether the item belongs to the dynamic group \i groupName. Writing to
2131 this property will add or remove the item from the group.
2132 \o \b {\i{groupName}Index} The index of the item within the dynamic group \i groupName.
2136 QDeclarativeV8Handle QQuickVisualDataGroup::get(int index)
2138 Q_D(QQuickVisualDataGroup);
2140 return QDeclarativeV8Handle::fromHandle(v8::Undefined());;
2142 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2143 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2144 qmlInfo(this) << tr("get: index out of range");
2145 return QDeclarativeV8Handle::fromHandle(v8::Undefined());
2148 Compositor::iterator it = model->m_compositor.find(d->group, index);
2149 QQuickVisualDataModelCacheItem *cacheItem = it->inCache()
2150 ? model->m_cache.at(it.cacheIndex)
2154 cacheItem = new QQuickVisualDataModelCacheItem(model->m_cacheMetaType);
2155 for (int i = 0; i < model->m_groupCount; ++i)
2156 cacheItem->index[i] = it.index[i];
2157 cacheItem->groups = it->flags & Compositor::GroupMask;
2159 model->m_cache.insert(it.cacheIndex, cacheItem);
2160 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2163 ++cacheItem->scriptRef;
2165 v8::Local<v8::Object> rv = model->m_cacheMetaType->constructor->NewInstance();
2166 rv->SetExternalResource(cacheItem);
2167 return QDeclarativeV8Handle::fromHandle(rv);
2171 \qmlmethod QtQuick2::VisualDataGroup::create(int index)
2173 Returns a reference to the instantiated item at \a index in the group.
2175 All items returned by create are added to the persistedItems group. Items in this
2176 group remain instantiated when not referenced by any view.
2179 QObject *QQuickVisualDataGroup::create(int index)
2181 Q_D(QQuickVisualDataGroup);
2185 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2186 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2187 qmlInfo(this) << tr("create: index out of range");
2191 QObject *object = model->object(d->group, index, false, false);
2193 model->addGroups(d->group, index, 1, Compositor::PersistedFlag);
2198 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2200 Removes \a count items starting at \a index from the group.
2203 void QQuickVisualDataGroup::remove(QDeclarativeV8Function *args)
2205 Q_D(QQuickVisualDataGroup);
2211 if (args->Length() == 0)
2215 v8::Local<v8::Value> v = (*args)[i];
2218 index = v->Int32Value();
2220 if (++i < args->Length()) {
2223 count = v->Int32Value();
2226 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2228 qmlInfo(this) << tr("remove: invalid count");
2229 } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
2230 qmlInfo(this) << tr("remove: index out of range");
2231 } else if (count > 0) {
2232 model->removeGroups(d->group, index, count, 1 << d->group);
2236 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2237 QDeclarativeV8Function *args, int *index, int *count, int *groups) const
2239 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2242 if (args->Length() < 2)
2246 v8::Local<v8::Value> v = (*args)[i];
2249 *index = v->Int32Value();
2253 *count = v->Int32Value();
2255 if (++i == args->Length())
2260 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(args->engine(), v);
2266 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2268 Adds \a count items starting at \a index to \a groups.
2271 void QQuickVisualDataGroup::addGroups(QDeclarativeV8Function *args)
2273 Q_D(QQuickVisualDataGroup);
2278 if (!d->parseGroupArgs(args, &index, &count, &groups))
2281 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2283 qmlInfo(this) << tr("addGroups: invalid count");
2284 } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
2285 qmlInfo(this) << tr("addGroups: index out of range");
2286 } else if (count > 0 && groups) {
2287 model->addGroups(d->group, index, count, groups);
2292 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2294 Removes \a count items starting at \a index from \a groups.
2297 void QQuickVisualDataGroup::removeGroups(QDeclarativeV8Function *args)
2299 Q_D(QQuickVisualDataGroup);
2304 if (!d->parseGroupArgs(args, &index, &count, &groups))
2307 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2309 qmlInfo(this) << tr("removeGroups: invalid count");
2310 } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
2311 qmlInfo(this) << tr("removeGroups: index out of range");
2312 } else if (count > 0 && groups) {
2313 model->removeGroups(d->group, index, count, groups);
2318 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2320 Sets the \a groups \a count items starting at \a index belong to.
2323 void QQuickVisualDataGroup::setGroups(QDeclarativeV8Function *args)
2325 Q_D(QQuickVisualDataGroup);
2330 if (!d->parseGroupArgs(args, &index, &count, &groups))
2333 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2335 qmlInfo(this) << tr("setGroups: invalid count");
2336 } else if (index < 0 || index + count > model->m_compositor.count(d->group)) {
2337 qmlInfo(this) << tr("setGroups: index out of range");
2338 } else if (count > 0) {
2339 model->setGroups(d->group, index, count, groups);
2344 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2346 Sets the \a groups \a count items starting at \a index belong to.
2350 \qmlmethod QtQuick2::VisualDataGroup::move(int from, int to, int count)
2352 Moves \a count at \a from in a group \a to a new position.
2355 void QQuickVisualDataGroup::move(QDeclarativeV8Function *args)
2357 Q_D(QQuickVisualDataGroup);
2359 if (args->Length() < 2)
2362 Compositor::Group fromGroup = d->group;
2363 Compositor::Group toGroup = d->group;
2369 v8::Local<v8::Value> v = (*args)[i];
2370 if (QQuickVisualDataGroup *group = qobject_cast<QQuickVisualDataGroup *>(args->engine()->toQObject(v))) {
2371 QQuickVisualDataGroupPrivate *g_d = QQuickVisualDataGroupPrivate::get(group);
2372 if (g_d->model != d->model)
2374 fromGroup = g_d->group;
2380 from = v->Int32Value();
2382 if (++i == args->Length())
2386 if (QQuickVisualDataGroup *group = qobject_cast<QQuickVisualDataGroup *>(args->engine()->toQObject(v))) {
2387 QQuickVisualDataGroupPrivate *g_d = QQuickVisualDataGroupPrivate::get(group);
2388 if (g_d->model != d->model)
2390 toGroup = g_d->group;
2392 if (++i == args->Length())
2399 to = v->Int32Value();
2401 if (++i < args->Length()) {
2404 count = v->Int32Value();
2407 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2410 qmlInfo(this) << tr("move: invalid count");
2411 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2412 qmlInfo(this) << tr("move: from index out of range");
2413 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count)) {
2414 qmlInfo(this) << tr("move: to index out of range");
2415 } else if (count > 0) {
2416 QVector<Compositor::Remove> removes;
2417 QVector<Compositor::Insert> inserts;
2419 model->m_compositor.move(fromGroup, from, toGroup, to, count, &removes, &inserts);
2420 model->itemsMoved(removes, inserts);
2421 model->emitChanges();
2427 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2429 This handler is called when items have been removed from or inserted into the group.
2431 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2432 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2434 Each index is adjusted for previous changes with all removed items preceding any inserted
2438 //============================================================================
2440 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2441 : QQuickVisualModel(*new QObjectPrivate, parent)
2444 , m_compositorGroup(Compositor::Cache)
2445 , m_inheritGroup(true)
2447 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2448 if (d->m_cacheMetaType) {
2449 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2450 m_compositorGroup = Compositor::Default;
2452 d->m_pendingParts.insert(this);
2456 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2460 QString QQuickVisualPartsModel::filterGroup() const
2463 return m_model->filterGroup();
2464 return m_filterGroup;
2467 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2469 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2470 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2474 if (m_filterGroup != group || m_inheritGroup) {
2475 m_filterGroup = group;
2476 m_inheritGroup = false;
2477 updateFilterGroup();
2479 emit filterGroupChanged();
2483 void QQuickVisualPartsModel::resetFilterGroup()
2485 if (!m_inheritGroup) {
2486 m_inheritGroup = true;
2487 updateFilterGroup();
2488 emit filterGroupChanged();
2492 void QQuickVisualPartsModel::updateFilterGroup()
2494 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2495 if (!model->m_cacheMetaType)
2498 if (m_inheritGroup) {
2499 if (m_filterGroup == model->m_filterGroup)
2501 m_filterGroup = model->m_filterGroup;
2504 QDeclarativeListCompositor::Group previousGroup = m_compositorGroup;
2505 m_compositorGroup = Compositor::Default;
2506 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2507 for (int i = 1; i < model->m_groupCount; ++i) {
2508 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2509 m_compositorGroup = Compositor::Group(i);
2514 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2515 if (m_compositorGroup != previousGroup) {
2516 QVector<QDeclarativeChangeSet::Remove> removes;
2517 QVector<QDeclarativeChangeSet::Insert> inserts;
2518 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2520 QDeclarativeChangeSet changeSet;
2521 changeSet.apply(removes, inserts);
2522 if (!changeSet.isEmpty())
2523 emit modelUpdated(changeSet, false);
2525 if (changeSet.difference() != 0)
2526 emit countChanged();
2530 void QQuickVisualPartsModel::updateFilterGroup(
2531 Compositor::Group group, const QDeclarativeChangeSet &changeSet)
2533 if (!m_inheritGroup)
2536 m_compositorGroup = group;
2537 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2539 if (!changeSet.isEmpty())
2540 emit modelUpdated(changeSet, false);
2542 if (changeSet.difference() != 0)
2543 emit countChanged();
2545 emit filterGroupChanged();
2548 int QQuickVisualPartsModel::count() const
2550 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2551 return model->m_delegate
2552 ? model->m_compositor.count(m_compositorGroup)
2556 bool QQuickVisualPartsModel::isValid() const
2558 return m_model->isValid();
2561 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2563 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2565 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2566 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2570 QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
2572 if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) {
2573 QObject *part = package->part(m_part);
2576 if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
2577 m_packaged.insertMulti(item, package);
2582 model->release(object);
2583 if (!model->m_delegateValidated) {
2585 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2586 model->m_delegateValidated = true;
2592 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2594 QQuickVisualModel::ReleaseFlags flags = 0;
2596 QHash<QObject *, QDeclarativePackage *>::iterator it = m_packaged.find(item);
2597 if (it != m_packaged.end()) {
2598 QDeclarativePackage *package = *it;
2599 QDeclarative_setParent_noEvent(item, package);
2600 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2601 flags = model->release(package);
2602 m_packaged.erase(it);
2603 if (!m_packaged.contains(item))
2604 flags &= ~Referenced;
2605 if (flags & Destroyed) {
2606 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2607 item->setParentItem(0);
2613 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2615 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2618 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2620 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2621 model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles);
2622 m_watchedRoles = roles;
2625 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2627 QHash<QObject *, QDeclarativePackage *>::const_iterator it = m_packaged.find(item);
2628 if (it != m_packaged.end()) {
2629 const QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2630 const int cacheIndex = model->cacheIndexOf(*it);
2631 return cacheIndex != -1
2632 ? model->m_cache.at(cacheIndex)->index[m_compositorGroup]
2638 void QQuickVisualPartsModel::createdPackage(int index, QDeclarativePackage *package)
2640 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2641 emit createdItem(index, item);
2644 void QQuickVisualPartsModel::initPackage(int index, QDeclarativePackage *package)
2646 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2647 emit initItem(index, item);
2650 void QQuickVisualPartsModel::destroyingPackage(QDeclarativePackage *package)
2652 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
2653 Q_ASSERT(!m_packaged.contains(item));
2654 emit destroyingItem(item);
2658 void QQuickVisualPartsModel::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
2660 emit modelUpdated(changeSet, reset);
2661 if (changeSet.difference() != 0)
2662 emit countChanged();
2668 #include <qquickvisualdatamodel.moc>