Don't attempt to destroy a null persisted item.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickvisualdatamodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickvisualdatamodel_p.h"
43 #include "qquickitem.h"
44
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>
51
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>
68
69 #include <QtCore/qhash.h>
70 #include <QtCore/qlist.h>
71
72 QT_BEGIN_NAMESPACE
73
74 typedef QDeclarativeListCompositor Compositor;
75
76 class QQuickVisualDataModelPrivate;
77 class QVDMIncubationTask : public QDeclarativeIncubator
78 {
79 public:
80     QVDMIncubationTask(QQuickVisualDataModelPrivate *l, IncubationMode mode)
81         : QDeclarativeIncubator(mode)
82         , incubating(0)
83         , incubatingContext(0)
84         , vdm(l) {}
85
86     virtual void statusChanged(Status);
87     virtual void setInitialState(QObject *);
88
89     QQuickVisualDataModelCacheItem *incubating;
90     QDeclarativeContext *incubatingContext;
91
92 private:
93     QQuickVisualDataModelPrivate *vdm;
94 };
95
96
97 class QQuickVisualDataGroupEmitter
98 {
99 public:
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 *) {}
104
105     QIntrusiveListNode emitterNode;
106 };
107
108 typedef QIntrusiveList<QQuickVisualDataGroupEmitter, &QQuickVisualDataGroupEmitter::emitterNode> QQuickVisualDataGroupEmitterList;
109
110 //---------------------------------------------------------------------------
111
112 class QQuickVisualDataGroupPrivate : public QObjectPrivate
113 {
114 public:
115     Q_DECLARE_PUBLIC(QQuickVisualDataGroup)
116
117     QQuickVisualDataGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
118
119     static QQuickVisualDataGroupPrivate *get(QQuickVisualDataGroup *group) {
120         return static_cast<QQuickVisualDataGroupPrivate *>(QObjectPrivate::get(group)); }
121
122     void setModel(QQuickVisualDataModel *model, Compositor::Group group);
123     void emitChanges(QV8Engine *engine);
124     void emitModelUpdated(bool reset);
125
126     void createdPackage(int index, QDeclarativePackage *package);
127     void initPackage(int index, QDeclarativePackage *package);
128     void destroyingPackage(QDeclarativePackage *package);
129
130     bool parseGroupArgs(QDeclarativeV8Function *args, int *index, int *count, int *groups) const;
131
132     Compositor::Group group;
133     QDeclarativeGuard<QQuickVisualDataModel> model;
134     QQuickVisualDataGroupEmitterList emitters;
135     QDeclarativeChangeSet changeSet;
136     QString name;
137     bool defaultInclude;
138 };
139
140 //---------------------------------------------------------------------------
141
142 class QQuickVisualDataModelCacheItem;
143 class QQuickVisualDataModelCacheMetaType;
144 class QQuickVisualDataModelParts;
145
146 class QQuickVisualDataModelCacheMetaType : public QDeclarativeRefCount
147 {
148 public:
149     QQuickVisualDataModelCacheMetaType(QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames);
150     ~QQuickVisualDataModelCacheMetaType();
151
152     int parseGroups(const QStringList &groupNames) const;
153     int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
154
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);
163
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;
172 };
173
174 class QQuickVisualDataModelCacheItem : public QV8ObjectResource
175 {
176     V8_RESOURCE_TYPE(VisualDataItemType)
177 public:
178     QQuickVisualDataModelCacheItem(QQuickVisualDataModelCacheMetaType *metaType)
179         : QV8ObjectResource(metaType->v8Engine)
180         , metaType(metaType)
181         , object(0)
182         , attached(0)
183         , objectRef(0)
184         , scriptRef(0)
185         , groups(0)
186         , incubationTask(0)
187     {
188         metaType->addref();
189     }
190
191     ~QQuickVisualDataModelCacheItem();
192
193     void referenceObject() { ++objectRef; }
194     bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
195     bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
196
197     bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag) || incubationTask; }
198
199     void Dispose();
200
201     QQuickVisualDataModelCacheMetaType * const metaType;
202     QDeclarativeGuard<QObject> object;
203     QQuickVisualDataModelAttached *attached;
204     int objectRef;
205     int scriptRef;
206     int groups;
207     int index[Compositor::MaximumGroupCount];
208     QVDMIncubationTask *incubationTask;
209 };
210
211
212 class QQuickVisualDataModelPrivate : public QObjectPrivate, public QQuickVisualDataGroupEmitter
213 {
214     Q_DECLARE_PUBLIC(QQuickVisualDataModel)
215 public:
216     QQuickVisualDataModelPrivate(QDeclarativeContext *);
217     ~QQuickVisualDataModelPrivate();
218
219     static QQuickVisualDataModelPrivate *get(QQuickVisualDataModel *m) {
220         return static_cast<QQuickVisualDataModelPrivate *>(QObjectPrivate::get(m));
221     }
222
223     void init();
224     void connectModel(QQuickVisualAdaptorModel *model);
225
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); }
239
240     void updateFilterGroup();
241
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);
245
246     void itemsInserted(
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);
251     void itemsRemoved(
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);
256     void itemsMoved(
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);
260     void emitChanges();
261     void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
262
263
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);
267
268     void releaseIncubator(QVDMIncubationTask *incubationTask);
269     void incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status);
270     void setInitialState(QVDMIncubationTask *incubationTask, QObject *o);
271
272     QQuickVisualAdaptorModel *m_adaptorModel;
273     QDeclarativeComponent *m_delegate;
274     QQuickVisualDataModelCacheMetaType *m_cacheMetaType;
275     QDeclarativeGuard<QDeclarativeContext> m_context;
276
277     QList<QQuickVisualDataModelCacheItem *> m_cache;
278     QQuickVisualDataModelParts *m_parts;
279     QQuickVisualDataGroupEmitterList m_pendingParts;
280
281     QDeclarativeListCompositor m_compositor;
282     QDeclarativeListCompositor::Group m_compositorGroup;
283     bool m_complete : 1;
284     bool m_delegateValidated : 1;
285     bool m_reset : 1;
286     bool m_transaction : 1;
287     bool m_incubatorCleanupScheduled : 1;
288
289     QString m_filterGroup;
290     QList<QByteArray> watchedRoles;
291
292     union {
293         struct {
294             QQuickVisualDataGroup *m_cacheItems;
295             QQuickVisualDataGroup *m_items;
296             QQuickVisualDataGroup *m_persistedItems;
297         };
298         QQuickVisualDataGroup *m_groups[Compositor::MaximumGroupCount];
299     };
300     int m_groupCount;
301
302     QList<QVDMIncubationTask *> m_finishedIncubating;
303 };
304
305 //---------------------------------------------------------------------------
306
307 class QQuickVisualPartsModel : public QQuickVisualModel, public QQuickVisualDataGroupEmitter
308 {
309     Q_OBJECT
310     Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
311 public:
312     QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent = 0);
313     ~QQuickVisualPartsModel();
314
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);
320
321     int count() const;
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);
327
328     int indexOf(QQuickItem *item, QObject *objectContext) const;
329
330     void emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
331
332     void createdPackage(int index, QDeclarativePackage *package);
333     void initPackage(int index, QDeclarativePackage *package);
334     void destroyingPackage(QDeclarativePackage *package);
335
336 Q_SIGNALS:
337     void filterGroupChanged();
338
339 private:
340     QQuickVisualDataModel *m_model;
341     QHash<QObject *, QDeclarativePackage *> m_packaged;
342     QString m_part;
343     QString m_filterGroup;
344     QList<QByteArray> m_watchedRoles;
345     Compositor::Group m_compositorGroup;
346     bool m_inheritGroup;
347 };
348
349 class QQuickVisualDataModelPartsMetaObject : public QDeclarativeOpenMetaObject
350 {
351 public:
352     QQuickVisualDataModelPartsMetaObject(QObject *parent)
353     : QDeclarativeOpenMetaObject(parent) {}
354
355     virtual void propertyCreated(int, QMetaPropertyBuilder &);
356     virtual QVariant initialValue(int);
357 };
358
359 class QQuickVisualDataModelParts : public QObject
360 {
361 Q_OBJECT
362 public:
363     QQuickVisualDataModelParts(QQuickVisualDataModel *parent);
364
365     QQuickVisualDataModel *model;
366     QList<QQuickVisualPartsModel *> models;
367 };
368
369 void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
370 {
371     prop.setWritable(false);
372 }
373
374 QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
375 {
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));
381 }
382
383 QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
384 : QObject(parent), model(parent)
385 {
386     new QQuickVisualDataModelPartsMetaObject(this);
387 }
388
389 class QQuickVisualDataModelAttachedMetaObject : public QAbstractDynamicMetaObject
390 {
391 public:
392     QQuickVisualDataModelAttachedMetaObject(
393             QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType);
394     ~QQuickVisualDataModelAttachedMetaObject();
395
396     int metaCall(QMetaObject::Call, int _id, void **);
397
398 private:
399     QQuickVisualDataModelAttached *attached;
400     QQuickVisualDataModelCacheMetaType *metaType;
401 };
402
403 //---------------------------------------------------------------------------
404
405 QHash<QObject*, QQuickVisualDataModelAttached*> QQuickVisualDataModelAttached::attachedProperties;
406
407 /*!
408     \qmlclass VisualDataModel QQuickVisualDataModel
409     \inqmlmodule QtQuick 2
410     \ingroup qml-working-with-data
411     \brief The VisualDataModel encapsulates a model and delegate
412
413     A VisualDataModel encapsulates a model and the delegate that will
414     be instantiated for items in the model.
415
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.
421
422     The example below illustrates using a VisualDataModel with a ListView.
423
424     \snippet doc/src/snippets/declarative/visualdatamodel.qml 0
425 */
426
427 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QDeclarativeContext *ctxt)
428     : m_adaptorModel(0)
429     , m_delegate(0)
430     , m_cacheMetaType(0)
431     , m_context(ctxt)
432     , m_parts(0)
433     , m_compositorGroup(Compositor::Cache)
434     , m_complete(false)
435     , m_delegateValidated(false)
436     , m_reset(false)
437     , m_transaction(false)
438     , m_incubatorCleanupScheduled(false)
439     , m_filterGroup(QStringLiteral("items"))
440     , m_cacheItems(0)
441     , m_items(0)
442     , m_groupCount(3)
443 {
444 }
445
446 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
447 {
448     qDeleteAll(m_finishedIncubating);
449 }
450
451 void QQuickVisualDataModelPrivate::connectModel(QQuickVisualAdaptorModel *model)
452 {
453     Q_Q(QQuickVisualDataModel);
454
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)));
460 }
461
462 void QQuickVisualDataModelPrivate::init()
463 {
464     Q_Q(QQuickVisualDataModel);
465     m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
466
467     m_adaptorModel = new QQuickVisualAdaptorModel;
468     QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged()));
469
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);
474 }
475
476 QQuickVisualDataModel::QQuickVisualDataModel()
477 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
478 {
479     Q_D(QQuickVisualDataModel);
480     d->init();
481 }
482
483 QQuickVisualDataModel::QQuickVisualDataModel(QDeclarativeContext *ctxt, QObject *parent)
484 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
485 {
486     Q_D(QQuickVisualDataModel);
487     d->init();
488 }
489
490 QQuickVisualDataModel::~QQuickVisualDataModel()
491 {
492     Q_D(QQuickVisualDataModel);
493
494     foreach (QQuickVisualDataModelCacheItem *cacheItem, d->m_cache) {
495         delete cacheItem->object;
496         cacheItem->object = 0;
497         cacheItem->objectRef = 0;
498         if (!cacheItem->isReferenced())
499             delete cacheItem;
500     }
501
502     delete d->m_adaptorModel;
503     if (d->m_cacheMetaType)
504         d->m_cacheMetaType->release();
505 }
506
507
508 void QQuickVisualDataModel::classBegin()
509 {
510 }
511
512 void QQuickVisualDataModel::componentComplete()
513 {
514     Q_D(QQuickVisualDataModel);
515     d->m_complete = true;
516
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];
529             --d->m_groupCount;
530             --i;
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];
534             --d->m_groupCount;
535             --i;
536         } else {
537             groupNames.append(name);
538
539             QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
540             group->setModel(this, Compositor::Group(i));
541             if (group->defaultInclude)
542                 defaultGroups |= (1 << i);
543         }
544     }
545     if (!d->m_context)
546         d->m_context = qmlContext(this);
547
548     d->m_cacheMetaType = new QQuickVisualDataModelCacheMetaType(
549             QDeclarativeEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
550
551     d->m_compositor.setGroupCount(d->m_groupCount);
552     d->m_compositor.setDefaultGroups(defaultGroups);
553     d->updateFilterGroup();
554
555     while (!d->m_pendingParts.isEmpty())
556         static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
557
558     d->connectModel(d->m_adaptorModel);
559     QVector<Compositor::Insert> inserts;
560     d->m_reset = true;
561     d->m_compositor.append(
562             d->m_adaptorModel,
563             0,
564             qMax(0, d->m_adaptorModel->count()),
565             defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
566             &inserts);
567     d->itemsInserted(inserts);
568     d->emitChanges();
569
570     if (d->m_adaptorModel->canFetchMore())
571         QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
572 }
573
574 /*!
575     \qmlproperty model QtQuick2::VisualDataModel::model
576     This property holds the model providing data for the VisualDataModel.
577
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.
582
583     Models can also be created directly in QML, using a \l{ListModel} or
584     \l{XmlListModel}.
585
586     \sa {qmlmodels}{Data Models}
587 */
588 QVariant QQuickVisualDataModel::model() const
589 {
590     Q_D(const QQuickVisualDataModel);
591     return d->m_adaptorModel->model();
592 }
593
594 void QQuickVisualDataModel::setModel(const QVariant &model)
595 {
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));
600 }
601
602 /*!
603     \qmlproperty Component QtQuick2::VisualDataModel::delegate
604
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}.
608 */
609 QDeclarativeComponent *QQuickVisualDataModel::delegate() const
610 {
611     Q_D(const QQuickVisualDataModel);
612     return d->m_delegate;
613 }
614
615 void QQuickVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
616 {
617     Q_D(QQuickVisualDataModel);
618     if (d->m_transaction) {
619         qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
620         return;
621     }
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)));
629         }
630     }
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)));
635         }
636     }
637     d->emitChanges();
638 }
639
640 /*!
641     \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
642
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.
646
647     This property only affects models of type QAbstractItemModel that
648     are hierarchical (e.g, a tree model).
649
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.
654
655     \c main.cpp:
656     \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/main.cpp 0
657
658     \c view.qml:
659     \snippet doc/src/snippets/declarative/visualdatamodel_rootindex/view.qml 0
660
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
664     any child nodes.
665
666
667     \sa modelIndex(), parentModelIndex()
668 */
669 QVariant QQuickVisualDataModel::rootIndex() const
670 {
671     Q_D(const QQuickVisualDataModel);
672     return d->m_adaptorModel->rootIndex();
673 }
674
675 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
676 {
677     Q_D(QQuickVisualDataModel);
678     d->m_adaptorModel->setRootIndex(root);
679 }
680
681 /*!
682     \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
683
684     QAbstractItemModel provides a hierarchical tree of data, whereas
685     QML only operates on list data.  This function assists in using
686     tree models in QML.
687
688     Returns a QModelIndex for the specified index.
689     This value can be assigned to rootIndex.
690
691     \sa rootIndex
692 */
693 QVariant QQuickVisualDataModel::modelIndex(int idx) const
694 {
695     Q_D(const QQuickVisualDataModel);
696     return d->m_adaptorModel->modelIndex(idx);
697 }
698
699 /*!
700     \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
701
702     QAbstractItemModel provides a hierarchical tree of data, whereas
703     QML only operates on list data.  This function assists in using
704     tree models in QML.
705
706     Returns a QModelIndex for the parent of the current rootIndex.
707     This value can be assigned to rootIndex.
708
709     \sa rootIndex
710 */
711 QVariant QQuickVisualDataModel::parentModelIndex() const
712 {
713     Q_D(const QQuickVisualDataModel);
714     return d->m_adaptorModel->parentModelIndex();
715 }
716
717 /*!
718     \qmlproperty int QtQuick2::VisualDataModel::count
719 */
720
721 int QQuickVisualDataModel::count() const
722 {
723     Q_D(const QQuickVisualDataModel);
724     if (!d->m_delegate)
725         return 0;
726     return d->m_compositor.count(d->m_compositorGroup);
727 }
728
729 void QQuickVisualDataModelPrivate::destroy(QObject *object)
730 {
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();
737 }
738
739 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
740 {
741     QQuickVisualDataModel::ReleaseFlags stat = 0;
742     if (!object)
743         return stat;
744
745     int cacheIndex = cacheIndexOf(object);
746     if (cacheIndex != -1) {
747         QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
748         if (cacheItem->releaseObject()) {
749             destroy(object);
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);
757                 delete cacheItem;
758                 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
759             }
760         } else {
761             stat |= QQuickVisualDataModel::Referenced;
762         }
763     }
764     return stat;
765 }
766
767 /*
768   Returns ReleaseStatus flags.
769 */
770
771 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
772 {
773     Q_D(QQuickVisualDataModel);
774     QQuickVisualModel::ReleaseFlags stat = d->release(item);
775     if (stat & Destroyed)
776         item->setParentItem(0);
777     return stat;
778 }
779
780 void QQuickVisualDataModelPrivate::group_append(
781         QDeclarativeListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
782 {
783     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
784     if (d->m_complete)
785         return;
786     if (d->m_groupCount == 11) {
787         qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
788         return;
789     }
790     d->m_groups[d->m_groupCount] = group;
791     d->m_groupCount += 1;
792 }
793
794 int QQuickVisualDataModelPrivate::group_count(
795         QDeclarativeListProperty<QQuickVisualDataGroup> *property)
796 {
797     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
798     return d->m_groupCount - 1;
799 }
800
801 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
802         QDeclarativeListProperty<QQuickVisualDataGroup> *property, int index)
803 {
804     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
805     return index >= 0 && index < d->m_groupCount - 1
806             ? d->m_groups[index + 1]
807             : 0;
808 }
809
810 /*!
811     \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
812
813     This property holds a visual data model's group definitions.
814
815     Groups define a sub-set of the items in a visual data model and can be used to filter
816     a model.
817
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.
822
823     The following example illustrates using groups to select items in a model.
824
825     \snippet doc/src/snippets/declarative/visualdatagroup.qml 0
826 */
827
828 QDeclarativeListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
829 {
830     Q_D(QQuickVisualDataModel);
831     return QDeclarativeListProperty<QQuickVisualDataGroup>(
832             this,
833             d,
834             QQuickVisualDataModelPrivate::group_append,
835             QQuickVisualDataModelPrivate::group_count,
836             QQuickVisualDataModelPrivate::group_at);
837 }
838
839 /*!
840     \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
841
842     This property holds visual data model's default group to which all new items are added.
843 */
844
845 QQuickVisualDataGroup *QQuickVisualDataModel::items()
846 {
847     Q_D(QQuickVisualDataModel);
848     return d->m_items;
849 }
850
851 /*!
852     \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
853
854     This property holds visual data model's persisted items group.
855
856     Items in this group are not destroyed when released by a view, instead they are persisted
857     until removed from the group.
858
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
862     instance.
863
864     Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
865     to this group.
866 */
867
868 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
869 {
870     Q_D(QQuickVisualDataModel);
871     return d->m_persistedItems;
872 }
873
874 /*!
875     \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
876
877     This property holds the name of the group used to filter the visual data model.
878
879     Only items which belong to this group are visible to a view.
880
881     By default this is the \l items group.
882 */
883
884 QString QQuickVisualDataModel::filterGroup() const
885 {
886     Q_D(const QQuickVisualDataModel);
887     return d->m_filterGroup;
888 }
889
890 void QQuickVisualDataModel::setFilterGroup(const QString &group)
891 {
892     Q_D(QQuickVisualDataModel);
893
894     if (d->m_transaction) {
895         qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
896         return;
897     }
898
899     if (d->m_filterGroup != group) {
900         d->m_filterGroup = group;
901         d->updateFilterGroup();
902         emit filterGroupChanged();
903     }
904 }
905
906 void QQuickVisualDataModel::resetFilterGroup()
907 {
908     setFilterGroup(QStringLiteral("items"));
909 }
910
911 void QQuickVisualDataModelPrivate::updateFilterGroup()
912 {
913     Q_Q(QQuickVisualDataModel);
914     if (!m_cacheMetaType)
915         return;
916
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);
922             break;
923         }
924     }
925
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);
931
932         QDeclarativeChangeSet changeSet;
933         changeSet.apply(removes, inserts);
934         emit q->modelUpdated(changeSet, false);
935
936         if (changeSet.difference() != 0)
937             emit q->countChanged();
938
939         if (m_parts) {
940             foreach (QQuickVisualPartsModel *model, m_parts->models)
941                 model->updateFilterGroup(m_compositorGroup, changeSet);
942         }
943     }
944 }
945
946 /*!
947     \qmlproperty object QtQuick2::VisualDataModel::parts
948
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.
952
953     For example, the code below selects a model which creates
954     delegates named \e list from a \l Package:
955
956     \code
957     VisualDataModel {
958         id: visualModel
959         delegate: Package {
960             Item { Package.name: "list" }
961         }
962         model: myModel
963     }
964
965     ListView {
966         width: 200; height:200
967         model: visualModel.parts.list
968     }
969     \endcode
970
971     \sa Package
972 */
973
974 QObject *QQuickVisualDataModel::parts()
975 {
976     Q_D(QQuickVisualDataModel);
977     if (!d->m_parts)
978         d->m_parts = new QQuickVisualDataModelParts(this);
979     return d->m_parts;
980 }
981
982 void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
983 {
984     for (int i = 1; i < m_groupCount; ++i)
985         QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
986 }
987
988 void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelCacheItem *cacheItem, QDeclarativePackage *package)
989 {
990     for (int i = 1; i < m_groupCount; ++i)
991         QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
992 }
993
994 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *package)
995 {
996     for (int i = 1; i < m_groupCount; ++i)
997         QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
998 }
999
1000 void QVDMIncubationTask::statusChanged(Status status)
1001 {
1002     vdm->incubatorStatusChanged(this, status);
1003 }
1004
1005 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
1006 {
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));
1014     }
1015 }
1016
1017 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QDeclarativeIncubator::Status status)
1018 {
1019     Q_Q(QQuickVisualDataModel);
1020     if (status != QDeclarativeIncubator::Ready && status != QDeclarativeIncubator::Error)
1021         return;
1022
1023     QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
1024     cacheItem->incubationTask = 0;
1025
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);
1040             delete cacheItem;
1041             Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1042         }
1043         releaseIncubator(incubationTask);
1044         qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
1045     }
1046 }
1047
1048 void QVDMIncubationTask::setInitialState(QObject *o)
1049 {
1050     vdm->setInitialState(this, o);
1051 }
1052
1053 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
1054 {
1055     QQuickVisualDataModelCacheItem *cacheItem = incubationTask->incubating;
1056     cacheItem->object = o;
1057     QDeclarative_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
1058     incubationTask->incubatingContext = 0;
1059
1060     cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
1061     cacheItem->attached->m_cacheItem = cacheItem;
1062     new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
1063     cacheItem->attached->emitChanges();
1064
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);
1069 }
1070
1071 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
1072 {
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);
1076         return 0;
1077     }
1078
1079     Compositor::iterator it = m_compositor.find(group, index);
1080     QQuickVisualDataModelCacheItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
1081     if (!cacheItem) {
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;
1086     }
1087
1088     int modelIndex = it.modelIndex();
1089
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));
1094     }
1095
1096     if (cacheItem->incubationTask) {
1097         if (!asynchronous) {
1098             // previously requested async - now needed immediately
1099             cacheItem->incubationTask->forceCompletion();
1100         }
1101     } else if (!cacheItem->object) {
1102         QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QDeclarativeIncubator::Asynchronous : QDeclarativeIncubator::AsynchronousIfNested);
1103         cacheItem->incubationTask = incubator;
1104
1105         QObject *data = m_adaptorModel->data(modelIndex);
1106
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);
1115             }
1116         }
1117
1118         QDeclarative_setParent_noEvent(data, ctxt);
1119         ctxt->setContextProperty(QLatin1String("model"), data);
1120         ctxt->setContextObject(data);
1121
1122         incubator->incubating = cacheItem;
1123         incubator->incubatingContext = rootContext;
1124         m_delegate->create(*incubator, ctxt, m_context);
1125     }
1126
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;
1132 }
1133
1134 /*
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.
1141 */
1142 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
1143 {
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);
1147         return 0;
1148     }
1149
1150     QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
1151     if (!object)
1152         return 0;
1153
1154     if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
1155         return item;
1156
1157     d->release(object);
1158     if (!d->m_delegateValidated) {
1159         if (object)
1160             qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
1161         d->m_delegateValidated = true;
1162     }
1163     return 0;
1164 }
1165
1166 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
1167 {
1168     Compositor::iterator it = m_compositor.find(group, index);
1169     if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
1170         return model->stringValue(it.modelIndex(), name);
1171     }
1172     return QString();
1173 }
1174
1175 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
1176 {
1177     Q_D(QQuickVisualDataModel);
1178     return d->stringValue(d->m_compositorGroup, index, name);
1179 }
1180
1181 int QQuickVisualDataModelPrivate::cacheIndexOf(QObject *object) const
1182 {
1183     for (int cacheIndex = 0; cacheIndex < m_cache.count(); ++cacheIndex) {
1184         if (m_cache.at(cacheIndex)->object == object)
1185             return cacheIndex;
1186     }
1187     return -1;
1188 }
1189
1190 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
1191 {
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]
1196             : -1;
1197 }
1198
1199 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
1200 {
1201     Q_D(QQuickVisualDataModel);
1202     d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles);
1203     d->watchedRoles = roles;
1204 }
1205
1206 void QQuickVisualDataModelPrivate::addGroups(Compositor::Group group, int index, int count, int groupFlags)
1207 {
1208     QVector<Compositor::Insert> inserts;
1209     m_compositor.setFlags(group, index, count, groupFlags, &inserts);
1210     itemsInserted(inserts);
1211     emitChanges();
1212 }
1213
1214 void QQuickVisualDataModelPrivate::removeGroups(Compositor::Group group, int index, int count, int groupFlags)
1215 {
1216     QVector<Compositor::Remove> removes;
1217     m_compositor.clearFlags(group, index, count, groupFlags, &removes);
1218     itemsRemoved(removes);
1219     emitChanges();
1220 }
1221
1222 void QQuickVisualDataModelPrivate::setGroups(Compositor::Group group, int index, int count, int groupFlags)
1223 {
1224     QVector<Compositor::Insert> inserts;
1225     m_compositor.setFlags(group, index, count, groupFlags, &inserts);
1226     itemsInserted(inserts);
1227
1228     const int removeFlags = ~groupFlags & Compositor::GroupMask;
1229     QVector<Compositor::Remove> removes;
1230     m_compositor.clearFlags(group, index, count, removeFlags, &removes);
1231     itemsRemoved(removes);
1232
1233     emitChanges();
1234 }
1235
1236 bool QQuickVisualDataModel::event(QEvent *e)
1237 {
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();
1245     }
1246     return QQuickVisualModel::event(e);
1247 }
1248
1249 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1250 {
1251     if (!m_delegate)
1252         return;
1253
1254     QVarLengthArray<QVector<QDeclarativeChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1255
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));
1261             }
1262         }
1263     }
1264
1265     for (int i = 1; i < m_groupCount; ++i)
1266         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1267 }
1268
1269 void QQuickVisualDataModel::_q_itemsChanged(int index, int count)
1270 {
1271     Q_D(QQuickVisualDataModel);
1272     if (count <= 0)
1273         return;
1274     QVector<Compositor::Change> changes;
1275     d->m_compositor.listItemsChanged(d->m_adaptorModel, index, count, &changes);
1276     d->itemsChanged(changes);
1277     d->emitChanges();
1278 }
1279
1280 void QQuickVisualDataModelPrivate::itemsInserted(
1281         const QVector<Compositor::Insert> &inserts,
1282         QVarLengthArray<QVector<QDeclarativeChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1283         QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
1284 {
1285     int cacheIndex = 0;
1286
1287     int inserted[Compositor::MaximumGroupCount];
1288     for (int i = 1; i < m_groupCount; ++i)
1289         inserted[i] = 0;
1290
1291     foreach (const Compositor::Insert &insert, inserts) {
1292         for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
1293             QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1294             if (!cacheItem->groups)
1295                 continue;
1296             for (int i = 1; i < m_groupCount; ++i)
1297                 cacheItem->index[i] += inserted[i];
1298         }
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;
1304             }
1305         }
1306
1307         if (!insert.inCache())
1308             continue;
1309
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);
1314         }
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
1322                             : insert.index[i];
1323                 }
1324             }
1325         } else {
1326             cacheIndex = insert.cacheIndex + insert.count;
1327         }
1328     }
1329     for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1330         QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1331         if (!cacheItem->groups)
1332             continue;
1333         for (int i = 1; i < m_groupCount; ++i)
1334             cacheItem->index[i] += inserted[i];
1335     }
1336 }
1337
1338 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1339 {
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));
1343     if (!m_delegate)
1344         return;
1345
1346     for (int i = 1; i < m_groupCount; ++i)
1347         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1348 }
1349
1350 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1351 {
1352
1353     Q_D(QQuickVisualDataModel);
1354     if (count <= 0)
1355         return;
1356     QVector<Compositor::Insert> inserts;
1357     d->m_compositor.listItemsInserted(d->m_adaptorModel, index, count, &inserts);
1358     d->itemsInserted(inserts);
1359     d->emitChanges();
1360 }
1361
1362 void QQuickVisualDataModelPrivate::itemsRemoved(
1363         const QVector<Compositor::Remove> &removes,
1364         QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1365         QHash<int, QList<QQuickVisualDataModelCacheItem *> > *movedItems)
1366 {
1367     int cacheIndex = 0;
1368     int removedCache = 0;
1369
1370     int removed[Compositor::MaximumGroupCount];
1371     for (int i = 1; i < m_groupCount; ++i)
1372         removed[i] = 0;
1373
1374     foreach (const Compositor::Remove &remove, removes) {
1375         for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
1376             QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1377             if (!cacheItem->groups)
1378                 continue;
1379             for (int i = 1; i < m_groupCount; ++i)
1380                 cacheItem->index[i] -= removed[i];
1381         }
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;
1387             }
1388         }
1389
1390         if (!remove.inCache())
1391             continue;
1392
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);
1398         } else {
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;
1408                 }
1409                 if (remove.groups() == cacheItem->groups && !cacheItem->isReferenced()) {
1410                     m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1411                     m_cache.removeAt(cacheIndex);
1412                     delete cacheItem;
1413                     --cacheIndex;
1414                     ++removedCache;
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;
1420                 } else {
1421                     for (int i = 1; i < m_groupCount; ++i) {
1422                         if (remove.inGroup(i))
1423                             cacheItem->index[i] = remove.index[i];
1424                     }
1425                     cacheItem->groups &= ~remove.flags & Compositor::GroupMask;
1426                 }
1427             }
1428         }
1429     }
1430
1431     for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1432         QQuickVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
1433         if (!cacheItem->groups)
1434             continue;
1435         for (int i = 1; i < m_groupCount; ++i)
1436             cacheItem->index[i] -= removed[i];
1437     }
1438 }
1439
1440 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1441 {
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));
1445     if (!m_delegate)
1446         return;
1447
1448     for (int i = 1; i < m_groupCount; ++i)
1449        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1450 }
1451
1452 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1453 {
1454     Q_D(QQuickVisualDataModel);
1455     if (count <= 0)
1456         return;
1457
1458     QVector<Compositor::Remove> removes;
1459     d->m_compositor.listItemsRemoved(d->m_adaptorModel, index, count, &removes);
1460     d->itemsRemoved(removes);
1461     d->emitChanges();
1462 }
1463
1464 void QQuickVisualDataModelPrivate::itemsMoved(
1465         const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1466 {
1467     QHash<int, QList<QQuickVisualDataModelCacheItem *> > movedItems;
1468
1469     QVarLengthArray<QVector<QDeclarativeChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1470     itemsRemoved(removes, &translatedRemoves, &movedItems);
1471
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());
1476     if (!m_delegate)
1477         return;
1478
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));
1483     }
1484 }
1485
1486 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1487 {
1488     Q_D(QQuickVisualDataModel);
1489     if (count <= 0)
1490         return;
1491
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);
1496     d->emitChanges();
1497 }
1498
1499 template <typename T> v8::Local<v8::Array>
1500 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1501 {
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");
1506
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);
1513     }
1514     return indexes;
1515 }
1516
1517 void QQuickVisualDataModelPrivate::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
1518 {
1519     Q_Q(QQuickVisualDataModel);
1520     emit q->modelUpdated(changeSet, reset);
1521     if (changeSet.difference() != 0)
1522         emit q->countChanged();
1523 }
1524
1525 void QQuickVisualDataModelPrivate::emitChanges()
1526 {
1527     if (m_transaction || !m_complete)
1528         return;
1529
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;
1535
1536     const bool reset = m_reset;
1537     m_reset = false;
1538     for (int i = 1; i < m_groupCount; ++i)
1539         QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1540
1541     foreach (QQuickVisualDataModelCacheItem *cacheItem, m_cache) {
1542         if (cacheItem->object && cacheItem->attached)
1543             cacheItem->attached->emitChanges();
1544     }
1545 }
1546
1547 void QQuickVisualDataModel::_q_modelReset(int oldCount, int newCount)
1548 {
1549     Q_D(QQuickVisualDataModel);
1550     if (!d->m_delegate)
1551         return;
1552
1553     QVector<Compositor::Remove> removes;
1554     QVector<Compositor::Insert> inserts;
1555     if (oldCount)
1556         d->m_compositor.listItemsRemoved(d->m_adaptorModel, 0, oldCount, &removes);
1557     if (newCount)
1558         d->m_compositor.listItemsInserted(d->m_adaptorModel, 0, newCount, &inserts);
1559     d->itemsMoved(removes, inserts);
1560     d->m_reset = true;
1561     d->emitChanges();
1562 }
1563
1564 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1565 {
1566     return QQuickVisualDataModelAttached::properties(obj);
1567 }
1568
1569 //============================================================================
1570
1571 QQuickVisualDataModelCacheMetaType::QQuickVisualDataModelCacheMetaType(
1572         QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1573     : model(model)
1574     , groupCount(groupNames.count() + 1)
1575     , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1576     , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
1577     , v8Engine(engine)
1578     , metaObject(0)
1579     , groupNames(groupNames)
1580 {
1581     QMetaObjectBuilder builder;
1582     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1583     builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1584     builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1585
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);
1592
1593     int notifierId = 0;
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);
1601
1602         ft->PrototypeTemplate()->SetAccessor(
1603                 engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1604     }
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);
1611
1612         ft->PrototypeTemplate()->SetAccessor(
1613                 engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1614     }
1615
1616     metaObject = builder.toMetaObject();
1617
1618     constructor = qPersistentNew<v8::Function>(ft->GetFunction());
1619 }
1620
1621 QQuickVisualDataModelCacheMetaType::~QQuickVisualDataModelCacheMetaType()
1622 {
1623     qFree(metaObject);
1624     qPersistentDispose(constructor);
1625 }
1626
1627 int QQuickVisualDataModelCacheMetaType::parseGroups(const QStringList &groups) const
1628 {
1629     int groupFlags = 0;
1630     foreach (const QString &groupName, groups) {
1631         int index = groupNames.indexOf(groupName);
1632         if (index != -1)
1633             groupFlags |= 2 << index;
1634     }
1635     return groupFlags;
1636 }
1637
1638 int QQuickVisualDataModelCacheMetaType::parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groups) const
1639 {
1640     int groupFlags = 0;
1641     if (groups->IsString()) {
1642         const QString groupName = engine->toString(groups);
1643         int index = groupNames.indexOf(groupName);
1644         if (index != -1)
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);
1651             if (index != -1)
1652                 groupFlags |= 2 << index;
1653         }
1654     }
1655     return groupFlags;
1656 }
1657
1658 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_model(
1659         v8::Local<v8::String>, const v8::AccessorInfo &info)
1660 {
1661     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1662     if (!cacheItem)
1663         V8THROW_ERROR("Not a valid VisualData object");
1664     if (!cacheItem->metaType->model)
1665         return v8::Undefined();
1666     QObject *data = 0;
1667
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());
1675             break;
1676         }
1677     }
1678     if (!data)
1679         return v8::Undefined();
1680     return cacheItem->engine->newQObject(data);
1681 }
1682
1683 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_groups(
1684         v8::Local<v8::String>, const v8::AccessorInfo &info)
1685 {
1686     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1687     if (!cacheItem)
1688         V8THROW_ERROR("Not a valid VisualData object");
1689
1690     QStringList groups;
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));
1694     }
1695
1696     return cacheItem->engine->fromVariant(groups);
1697 }
1698
1699 void QQuickVisualDataModelCacheMetaType::set_groups(
1700         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1701 {
1702     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1703     if (!cacheItem)
1704         V8THROW_ERROR_SETTER("Not a valid VisualData object");
1705
1706     if (!cacheItem->metaType->model)
1707         return;
1708     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1709
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);
1714             break;
1715         }
1716     }
1717 }
1718
1719 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_member(
1720         v8::Local<v8::String>, const v8::AccessorInfo &info)
1721 {
1722     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1723     if (!cacheItem)
1724         V8THROW_ERROR("Not a valid VisualData object");
1725
1726     return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1727 }
1728
1729 void QQuickVisualDataModelCacheMetaType::set_member(
1730         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1731 {
1732     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1733     if (!cacheItem)
1734         V8THROW_ERROR_SETTER("Not a valid VisualData object");
1735
1736     if (!cacheItem->metaType->model)
1737         return;
1738     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1739
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))
1744         return;
1745
1746     for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1747         if (cacheItem->groups & (1 << i)) {
1748             if (member)
1749                 model->addGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
1750             else
1751                 model->removeGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
1752             break;
1753         }
1754     }
1755 }
1756
1757 v8::Handle<v8::Value> QQuickVisualDataModelCacheMetaType::get_index(
1758         v8::Local<v8::String>, const v8::AccessorInfo &info)
1759 {
1760     QQuickVisualDataModelCacheItem *cacheItem = v8_resource_cast<QQuickVisualDataModelCacheItem>(info.This());
1761     if (!cacheItem)
1762         V8THROW_ERROR("Not a valid VisualData object");
1763
1764     return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
1765 }
1766
1767
1768 //---------------------------------------------------------------------------
1769
1770 QQuickVisualDataModelCacheItem::~QQuickVisualDataModelCacheItem()
1771 {
1772     Q_ASSERT(scriptRef == 0);
1773     Q_ASSERT(objectRef == 0);
1774     Q_ASSERT(!object);
1775     if (incubationTask && metaType->model)
1776         QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1777
1778     metaType->release();
1779 }
1780
1781 void QQuickVisualDataModelCacheItem::Dispose()
1782 {
1783     --scriptRef;
1784     if (isReferenced())
1785         return;
1786
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);
1793         }
1794     }
1795     delete this;
1796 }
1797
1798 //---------------------------------------------------------------------------
1799
1800 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1801         QQuickVisualDataModelAttached *attached, QQuickVisualDataModelCacheMetaType *metaType)
1802     : attached(attached)
1803     , metaType(metaType)
1804 {
1805     metaType->addref();
1806     *static_cast<QMetaObject *>(this) = *metaType->metaObject;
1807     QObjectPrivate::get(attached)->metaObject = this;
1808 }
1809
1810 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1811 {
1812     metaType->release();
1813 }
1814
1815 int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
1816 {
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];
1821             return -1;
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);
1825             return -1;
1826         }
1827     } else if (call == QMetaObject::WriteProperty) {
1828         if (_id >= metaType->memberPropertyOffset) {
1829             if (!metaType->model)
1830                 return -1;
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);
1836                 if (member)
1837                     model->removeGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
1838                 else
1839                     model->addGroups(Compositor::Cache, cacheIndex, 1, (1 << group));
1840             }
1841             return -1;
1842         }
1843     }
1844     return attached->qt_metacall(call, _id, arguments);
1845 }
1846
1847 void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelCacheItem *item)
1848 {
1849     m_cacheItem = item;
1850     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1851         m_previousIndex[i] = m_cacheItem->index[i];
1852 }
1853
1854 /*!
1855     \qmlattachedproperty int QtQuick2::VisualDataModel::model
1856
1857     This attached property holds the visual data model this delegate instance belongs to.
1858
1859     It is attached to each instance of the delegate.
1860 */
1861
1862 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1863 {
1864     return m_cacheItem ? m_cacheItem->metaType->model : 0;
1865 }
1866
1867 /*!
1868     \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1869
1870     This attached property holds the name of VisualDataGroups the item belongs to.
1871
1872     It is attached to each instance of the delegate.
1873 */
1874
1875 QStringList QQuickVisualDataModelAttached::groups() const
1876 {
1877     QStringList groups;
1878
1879     if (!m_cacheItem)
1880         return groups;
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));
1884     }
1885     return groups;
1886 }
1887
1888 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1889 {
1890     if (!m_cacheItem)
1891         return;
1892
1893     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1894
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);
1898 }
1899
1900 /*!
1901     \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1902
1903     This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1904
1905     Changing this property will add or remove the item from the items group.
1906
1907     It is attached to each instance of the delegate.
1908 */
1909
1910 /*!
1911     \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1912
1913     This attached property holds the index of the item in the default \l items VisualDataGroup.
1914
1915     It is attached to each instance of the delegate.
1916 */
1917
1918 /*!
1919     \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1920
1921     This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1922
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.
1926
1927     It is attached to each instance of the delegate.
1928 */
1929
1930 /*!
1931     \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
1932
1933     This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
1934
1935     It is attached to each instance of the delegate.
1936 */
1937
1938 void QQuickVisualDataModelAttached::emitChanges()
1939 {
1940     if (m_modelChanged) {
1941         m_modelChanged = false;
1942         emit modelChanged();
1943     }
1944
1945     const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
1946     m_previousGroups = m_cacheItem->groups;
1947
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);
1953         }
1954     }
1955
1956     int notifierId = 0;
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);
1961     }
1962     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1963         if (indexChanges & (1 << i))
1964             QMetaObject::activate(this, meta, notifierId, 0);
1965     }
1966
1967     if (groupChanges)
1968         emit groupsChanged();
1969 }
1970
1971 //============================================================================
1972
1973 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
1974 {
1975     Q_ASSERT(!model);
1976     model = m;
1977     group = g;
1978 }
1979
1980 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
1981 {
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());
1989         emit q->changed(
1990                 QDeclarativeV8Handle::fromHandle(removed), QDeclarativeV8Handle::fromHandle(inserted));
1991     }
1992     if (changeSet.difference() != 0)
1993         emit q->countChanged();
1994 }
1995
1996 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
1997 {
1998     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1999         it->emitModelUpdated(changeSet, reset);
2000     changeSet.clear();
2001 }
2002
2003 void QQuickVisualDataGroupPrivate::createdPackage(int index, QDeclarativePackage *package)
2004 {
2005     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2006         it->createdPackage(index, package);
2007 }
2008
2009 void QQuickVisualDataGroupPrivate::initPackage(int index, QDeclarativePackage *package)
2010 {
2011     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2012         it->initPackage(index, package);
2013 }
2014
2015 void QQuickVisualDataGroupPrivate::destroyingPackage(QDeclarativePackage *package)
2016 {
2017     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2018         it->destroyingPackage(package);
2019 }
2020
2021 /*!
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.
2026
2027 */
2028
2029 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2030     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2031 {
2032 }
2033
2034 QQuickVisualDataGroup::QQuickVisualDataGroup(
2035         const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2036     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2037 {
2038     Q_D(QQuickVisualDataGroup);
2039     d->name = name;
2040     d->setModel(model, Compositor::Group(index));
2041 }
2042
2043 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2044 {
2045 }
2046
2047 /*!
2048     \qmlproperty string QtQuick2::VisualDataGroup::name
2049
2050     This property holds the name of the group.
2051
2052     Each group in a model must have a unique name starting with a lower case letter.
2053 */
2054
2055 QString QQuickVisualDataGroup::name() const
2056 {
2057     Q_D(const QQuickVisualDataGroup);
2058     return d->name;
2059 }
2060
2061 void QQuickVisualDataGroup::setName(const QString &name)
2062 {
2063     Q_D(QQuickVisualDataGroup);
2064     if (d->model)
2065         return;
2066     if (d->name != name) {
2067         d->name = name;
2068         emit nameChanged();
2069     }
2070 }
2071
2072 /*!
2073     \qmlproperty int QtQuick2::VisualDataGroup::count
2074
2075     This property holds the number of items in the group.
2076 */
2077
2078 int QQuickVisualDataGroup::count() const
2079 {
2080     Q_D(const QQuickVisualDataGroup);
2081     if (!d->model)
2082         return 0;
2083     return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2084 }
2085
2086 /*!
2087     \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2088
2089     This property holds whether new items are assigned to this group by default.
2090 */
2091
2092 bool QQuickVisualDataGroup::defaultInclude() const
2093 {
2094     Q_D(const QQuickVisualDataGroup);
2095     return d->defaultInclude;
2096 }
2097
2098 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2099 {
2100     Q_D(QQuickVisualDataGroup);
2101     if (d->defaultInclude != include) {
2102         d->defaultInclude = include;
2103
2104         if (d->model) {
2105             if (include)
2106                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2107             else
2108                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2109         }
2110         emit defaultIncludeChanged();
2111     }
2112 }
2113
2114 /*!
2115     \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2116
2117     Returns a javascript object describing the item at \a index in the group.
2118
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:
2121
2122     \list
2123     \o \b model The model data of the item.  This is the same as the model context property in
2124     a delegate
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.
2133     \endlist
2134 */
2135
2136 QDeclarativeV8Handle QQuickVisualDataGroup::get(int index)
2137 {
2138     Q_D(QQuickVisualDataGroup);
2139     if (!d->model)
2140         return QDeclarativeV8Handle::fromHandle(v8::Undefined());;
2141
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());
2146     }
2147
2148     Compositor::iterator it = model->m_compositor.find(d->group, index);
2149     QQuickVisualDataModelCacheItem *cacheItem = it->inCache()
2150             ? model->m_cache.at(it.cacheIndex)
2151             : 0;
2152
2153     if (!cacheItem) {
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;
2158
2159         model->m_cache.insert(it.cacheIndex, cacheItem);
2160         model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2161     }
2162
2163     ++cacheItem->scriptRef;
2164
2165     v8::Local<v8::Object> rv = model->m_cacheMetaType->constructor->NewInstance();
2166     rv->SetExternalResource(cacheItem);
2167     return QDeclarativeV8Handle::fromHandle(rv);
2168 }
2169
2170 /*!
2171     \qmlmethod QtQuick2::VisualDataGroup::create(int index)
2172
2173     Returns a reference to the instantiated item at \a index in the group.
2174
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.
2177 */
2178
2179 QObject *QQuickVisualDataGroup::create(int index)
2180 {
2181     Q_D(QQuickVisualDataGroup);
2182     if (!d->model)
2183         return 0;
2184
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");
2188         return 0;
2189     }
2190
2191     QObject *object = model->object(d->group, index, false, false);
2192     if (object)
2193         model->addGroups(d->group, index, 1, Compositor::PersistedFlag);
2194     return object;
2195 }
2196
2197 /*!
2198     \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2199
2200     Removes \a count items starting at \a index from the group.
2201 */
2202
2203 void QQuickVisualDataGroup::remove(QDeclarativeV8Function *args)
2204 {
2205     Q_D(QQuickVisualDataGroup);
2206     if (!d->model)
2207         return;
2208     int index = -1;
2209     int count = 1;
2210
2211     if (args->Length() == 0)
2212         return;
2213
2214     int i = 0;
2215     v8::Local<v8::Value> v = (*args)[i];
2216     if (!v->IsInt32())
2217         return;
2218     index = v->Int32Value();
2219
2220     if (++i < args->Length()) {
2221         v = (*args)[i];
2222         if (v->IsInt32())
2223             count = v->Int32Value();
2224     }
2225
2226     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2227     if (count < 0) {
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);
2233     }
2234 }
2235
2236 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2237         QDeclarativeV8Function *args, int *index, int *count, int *groups) const
2238 {
2239     if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2240         return false;
2241
2242     if (args->Length() < 2)
2243         return false;
2244
2245     int i = 0;
2246     v8::Local<v8::Value> v = (*args)[i];
2247     if (!v->IsInt32())
2248         return false;
2249     *index = v->Int32Value();
2250
2251     v = (*args)[++i];
2252     if (v->IsInt32()) {
2253         *count = v->Int32Value();
2254
2255         if (++i == args->Length())
2256             return false;
2257         v = (*args)[i];
2258     }
2259
2260     *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(args->engine(), v);
2261
2262     return true;
2263 }
2264
2265 /*!
2266     \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2267
2268     Adds \a count items starting at \a index to \a groups.
2269 */
2270
2271 void QQuickVisualDataGroup::addGroups(QDeclarativeV8Function *args)
2272 {
2273     Q_D(QQuickVisualDataGroup);
2274     int index = -1;
2275     int count = 1;
2276     int groups = 0;
2277
2278     if (!d->parseGroupArgs(args, &index, &count, &groups))
2279         return;
2280
2281     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2282     if (count < 0) {
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);
2288     }
2289 }
2290
2291 /*!
2292     \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2293
2294     Removes \a count items starting at \a index from \a groups.
2295 */
2296
2297 void QQuickVisualDataGroup::removeGroups(QDeclarativeV8Function *args)
2298 {
2299     Q_D(QQuickVisualDataGroup);
2300     int index = -1;
2301     int count = 1;
2302     int groups = 0;
2303
2304     if (!d->parseGroupArgs(args, &index, &count, &groups))
2305         return;
2306
2307     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2308     if (count < 0) {
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);
2314     }
2315 }
2316
2317 /*!
2318     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2319
2320     Sets the \a groups \a count items starting at \a index belong to.
2321 */
2322
2323 void QQuickVisualDataGroup::setGroups(QDeclarativeV8Function *args)
2324 {
2325     Q_D(QQuickVisualDataGroup);
2326     int index = -1;
2327     int count = 1;
2328     int groups = 0;
2329
2330     if (!d->parseGroupArgs(args, &index, &count, &groups))
2331         return;
2332
2333     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2334     if (count < 0) {
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);
2340     }
2341 }
2342
2343 /*!
2344     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2345
2346     Sets the \a groups \a count items starting at \a index belong to.
2347 */
2348
2349 /*!
2350     \qmlmethod QtQuick2::VisualDataGroup::move(int from, int to, int count)
2351
2352     Moves \a count at \a from in a group \a to a new position.
2353 */
2354
2355 void QQuickVisualDataGroup::move(QDeclarativeV8Function *args)
2356 {
2357     Q_D(QQuickVisualDataGroup);
2358
2359     if (args->Length() < 2)
2360         return;
2361
2362     Compositor::Group fromGroup = d->group;
2363     Compositor::Group toGroup = d->group;
2364     int from = -1;
2365     int to = -1;
2366     int count = 1;
2367
2368     int i = 0;
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)
2373             return;
2374         fromGroup = g_d->group;
2375         v = (*args)[++i];
2376     }
2377
2378     if (!v->IsInt32())
2379         return;
2380     from = v->Int32Value();
2381
2382     if (++i == args->Length())
2383         return;
2384     v = (*args)[i];
2385
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)
2389             return;
2390         toGroup = g_d->group;
2391
2392         if (++i == args->Length())
2393             return;
2394         v = (*args)[i];
2395     }
2396
2397     if (!v->IsInt32())
2398         return;
2399     to = v->Int32Value();
2400
2401     if (++i < args->Length()) {
2402         v = (*args)[i];
2403         if (v->IsInt32())
2404             count = v->Int32Value();
2405     }
2406
2407     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2408
2409     if (count < 0) {
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;
2418
2419         model->m_compositor.move(fromGroup, from, toGroup, to, count, &removes, &inserts);
2420         model->itemsMoved(removes, inserts);
2421         model->emitChanges();
2422     }
2423
2424 }
2425
2426 /*!
2427     \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2428
2429     This handler is called when items have been removed from or inserted into the group.
2430
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.
2433
2434     Each index is adjusted for previous changes with all removed items preceding any inserted
2435     items.
2436 */
2437
2438 //============================================================================
2439
2440 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2441     : QQuickVisualModel(*new QObjectPrivate, parent)
2442     , m_model(model)
2443     , m_part(part)
2444     , m_compositorGroup(Compositor::Cache)
2445     , m_inheritGroup(true)
2446 {
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;
2451     } else {
2452         d->m_pendingParts.insert(this);
2453     }
2454 }
2455
2456 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2457 {
2458 }
2459
2460 QString QQuickVisualPartsModel::filterGroup() const
2461 {
2462     if (m_inheritGroup)
2463         return m_model->filterGroup();
2464     return m_filterGroup;
2465 }
2466
2467 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2468 {
2469     if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2470         qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2471         return;
2472     }
2473
2474     if (m_filterGroup != group || m_inheritGroup) {
2475         m_filterGroup = group;
2476         m_inheritGroup = false;
2477         updateFilterGroup();
2478
2479         emit filterGroupChanged();
2480     }
2481 }
2482
2483 void QQuickVisualPartsModel::resetFilterGroup()
2484 {
2485     if (!m_inheritGroup) {
2486         m_inheritGroup = true;
2487         updateFilterGroup();
2488         emit filterGroupChanged();
2489     }
2490 }
2491
2492 void QQuickVisualPartsModel::updateFilterGroup()
2493 {
2494     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2495     if (!model->m_cacheMetaType)
2496         return;
2497
2498     if (m_inheritGroup) {
2499         if (m_filterGroup == model->m_filterGroup)
2500             return;
2501         m_filterGroup = model->m_filterGroup;
2502     }
2503
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);
2510             break;
2511         }
2512     }
2513
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);
2519
2520         QDeclarativeChangeSet changeSet;
2521         changeSet.apply(removes, inserts);
2522         if (!changeSet.isEmpty())
2523             emit modelUpdated(changeSet, false);
2524
2525         if (changeSet.difference() != 0)
2526             emit countChanged();
2527     }
2528 }
2529
2530 void QQuickVisualPartsModel::updateFilterGroup(
2531         Compositor::Group group, const QDeclarativeChangeSet &changeSet)
2532 {
2533     if (!m_inheritGroup)
2534         return;
2535
2536     m_compositorGroup = group;
2537     QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2538
2539     if (!changeSet.isEmpty())
2540         emit modelUpdated(changeSet, false);
2541
2542     if (changeSet.difference() != 0)
2543         emit countChanged();
2544
2545     emit filterGroupChanged();
2546 }
2547
2548 int QQuickVisualPartsModel::count() const
2549 {
2550     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2551     return model->m_delegate
2552             ? model->m_compositor.count(m_compositorGroup)
2553             : 0;
2554 }
2555
2556 bool QQuickVisualPartsModel::isValid() const
2557 {
2558     return m_model->isValid();
2559 }
2560
2561 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2562 {
2563     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2564
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);
2567         return 0;
2568     }
2569
2570     QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
2571
2572     if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) {
2573         QObject *part = package->part(m_part);
2574         if (!part)
2575             return 0;
2576         if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
2577             m_packaged.insertMulti(item, package);
2578             return item;
2579         }
2580     }
2581
2582     model->release(object);
2583     if (!model->m_delegateValidated) {
2584         if (object)
2585             qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2586         model->m_delegateValidated = true;
2587     }
2588
2589     return 0;
2590 }
2591
2592 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2593 {
2594     QQuickVisualModel::ReleaseFlags flags = 0;
2595
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);
2608         }
2609     }
2610     return flags;
2611 }
2612
2613 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2614 {
2615     return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2616 }
2617
2618 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2619 {
2620     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2621     model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles);
2622     m_watchedRoles = roles;
2623 }
2624
2625 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2626 {
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]
2633                 : -1;
2634     }
2635     return -1;
2636 }
2637
2638 void QQuickVisualPartsModel::createdPackage(int index, QDeclarativePackage *package)
2639 {
2640     if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2641         emit createdItem(index, item);
2642 }
2643
2644 void QQuickVisualPartsModel::initPackage(int index, QDeclarativePackage *package)
2645 {
2646     if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2647         emit initItem(index, item);
2648 }
2649
2650 void QQuickVisualPartsModel::destroyingPackage(QDeclarativePackage *package)
2651 {
2652     if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
2653         Q_ASSERT(!m_packaged.contains(item));
2654         emit destroyingItem(item);
2655     }
2656 }
2657
2658 void QQuickVisualPartsModel::emitModelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
2659 {
2660     emit modelUpdated(changeSet, reset);
2661     if (changeSet.difference() != 0)
2662         emit countChanged();
2663 }
2664
2665
2666 QT_END_NAMESPACE
2667
2668 #include <qquickvisualdatamodel.moc>