bd4f66f6fa22c2e854bf86c0416a100c447d6415
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickvisualdatamodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickvisualdatamodel_p_p.h"
43 #include "qquickitem.h"
44
45 #include <QtQml/qqmlinfo.h>
46
47 #include <private/qquickpackage_p.h>
48 #include <private/qmetaobjectbuilder_p.h>
49 #include <private/qquickvisualadaptormodel_p.h>
50 #include <private/qquickchangeset_p.h>
51 #include <private/qqmlengine_p.h>
52 #include <private/qqmlcomponent_p.h>
53 #include <private/qqmlincubator_p.h>
54 #include <private/qqmlcompiler_p.h>
55
56 QT_BEGIN_NAMESPACE
57
58 class QQuickVisualDataModelEngineData : public QV8Engine::Deletable
59 {
60 public:
61     enum
62     {
63         Model,
64         Groups,
65         IsUnresolved,
66         ItemsIndex,
67         PersistedItemsIndex,
68         InItems,
69         InPersistedItems,
70         StringCount
71     };
72
73     QQuickVisualDataModelEngineData(QV8Engine *engine);
74     ~QQuickVisualDataModelEngineData();
75
76     v8::Local<v8::Object> array(
77             QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes);
78     v8::Local<v8::Object> array(
79             QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes);
80     v8::Local<v8::Object> array(
81             QV8Engine *engine, const QVector<QQuickChangeSet::Change> &changes);
82
83
84     inline v8::Local<v8::String> model() { return strings->Get(Model)->ToString(); }
85     inline v8::Local<v8::String> groups() { return strings->Get(Groups)->ToString(); }
86     inline v8::Local<v8::String> isUnresolved() { return strings->Get(IsUnresolved)->ToString(); }
87     inline v8::Local<v8::String> itemsIndex() { return strings->Get(ItemsIndex)->ToString(); }
88     inline v8::Local<v8::String> persistedItemsIndex() { return strings->Get(PersistedItemsIndex)->ToString(); }
89     inline v8::Local<v8::String> inItems() { return strings->Get(InItems)->ToString(); }
90     inline v8::Local<v8::String> inPersistedItems() { return strings->Get(InPersistedItems)->ToString(); }
91
92     v8::Persistent<v8::Array> strings;
93     v8::Persistent<v8::Function> constructorChange;
94     v8::Persistent<v8::Function> constructorChangeArray;
95 };
96
97 V8_DEFINE_EXTENSION(QQuickVisualDataModelEngineData, engineData)
98
99
100 void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
101 {
102     prop.setWritable(false);
103 }
104
105 QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
106 {
107     QQuickVisualDataModelParts *parts = static_cast<QQuickVisualDataModelParts *>(object());
108     QQuickVisualPartsModel *m = new QQuickVisualPartsModel(
109             parts->model, QString::fromUtf8(name(id)), parts);
110     parts->models.append(m);
111     return QVariant::fromValue(static_cast<QObject *>(m));
112 }
113
114 QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
115 : QObject(parent), model(parent)
116 {
117     new QQuickVisualDataModelPartsMetaObject(this);
118 }
119
120 //---------------------------------------------------------------------------
121
122 /*!
123     \qmlclass VisualDataModel QQuickVisualDataModel
124     \inqmlmodule QtQuick 2
125     \ingroup qtquick-models
126     \brief Encapsulates a model and delegate
127
128     The VisualDataModel type encapsulates a model and the delegate that will
129     be instantiated for items in the model.
130
131     It is usually not necessary to create a VisualDataModel.
132     However, it can be useful for manipulating and accessing the \l modelIndex
133     when a QAbstractItemModel subclass is used as the
134     model. Also, VisualDataModel is used together with \l Package to
135     provide delegates to multiple views.
136
137     The example below illustrates using a VisualDataModel with a ListView.
138
139     \snippet qml/visualdatamodel.qml 0
140 */
141
142 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QQmlContext *ctxt)
143     : m_delegate(0)
144     , m_cacheMetaType(0)
145     , m_context(ctxt)
146     , m_parts(0)
147     , m_filterGroup(QStringLiteral("items"))
148     , m_count(0)
149     , m_groupCount(Compositor::MinimumGroupCount)
150     , m_compositorGroup(Compositor::Cache)
151     , m_complete(false)
152     , m_delegateValidated(false)
153     , m_reset(false)
154     , m_transaction(false)
155     , m_incubatorCleanupScheduled(false)
156     , m_cacheItems(0)
157     , m_items(0)
158     , m_persistedItems(0)
159 {
160 }
161
162 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
163 {
164     qDeleteAll(m_finishedIncubating);
165
166     if (m_cacheMetaType)
167         m_cacheMetaType->release();
168 }
169
170 void QQuickVisualDataModelPrivate::init()
171 {
172     Q_Q(QQuickVisualDataModel);
173     m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
174
175     m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
176     m_items->setDefaultInclude(true);
177     m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
178     QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
179 }
180
181 QQuickVisualDataModel::QQuickVisualDataModel()
182 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
183 {
184     Q_D(QQuickVisualDataModel);
185     d->init();
186 }
187
188 QQuickVisualDataModel::QQuickVisualDataModel(QQmlContext *ctxt, QObject *parent)
189 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
190 {
191     Q_D(QQuickVisualDataModel);
192     d->init();
193 }
194
195 QQuickVisualDataModel::~QQuickVisualDataModel()
196 {
197     Q_D(QQuickVisualDataModel);
198
199     foreach (QQuickVisualDataModelItem *cacheItem, d->m_cache) {
200         if (cacheItem->object) {
201             delete cacheItem->object;
202
203             cacheItem->object = 0;
204             cacheItem->contextData->destroy();
205             cacheItem->contextData = 0;
206             cacheItem->scriptRef -= 1;
207         }
208         cacheItem->groups &= ~Compositor::UnresolvedFlag;
209         cacheItem->objectRef = 0;
210         if (!cacheItem->isReferenced())
211             delete cacheItem;
212     }
213 }
214
215
216 void QQuickVisualDataModel::classBegin()
217 {
218     Q_D(QQuickVisualDataModel);
219     if (!d->m_context)
220         d->m_context = qmlContext(this);
221 }
222
223 void QQuickVisualDataModel::componentComplete()
224 {
225     Q_D(QQuickVisualDataModel);
226     d->m_complete = true;
227
228     int defaultGroups = 0;
229     QStringList groupNames;
230     groupNames.append(QStringLiteral("items"));
231     groupNames.append(QStringLiteral("persistedItems"));
232     if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
233         defaultGroups |= Compositor::DefaultFlag;
234     if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
235         defaultGroups |= Compositor::PersistedFlag;
236     for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
237         QString name = d->m_groups[i]->name();
238         if (name.isEmpty()) {
239             d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
240             --d->m_groupCount;
241             --i;
242         } else if (name.at(0).isUpper()) {
243             qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
244             d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
245             --d->m_groupCount;
246             --i;
247         } else {
248             groupNames.append(name);
249
250             QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
251             group->setModel(this, Compositor::Group(i));
252             if (group->defaultInclude)
253                 defaultGroups |= (1 << i);
254         }
255     }
256
257     d->m_cacheMetaType = new QQuickVisualDataModelItemMetaType(
258             QQmlEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
259
260     d->m_compositor.setGroupCount(d->m_groupCount);
261     d->m_compositor.setDefaultGroups(defaultGroups);
262     d->updateFilterGroup();
263
264     while (!d->m_pendingParts.isEmpty())
265         static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
266
267     QVector<Compositor::Insert> inserts;
268     d->m_count = d->m_adaptorModel.count();
269     d->m_compositor.append(
270             &d->m_adaptorModel,
271             0,
272             d->m_count,
273             defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
274             &inserts);
275     d->itemsInserted(inserts);
276     d->emitChanges();
277
278     if (d->m_adaptorModel.canFetchMore())
279         QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
280 }
281
282 /*!
283     \qmlproperty model QtQuick2::VisualDataModel::model
284     This property holds the model providing data for the VisualDataModel.
285
286     The model provides a set of data that is used to create the items
287     for a view.  For large or dynamic datasets the model is usually
288     provided by a C++ model object.  The C++ model object must be a \l
289     {QAbstractItemModel} subclass or a simple list.
290
291     Models can also be created directly in QML, using a \l{ListModel} or
292     \l{XmlListModel}.
293
294     \sa {qmlmodels}{Data Models}
295 */
296 QVariant QQuickVisualDataModel::model() const
297 {
298     Q_D(const QQuickVisualDataModel);
299     return d->m_adaptorModel.model();
300 }
301
302 void QQuickVisualDataModel::setModel(const QVariant &model)
303 {
304     Q_D(QQuickVisualDataModel);
305
306     if (d->m_complete)
307         _q_itemsRemoved(0, d->m_count);
308
309     d->m_adaptorModel.setModel(model, this, d->m_context->engine());
310     d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
311     for (int i = 0; d->m_parts && i < d->m_parts->models.count(); ++i) {
312         d->m_adaptorModel.replaceWatchedRoles(
313                 QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
314     }
315
316     if (d->m_complete) {
317         _q_itemsInserted(0, d->m_adaptorModel.count());
318         if (d->m_adaptorModel.canFetchMore())
319             QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
320     }
321 }
322
323 /*!
324     \qmlproperty Component QtQuick2::VisualDataModel::delegate
325
326     The delegate provides a template defining each item instantiated by a view.
327     The index is exposed as an accessible \c index property.  Properties of the
328     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
329 */
330 QQmlComponent *QQuickVisualDataModel::delegate() const
331 {
332     Q_D(const QQuickVisualDataModel);
333     return d->m_delegate;
334 }
335
336 void QQuickVisualDataModel::setDelegate(QQmlComponent *delegate)
337 {
338     Q_D(QQuickVisualDataModel);
339     if (d->m_transaction) {
340         qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
341         return;
342     }
343     bool wasValid = d->m_delegate != 0;
344     d->m_delegate = delegate;
345     d->m_delegateValidated = false;
346     if (wasValid && d->m_complete) {
347         for (int i = 1; i < d->m_groupCount; ++i) {
348             QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
349                     0, d->m_compositor.count(Compositor::Group(i)));
350         }
351     }
352     if (d->m_complete && d->m_delegate) {
353         for (int i = 1; i < d->m_groupCount; ++i) {
354             QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
355                     0, d->m_compositor.count(Compositor::Group(i)));
356         }
357     }
358     d->emitChanges();
359 }
360
361 /*!
362     \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
363
364     QAbstractItemModel provides a hierarchical tree of data, whereas
365     QML only operates on list data.  \c rootIndex allows the children of
366     any node in a QAbstractItemModel to be provided by this model.
367
368     This property only affects models of type QAbstractItemModel that
369     are hierarchical (e.g, a tree model).
370
371     For example, here is a simple interactive file system browser.
372     When a directory name is clicked, the view's \c rootIndex is set to the
373     QModelIndex node of the clicked directory, thus updating the view to show
374     the new directory's contents.
375
376     \c main.cpp:
377     \snippet qml/visualdatamodel_rootindex/main.cpp 0
378
379     \c view.qml:
380     \snippet qml/visualdatamodel_rootindex/view.qml 0
381
382     If the \l model is a QAbstractItemModel subclass, the delegate can also
383     reference a \c hasModelChildren property (optionally qualified by a
384     \e model. prefix) that indicates whether the delegate's model item has
385     any child nodes.
386
387
388     \sa modelIndex(), parentModelIndex()
389 */
390 QVariant QQuickVisualDataModel::rootIndex() const
391 {
392     Q_D(const QQuickVisualDataModel);
393     return QVariant::fromValue(d->m_adaptorModel.rootIndex);
394 }
395
396 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
397 {
398     Q_D(QQuickVisualDataModel);
399
400     QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
401     if (d->m_adaptorModel.rootIndex != modelIndex) {
402         const int oldCount = d->m_count;
403         d->m_adaptorModel.rootIndex = modelIndex;
404         if (d->m_adaptorModel.canFetchMore())
405             d->m_adaptorModel.fetchMore();
406         if (d->m_complete) {
407             const int newCount = d->m_adaptorModel.count();
408             if (oldCount)
409                 _q_itemsRemoved(0, oldCount);
410             if (newCount)
411                 _q_itemsInserted(0, newCount);
412         }
413         emit rootIndexChanged();
414     }
415 }
416
417 /*!
418     \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
419
420     QAbstractItemModel provides a hierarchical tree of data, whereas
421     QML only operates on list data.  This function assists in using
422     tree models in QML.
423
424     Returns a QModelIndex for the specified index.
425     This value can be assigned to rootIndex.
426
427     \sa rootIndex
428 */
429 QVariant QQuickVisualDataModel::modelIndex(int idx) const
430 {
431     Q_D(const QQuickVisualDataModel);
432     return d->m_adaptorModel.modelIndex(idx);
433 }
434
435 /*!
436     \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
437
438     QAbstractItemModel provides a hierarchical tree of data, whereas
439     QML only operates on list data.  This function assists in using
440     tree models in QML.
441
442     Returns a QModelIndex for the parent of the current rootIndex.
443     This value can be assigned to rootIndex.
444
445     \sa rootIndex
446 */
447 QVariant QQuickVisualDataModel::parentModelIndex() const
448 {
449     Q_D(const QQuickVisualDataModel);
450     return d->m_adaptorModel.parentModelIndex();
451 }
452
453 /*!
454     \qmlproperty int QtQuick2::VisualDataModel::count
455 */
456
457 int QQuickVisualDataModel::count() const
458 {
459     Q_D(const QQuickVisualDataModel);
460     if (!d->m_delegate)
461         return 0;
462     return d->m_compositor.count(d->m_compositorGroup);
463 }
464
465 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
466 {
467     QQuickVisualDataModel::ReleaseFlags stat = 0;
468     if (!object)
469         return stat;
470
471     if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(object)) {
472         if (cacheItem->releaseObject()) {
473             cacheItem->destroyObject();
474             if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
475                 emitDestroyingItem(item);
476             if (cacheItem->incubationTask) {
477                 releaseIncubator(cacheItem->incubationTask);
478                 cacheItem->incubationTask = 0;
479             }
480             cacheItem->Dispose();
481             stat |= QQuickVisualModel::Destroyed;
482         } else {
483             stat |= QQuickVisualDataModel::Referenced;
484         }
485     }
486     return stat;
487 }
488
489 /*
490   Returns ReleaseStatus flags.
491 */
492
493 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
494 {
495     Q_D(QQuickVisualDataModel);
496     QQuickVisualModel::ReleaseFlags stat = d->release(item);
497     if (stat & Destroyed)
498         item->setParentItem(0);
499     return stat;
500 }
501
502 // Cancel a requested async item
503 void QQuickVisualDataModel::cancel(int index)
504 {
505     Q_D(QQuickVisualDataModel);
506     if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
507         qWarning() << "VisualDataModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
508         return;
509     }
510
511     Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
512     QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
513     if (cacheItem) {
514         if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
515             d->releaseIncubator(cacheItem->incubationTask);
516             cacheItem->incubationTask = 0;
517
518             if (cacheItem->object) {
519                 QObject *object = cacheItem->object;
520                 cacheItem->destroyObject();
521                 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
522                     d->emitDestroyingItem(item);
523                 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
524                     d->emitDestroyingPackage(package);
525             }
526
527             cacheItem->scriptRef -= 1;
528         }
529         if (!cacheItem->isReferenced()) {
530             d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
531             d->m_cache.removeAt(it.cacheIndex);
532             delete cacheItem;
533             Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
534         }
535     }
536 }
537
538 void QQuickVisualDataModelPrivate::group_append(
539         QQmlListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
540 {
541     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
542     if (d->m_complete)
543         return;
544     if (d->m_groupCount == Compositor::MaximumGroupCount) {
545         qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
546         return;
547     }
548     d->m_groups[d->m_groupCount] = group;
549     d->m_groupCount += 1;
550 }
551
552 int QQuickVisualDataModelPrivate::group_count(
553         QQmlListProperty<QQuickVisualDataGroup> *property)
554 {
555     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
556     return d->m_groupCount - 1;
557 }
558
559 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
560         QQmlListProperty<QQuickVisualDataGroup> *property, int index)
561 {
562     QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
563     return index >= 0 && index < d->m_groupCount - 1
564             ? d->m_groups[index + 1]
565             : 0;
566 }
567
568 /*!
569     \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
570
571     This property holds a visual data model's group definitions.
572
573     Groups define a sub-set of the items in a visual data model and can be used to filter
574     a model.
575
576     For every group defined in a VisualDataModel two attached properties are added to each
577     delegate item.  The first of the form VisualDataModel.in\e{GroupName} holds whether the
578     item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
579     index of the item in that group.
580
581     The following example illustrates using groups to select items in a model.
582
583     \snippet qml/visualdatagroup.qml 0
584 */
585
586 QQmlListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
587 {
588     Q_D(QQuickVisualDataModel);
589     return QQmlListProperty<QQuickVisualDataGroup>(
590             this,
591             d,
592             QQuickVisualDataModelPrivate::group_append,
593             QQuickVisualDataModelPrivate::group_count,
594             QQuickVisualDataModelPrivate::group_at);
595 }
596
597 /*!
598     \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
599
600     This property holds visual data model's default group to which all new items are added.
601 */
602
603 QQuickVisualDataGroup *QQuickVisualDataModel::items()
604 {
605     Q_D(QQuickVisualDataModel);
606     return d->m_items;
607 }
608
609 /*!
610     \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
611
612     This property holds visual data model's persisted items group.
613
614     Items in this group are not destroyed when released by a view, instead they are persisted
615     until removed from the group.
616
617     An item can be removed from the persistedItems group by setting the
618     VisualDataModel.inPersistedItems property to false.  If the item is not referenced by a view
619     at that time it will be destroyed.  Adding an item to this group will not create a new
620     instance.
621
622     Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
623     to this group.
624 */
625
626 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
627 {
628     Q_D(QQuickVisualDataModel);
629     return d->m_persistedItems;
630 }
631
632 /*!
633     \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
634
635     This property holds the name of the group used to filter the visual data model.
636
637     Only items which belong to this group are visible to a view.
638
639     By default this is the \l items group.
640 */
641
642 QString QQuickVisualDataModel::filterGroup() const
643 {
644     Q_D(const QQuickVisualDataModel);
645     return d->m_filterGroup;
646 }
647
648 void QQuickVisualDataModel::setFilterGroup(const QString &group)
649 {
650     Q_D(QQuickVisualDataModel);
651
652     if (d->m_transaction) {
653         qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
654         return;
655     }
656
657     if (d->m_filterGroup != group) {
658         d->m_filterGroup = group;
659         d->updateFilterGroup();
660         emit filterGroupChanged();
661     }
662 }
663
664 void QQuickVisualDataModel::resetFilterGroup()
665 {
666     setFilterGroup(QStringLiteral("items"));
667 }
668
669 void QQuickVisualDataModelPrivate::updateFilterGroup()
670 {
671     Q_Q(QQuickVisualDataModel);
672     if (!m_cacheMetaType)
673         return;
674
675     QQuickListCompositor::Group previousGroup = m_compositorGroup;
676     m_compositorGroup = Compositor::Default;
677     for (int i = 1; i < m_groupCount; ++i) {
678         if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
679             m_compositorGroup = Compositor::Group(i);
680             break;
681         }
682     }
683
684     QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
685     if (m_compositorGroup != previousGroup) {
686         QVector<QQuickChangeSet::Remove> removes;
687         QVector<QQuickChangeSet::Insert> inserts;
688         m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
689
690         QQuickChangeSet changeSet;
691         changeSet.apply(removes, inserts);
692         emit q->modelUpdated(changeSet, false);
693
694         if (changeSet.difference() != 0)
695             emit q->countChanged();
696
697         if (m_parts) {
698             foreach (QQuickVisualPartsModel *model, m_parts->models)
699                 model->updateFilterGroup(m_compositorGroup, changeSet);
700         }
701     }
702 }
703
704 /*!
705     \qmlproperty object QtQuick2::VisualDataModel::parts
706
707     The \a parts property selects a VisualDataModel which creates
708     delegates from the part named.  This is used in conjunction with
709     the \l Package type.
710
711     For example, the code below selects a model which creates
712     delegates named \e list from a \l Package:
713
714     \code
715     VisualDataModel {
716         id: visualModel
717         delegate: Package {
718             Item { Package.name: "list" }
719         }
720         model: myModel
721     }
722
723     ListView {
724         width: 200; height:200
725         model: visualModel.parts.list
726     }
727     \endcode
728
729     \sa Package
730 */
731
732 QObject *QQuickVisualDataModel::parts()
733 {
734     Q_D(QQuickVisualDataModel);
735     if (!d->m_parts)
736         d->m_parts = new QQuickVisualDataModelParts(this);
737     return d->m_parts;
738 }
739
740 void QQuickVisualDataModelPrivate::emitCreatedPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
741 {
742     for (int i = 1; i < m_groupCount; ++i)
743         QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
744 }
745
746 void QQuickVisualDataModelPrivate::emitInitPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
747 {
748     for (int i = 1; i < m_groupCount; ++i)
749         QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
750 }
751
752 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
753 {
754     for (int i = 1; i < m_groupCount; ++i)
755         QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
756 }
757
758 void QVDMIncubationTask::statusChanged(Status status)
759 {
760     vdm->incubatorStatusChanged(this, status);
761 }
762
763 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
764 {
765     Q_Q(QQuickVisualDataModel);
766     if (!incubationTask->isError())
767         incubationTask->clear();
768     m_finishedIncubating.append(incubationTask);
769     if (!m_incubatorCleanupScheduled) {
770         m_incubatorCleanupScheduled = true;
771         QCoreApplication::postEvent(q, new QEvent(QEvent::User));
772     }
773 }
774
775 void QQuickVisualDataModelPrivate::removeCacheItem(QQuickVisualDataModelItem *cacheItem)
776 {
777     int cidx = m_cache.indexOf(cacheItem);
778     if (cidx >= 0) {
779         m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
780         m_cache.removeAt(cidx);
781     }
782     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
783 }
784
785 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
786 {
787     Q_Q(QQuickVisualDataModel);
788     if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
789         return;
790
791     QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
792     cacheItem->incubationTask = 0;
793     incubationTask->incubating = 0;
794     releaseIncubator(incubationTask);
795
796     if (status == QQmlIncubator::Ready) {
797         if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
798             emitCreatedItem(incubationTask, item);
799         else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
800             emitCreatedPackage(incubationTask, package);
801     } else if (status == QQmlIncubator::Error) {
802         qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
803     }
804
805     if (!cacheItem->isObjectReferenced()) {
806         if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
807             emitDestroyingItem(item);
808         else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
809             emitDestroyingPackage(package);
810         delete cacheItem->object;
811         cacheItem->object = 0;
812         cacheItem->scriptRef -= 1;
813         cacheItem->contextData->destroy();
814         cacheItem->contextData = 0;
815         if (!cacheItem->isReferenced()) {
816             removeCacheItem(cacheItem);
817             delete cacheItem;
818         }
819     }
820 }
821
822 void QVDMIncubationTask::setInitialState(QObject *o)
823 {
824     vdm->setInitialState(this, o);
825 }
826
827 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
828 {
829     QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
830     cacheItem->object = o;
831
832     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
833         emitInitItem(incubationTask, item);
834     else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
835         emitInitPackage(incubationTask, package);
836 }
837
838 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous)
839 {
840     Q_Q(QQuickVisualDataModel);
841     if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
842         qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
843         return 0;
844     }
845
846     Compositor::iterator it = m_compositor.find(group, index);
847
848     QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
849
850     if (!cacheItem) {
851         cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), it.modelIndex());
852         if (!cacheItem)
853             return 0;
854
855         cacheItem->groups = it->flags;
856
857         m_cache.insert(it.cacheIndex, cacheItem);
858         m_compositor.setFlags(it, 1, Compositor::CacheFlag);
859         Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
860     }
861
862     // Bump the reference counts temporarily so neither the content data or the delegate object
863     // are deleted if incubatorStatusChanged() is called synchronously.
864     cacheItem->scriptRef += 1;
865     cacheItem->referenceObject();
866
867     if (cacheItem->incubationTask) {
868         if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
869             // previously requested async - now needed immediately
870             cacheItem->incubationTask->forceCompletion();
871         }
872     } else if (!cacheItem->object) {
873         QQmlContext *creationContext = m_delegate->creationContext();
874
875         cacheItem->scriptRef += 1;
876
877         cacheItem->incubationTask = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
878         cacheItem->incubationTask->incubating = cacheItem;
879         cacheItem->incubationTask->clear();
880
881         for (int i = 1; i < m_groupCount; ++i)
882             cacheItem->incubationTask->index[i] = it.index[i];
883
884         QQmlContextData *ctxt = new QQmlContextData;
885         ctxt->setParent(QQmlContextData::get(creationContext  ? creationContext : m_context));
886         ctxt->contextObject = cacheItem;
887         cacheItem->contextData = ctxt;
888
889         if (m_adaptorModel.hasProxyObject()) {
890             if (QQuickVisualAdaptorModelProxyInterface *proxy
891                     = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
892                 ctxt = new QQmlContextData;
893                 ctxt->setParent(cacheItem->contextData, true);
894                 ctxt->contextObject = proxy->proxiedObject();
895             }
896         }
897
898         cacheItem->incubateObject(
899                     m_delegate,
900                     m_context->engine(),
901                     ctxt,
902                     QQmlContextData::get(m_context));
903     }
904
905     if (index == m_compositor.count(group) - 1 && m_adaptorModel.canFetchMore())
906         QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
907
908     // Remove the temporary reference count.
909     cacheItem->scriptRef -= 1;
910     if (cacheItem->object)
911         return cacheItem->object;
912
913     cacheItem->releaseObject();
914     if (!cacheItem->isReferenced()) {
915         removeCacheItem(cacheItem);
916         delete cacheItem;
917     }
918
919     return 0;
920 }
921
922 /*
923   If asynchronous is true or the component is being loaded asynchronously due
924   to an ancestor being loaded asynchronously, item() may return 0.  In this
925   case itemCreated() will be emitted when the item is available.  The item
926   at this stage does not have any references, so item() must be called again
927   to ensure a reference is held.  Any call to item() which returns a valid item
928   must be matched by a call to release() in order to destroy the item.
929 */
930 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
931 {
932     Q_D(QQuickVisualDataModel);
933     if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
934         qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
935         return 0;
936     }
937
938     QObject *object = d->object(d->m_compositorGroup, index, asynchronous);
939     if (!object)
940         return 0;
941
942     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
943         return item;
944
945     d->release(object);
946     if (!d->m_delegateValidated) {
947         if (object)
948             qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
949         d->m_delegateValidated = true;
950     }
951     return 0;
952 }
953
954 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
955 {
956     Compositor::iterator it = m_compositor.find(group, index);
957     if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
958         QString role = name;
959         int dot = name.indexOf(QLatin1Char('.'));
960         if (dot > 0)
961             role = name.left(dot);
962         QVariant value = model->value(it.modelIndex(), role);
963         while (dot > 0) {
964             QObject *obj = qvariant_cast<QObject*>(value);
965             if (!obj)
966                 return QString();
967             int from = dot+1;
968             dot = name.indexOf(QLatin1Char('.'), from);
969             value = obj->property(name.mid(from, dot-from).toUtf8());
970         }
971         return value.toString();
972     }
973     return QString();
974 }
975
976 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
977 {
978     Q_D(QQuickVisualDataModel);
979     return d->stringValue(d->m_compositorGroup, index, name);
980 }
981
982 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
983 {
984     Q_D(const QQuickVisualDataModel);
985     if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
986         return cacheItem->groupIndex(d->m_compositorGroup);
987     return -1;
988 }
989
990 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
991 {
992     Q_D(QQuickVisualDataModel);
993     d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
994     d->m_watchedRoles = roles;
995 }
996
997 void QQuickVisualDataModelPrivate::addGroups(
998         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
999 {
1000     QVector<Compositor::Insert> inserts;
1001     m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1002     itemsInserted(inserts);
1003     emitChanges();
1004 }
1005
1006 void QQuickVisualDataModelPrivate::removeGroups(
1007         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1008 {
1009     QVector<Compositor::Remove> removes;
1010     m_compositor.clearFlags(from, count, group, groupFlags, &removes);
1011     itemsRemoved(removes);
1012     emitChanges();
1013 }
1014
1015 void QQuickVisualDataModelPrivate::setGroups(
1016         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1017 {
1018     QVector<Compositor::Remove> removes;
1019     QVector<Compositor::Insert> inserts;
1020
1021     m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1022     itemsInserted(inserts);
1023     const int removeFlags = ~groupFlags & Compositor::GroupMask;
1024
1025     from = m_compositor.find(from.group, from.index[from.group]);
1026     m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1027     itemsRemoved(removes);
1028     emitChanges();
1029 }
1030
1031 bool QQuickVisualDataModel::event(QEvent *e)
1032 {
1033     Q_D(QQuickVisualDataModel);
1034     if (e->type() == QEvent::UpdateRequest) {
1035         d->m_adaptorModel.fetchMore();
1036     } else if (e->type() == QEvent::User) {
1037         d->m_incubatorCleanupScheduled = false;
1038         qDeleteAll(d->m_finishedIncubating);
1039         d->m_finishedIncubating.clear();
1040     }
1041     return QQuickVisualModel::event(e);
1042 }
1043
1044 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1045 {
1046     if (!m_delegate)
1047         return;
1048
1049     QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1050
1051     foreach (const Compositor::Change &change, changes) {
1052         for (int i = 1; i < m_groupCount; ++i) {
1053             if (change.inGroup(i)) {
1054                 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
1055             }
1056         }
1057     }
1058
1059     for (int i = 1; i < m_groupCount; ++i)
1060         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1061 }
1062
1063 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
1064 {
1065     Q_D(QQuickVisualDataModel);
1066     if (count <= 0 || !d->m_complete)
1067         return;
1068
1069     if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1070         QVector<Compositor::Change> changes;
1071         d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1072         d->itemsChanged(changes);
1073         d->emitChanges();
1074     }
1075 }
1076
1077 static void incrementIndexes(QQuickVisualDataModelItem *cacheItem, int count, const int *deltas)
1078 {
1079     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1080         for (int i = 1; i < count; ++i)
1081             incubationTask->index[i] += deltas[i];
1082     }
1083     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1084         for (int i = 1; i < count; ++i)
1085             attached->m_currentIndex[i] += deltas[i];
1086     }
1087 }
1088
1089 void QQuickVisualDataModelPrivate::itemsInserted(
1090         const QVector<Compositor::Insert> &inserts,
1091         QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1092         QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1093 {
1094     int cacheIndex = 0;
1095
1096     int inserted[Compositor::MaximumGroupCount];
1097     for (int i = 1; i < m_groupCount; ++i)
1098         inserted[i] = 0;
1099
1100     foreach (const Compositor::Insert &insert, inserts) {
1101         for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
1102             incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1103
1104         for (int i = 1; i < m_groupCount; ++i) {
1105             if (insert.inGroup(i)) {
1106                 (*translatedInserts)[i].append(
1107                         QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1108                 inserted[i] += insert.count;
1109             }
1110         }
1111
1112         if (!insert.inCache())
1113             continue;
1114
1115         if (movedItems && insert.isMove()) {
1116             QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1117             Q_ASSERT(items.count() == insert.count);
1118             m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1119         }
1120         if (insert.inGroup()) {
1121             for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1122                 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1123                 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1124
1125                 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1126                     for (int i = 1; i < m_groupCount; ++i)
1127                         incubationTask->index[i] = cacheItem->groups & (1 << i)
1128                                 ? insert.index[i] + offset
1129                                 : insert.index[i];
1130                 }
1131                 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1132                     for (int i = 1; i < m_groupCount; ++i)
1133                         attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1134                                 ? insert.index[i] + offset
1135                                 : insert.index[i];
1136                 }
1137             }
1138         } else {
1139             cacheIndex = insert.cacheIndex + insert.count;
1140         }
1141     }
1142     for (; cacheIndex < m_cache.count(); ++cacheIndex)
1143         incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1144 }
1145
1146 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1147 {
1148     QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1149     itemsInserted(inserts, &translatedInserts);
1150     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1151     if (!m_delegate)
1152         return;
1153
1154     for (int i = 1; i < m_groupCount; ++i)
1155         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1156 }
1157
1158 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1159 {
1160
1161     Q_D(QQuickVisualDataModel);
1162     if (count <= 0 || !d->m_complete)
1163         return;
1164
1165     d->m_count += count;
1166
1167     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1168         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1169         if (item->modelIndex() >= index)
1170             item->setModelIndex(item->modelIndex() + count);
1171     }
1172
1173     QVector<Compositor::Insert> inserts;
1174     d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1175     d->itemsInserted(inserts);
1176     d->emitChanges();
1177 }
1178
1179 void QQuickVisualDataModelPrivate::itemsRemoved(
1180         const QVector<Compositor::Remove> &removes,
1181         QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1182         QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1183 {
1184     int cacheIndex = 0;
1185     int removedCache = 0;
1186
1187     int removed[Compositor::MaximumGroupCount];
1188     for (int i = 1; i < m_groupCount; ++i)
1189         removed[i] = 0;
1190
1191     foreach (const Compositor::Remove &remove, removes) {
1192         for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
1193             incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1194
1195         for (int i = 1; i < m_groupCount; ++i) {
1196             if (remove.inGroup(i)) {
1197                 (*translatedRemoves)[i].append(
1198                         QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1199                 removed[i] -= remove.count;
1200             }
1201         }
1202
1203         if (!remove.inCache())
1204             continue;
1205
1206         if (movedItems && remove.isMove()) {
1207             movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1208             QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1209             QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1210             m_cache.erase(begin, end);
1211         } else {
1212             for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1213                 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1214                 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1215                     QObject *object = cacheItem->object;
1216                     cacheItem->destroyObject();
1217                     if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1218                         emitDestroyingPackage(package);
1219                     else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
1220                         emitDestroyingItem(item);
1221                     cacheItem->scriptRef -= 1;
1222                 }
1223                 if (!cacheItem->isReferenced()) {
1224                     m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1225                     m_cache.removeAt(cacheIndex);
1226                     delete cacheItem;
1227                     --cacheIndex;
1228                     ++removedCache;
1229                     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1230                 } else if (remove.groups() == cacheItem->groups) {
1231                     cacheItem->groups = 0;
1232                     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1233                         for (int i = 1; i < m_groupCount; ++i)
1234                             incubationTask->index[i] = -1;
1235                     }
1236                     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1237                         for (int i = 1; i < m_groupCount; ++i)
1238                             attached->m_currentIndex[i] = -1;
1239                     }
1240                 } else {
1241                     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1242                         for (int i = 1; i < m_groupCount; ++i) {
1243                             if (remove.inGroup(i))
1244                                 incubationTask->index[i] = remove.index[i];
1245                         }
1246                     }
1247                     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1248                         for (int i = 1; i < m_groupCount; ++i) {
1249                             if (remove.inGroup(i))
1250                                 attached->m_currentIndex[i] = remove.index[i];
1251                         }
1252                     }
1253                     cacheItem->groups &= ~remove.flags;
1254                 }
1255             }
1256         }
1257     }
1258
1259     for (; cacheIndex < m_cache.count(); ++cacheIndex)
1260         incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1261 }
1262
1263 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1264 {
1265     QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1266     itemsRemoved(removes, &translatedRemoves);
1267     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1268     if (!m_delegate)
1269         return;
1270
1271     for (int i = 1; i < m_groupCount; ++i)
1272        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1273 }
1274
1275 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1276 {
1277     Q_D(QQuickVisualDataModel);
1278     if (count <= 0|| !d->m_complete)
1279         return;
1280
1281     d->m_count -= count;
1282
1283     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1284         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1285         if (item->modelIndex() >= index + count)
1286             item->setModelIndex(item->modelIndex() - count);
1287         else  if (item->modelIndex() >= index)
1288             item->setModelIndex(-1);
1289     }
1290
1291     QVector<Compositor::Remove> removes;
1292     d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1293     d->itemsRemoved(removes);
1294
1295     d->emitChanges();
1296 }
1297
1298 void QQuickVisualDataModelPrivate::itemsMoved(
1299         const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1300 {
1301     QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1302
1303     QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1304     itemsRemoved(removes, &translatedRemoves, &movedItems);
1305
1306     QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1307     itemsInserted(inserts, &translatedInserts, &movedItems);
1308     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1309     Q_ASSERT(movedItems.isEmpty());
1310     if (!m_delegate)
1311         return;
1312
1313     for (int i = 1; i < m_groupCount; ++i) {
1314         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1315                     translatedRemoves.at(i),
1316                     translatedInserts.at(i));
1317     }
1318 }
1319
1320 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1321 {
1322     Q_D(QQuickVisualDataModel);
1323     if (count <= 0 || !d->m_complete)
1324         return;
1325
1326     const int minimum = qMin(from, to);
1327     const int maximum = qMax(from, to) + count;
1328     const int difference = from > to ? count : -count;
1329
1330     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1331         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1332         if (item->modelIndex() >= from && item->modelIndex() < from + count)
1333             item->setModelIndex(item->modelIndex() - from + to);
1334         else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1335             item->setModelIndex(item->modelIndex() + difference);
1336     }
1337
1338     QVector<Compositor::Remove> removes;
1339     QVector<Compositor::Insert> inserts;
1340     d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1341     d->itemsMoved(removes, inserts);
1342     d->emitChanges();
1343 }
1344
1345 template <typename T> v8::Local<v8::Array>
1346 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1347 {
1348     v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1349     v8::Local<v8::String> indexKey = v8::String::New("index");
1350     v8::Local<v8::String> countKey = v8::String::New("count");
1351     v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1352
1353     for (int i = 0; i < changes.count(); ++i) {
1354         v8::Local<v8::Object> object = v8::Object::New();
1355         object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1356         object->Set(countKey, v8::Integer::New(changes.at(i).count));
1357         object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1358         indexes->Set(i, object);
1359     }
1360     return indexes;
1361 }
1362
1363 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1364 {
1365     Q_Q(QQuickVisualDataModel);
1366     emit q->modelUpdated(changeSet, reset);
1367     if (changeSet.difference() != 0)
1368         emit q->countChanged();
1369 }
1370
1371 void QQuickVisualDataModelPrivate::emitChanges()
1372 {
1373     if (m_transaction || !m_complete)
1374         return;
1375
1376     m_transaction = true;
1377     QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1378     for (int i = 1; i < m_groupCount; ++i)
1379         QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1380     m_transaction = false;
1381
1382     const bool reset = m_reset;
1383     m_reset = false;
1384     for (int i = 1; i < m_groupCount; ++i)
1385         QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1386
1387     foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1388         if (cacheItem->attached)
1389             cacheItem->attached->emitChanges();
1390     }
1391 }
1392
1393 void QQuickVisualDataModel::_q_modelReset()
1394 {
1395     Q_D(QQuickVisualDataModel);
1396     if (!d->m_delegate)
1397         return;
1398
1399     int oldCount = d->m_count;
1400     d->m_adaptorModel.rootIndex = QModelIndex();
1401
1402     if (d->m_complete) {
1403         d->m_count = d->m_adaptorModel.count();
1404
1405         for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1406             QQuickVisualDataModelItem *item = d->m_cache.at(i);
1407             if (item->modelIndex() != -1)
1408                 item->setModelIndex(-1);
1409         }
1410
1411         QVector<Compositor::Remove> removes;
1412         QVector<Compositor::Insert> inserts;
1413         if (oldCount)
1414             d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1415         if (d->m_count)
1416             d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1417         d->itemsMoved(removes, inserts);
1418         d->m_reset = true;
1419
1420         if (d->m_adaptorModel.canFetchMore())
1421             d->m_adaptorModel.fetchMore();
1422
1423         d->emitChanges();
1424     }
1425     emit rootIndexChanged();
1426 }
1427
1428 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1429 {
1430     Q_D(QQuickVisualDataModel);
1431     if (parent == d->m_adaptorModel.rootIndex)
1432         _q_itemsInserted(begin, end - begin + 1);
1433 }
1434
1435 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1436 {
1437     Q_D(QQuickVisualDataModel);
1438     if (parent == d->m_adaptorModel.rootIndex)
1439         _q_itemsRemoved(begin, end - begin + 1);
1440 }
1441
1442 void QQuickVisualDataModel::_q_rowsMoved(
1443         const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1444         const QModelIndex &destinationParent, int destinationRow)
1445 {
1446    Q_D(QQuickVisualDataModel);
1447     const int count = sourceEnd - sourceStart + 1;
1448     if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1449         _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1450     } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1451         _q_itemsRemoved(sourceStart, count);
1452     } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1453         _q_itemsInserted(destinationRow, count);
1454     }
1455 }
1456
1457 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
1458 {
1459     Q_D(QQuickVisualDataModel);
1460     if (begin.parent() == d->m_adaptorModel.rootIndex)
1461         _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
1462 }
1463
1464 void QQuickVisualDataModel::_q_layoutChanged()
1465 {
1466     Q_D(QQuickVisualDataModel);
1467     _q_itemsChanged(0, d->m_count, QVector<int>());
1468 }
1469
1470 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1471 {
1472     if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1473         if (cacheItem->object == obj) { // Don't create attached item for child objects.
1474             cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1475             return cacheItem->attached;
1476         }
1477     }
1478     return new QQuickVisualDataModelAttached(obj);
1479 }
1480
1481 bool QQuickVisualDataModelPrivate::insert(
1482         Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1483 {
1484     QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1485     if (!cacheItem)
1486         return false;
1487
1488     v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1489     for (uint i = 0; i < propertyNames->Length(); ++i) {
1490         v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1491         cacheItem->setValue(
1492                 m_cacheMetaType->v8Engine->toString(propertyName),
1493                 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1494     }
1495
1496     cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1497
1498     // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1499     itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1500
1501     before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1502     m_cache.insert(before.cacheIndex, cacheItem);
1503
1504     return true;
1505 }
1506
1507 //============================================================================
1508
1509 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1510         QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1511     : model(model)
1512     , groupCount(groupNames.count() + 1)
1513     , v8Engine(engine)
1514     , metaObject(0)
1515     , groupNames(groupNames)
1516 {
1517 }
1518
1519 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1520 {
1521     if (metaObject)
1522         metaObject->release();
1523     qPersistentDispose(constructor);
1524 }
1525
1526 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1527 {
1528     QMetaObjectBuilder builder;
1529     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1530     builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1531     builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1532
1533     int notifierId = 0;
1534     for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1535         QString propertyName = QStringLiteral("in") + groupNames.at(i);
1536         propertyName.replace(2, 1, propertyName.at(2).toUpper());
1537         builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1538         QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1539                 propertyName.toUtf8(), "bool", notifierId);
1540         propertyBuilder.setWritable(true);
1541     }
1542     for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1543         const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1544         builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1545         QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1546                 propertyName.toUtf8(), "int", notifierId);
1547         propertyBuilder.setWritable(true);
1548     }
1549
1550     metaObject = new QQuickVisualDataModelAttachedMetaObject(this, builder.toMetaObject());
1551 }
1552
1553 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1554 {
1555     v8::HandleScope handleScope;
1556     v8::Context::Scope contextScope(v8Engine->context());
1557
1558     QQuickVisualDataModelEngineData *data = engineData(v8Engine);
1559
1560     constructor = qPersistentNew(v8::ObjectTemplate::New());
1561
1562     constructor->SetHasExternalResource(true);
1563     constructor->SetAccessor(data->model(), get_model);
1564     constructor->SetAccessor(data->groups(), get_groups, set_groups);
1565     constructor->SetAccessor(data->isUnresolved(), get_member, 0, v8::Int32::New(30));
1566     constructor->SetAccessor(data->inItems(), get_member, set_member, v8::Int32::New(1));
1567     constructor->SetAccessor(data->inPersistedItems(), get_member, set_member, v8::Int32::New(2));
1568     constructor->SetAccessor(data->itemsIndex(), get_index, 0, v8::Int32::New(1));
1569     constructor->SetAccessor(data->persistedItemsIndex(), get_index, 0, v8::Int32::New(2));
1570
1571     for (int i = 2; i < groupNames.count(); ++i) {
1572         QString propertyName = QStringLiteral("in") + groupNames.at(i);
1573         propertyName.replace(2, 1, propertyName.at(2).toUpper());
1574         constructor->SetAccessor(
1575                 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1576     }
1577     for (int i = 2; i < groupNames.count(); ++i) {
1578         const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1579         constructor->SetAccessor(
1580                 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1581     }
1582 }
1583
1584 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1585 {
1586     int groupFlags = 0;
1587     foreach (const QString &groupName, groups) {
1588         int index = groupNames.indexOf(groupName);
1589         if (index != -1)
1590             groupFlags |= 2 << index;
1591     }
1592     return groupFlags;
1593 }
1594
1595 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1596 {
1597     int groupFlags = 0;
1598     if (groups->IsString()) {
1599         const QString groupName = v8Engine->toString(groups);
1600         int index = groupNames.indexOf(groupName);
1601         if (index != -1)
1602             groupFlags |= 2 << index;
1603     } else if (groups->IsArray()) {
1604         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1605         for (uint i = 0; i < array->Length(); ++i) {
1606             const QString groupName = v8Engine->toString(array->Get(i));
1607             int index = groupNames.indexOf(groupName);
1608             if (index != -1)
1609                 groupFlags |= 2 << index;
1610         }
1611     }
1612     return groupFlags;
1613 }
1614
1615 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1616         v8::Local<v8::String>, const v8::AccessorInfo &info)
1617 {
1618     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1619     V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1620     if (!cacheItem->metaType->model)
1621         return v8::Undefined();
1622
1623     return cacheItem->get();
1624 }
1625
1626 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1627         v8::Local<v8::String>, const v8::AccessorInfo &info)
1628 {
1629     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1630     V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1631
1632     QStringList groups;
1633     for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1634         if (cacheItem->groups & (1 << i))
1635             groups.append(cacheItem->metaType->groupNames.at(i - 1));
1636     }
1637
1638     return cacheItem->engine->fromVariant(groups);
1639 }
1640
1641 void QQuickVisualDataModelItemMetaType::set_groups(
1642         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1643 {
1644     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1645     V8ASSERT_TYPE_SETTER(cacheItem, "Not a valid VisualData object");
1646
1647     if (!cacheItem->metaType->model)
1648         return;
1649     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1650
1651     const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1652     const int cacheIndex = model->m_cache.indexOf(cacheItem);
1653     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1654     model->setGroups(it, 1, Compositor::Cache, groupFlags);
1655 }
1656
1657 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1658         v8::Local<v8::String>, const v8::AccessorInfo &info)
1659 {
1660     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1661     V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1662
1663     return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1664 }
1665
1666 void QQuickVisualDataModelItemMetaType::set_member(
1667         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1668 {
1669     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1670     V8ASSERT_TYPE_SETTER(cacheItem, "Not a valid VisualData object");
1671
1672     if (!cacheItem->metaType->model)
1673         return;
1674     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1675
1676     Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1677     const bool member = value->BooleanValue();
1678     const int groupFlag = (1 << group);
1679     if (member == ((cacheItem->groups & groupFlag) != 0))
1680         return;
1681
1682     const int cacheIndex = model->m_cache.indexOf(cacheItem);
1683     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1684     if (member)
1685         model->addGroups(it, 1, Compositor::Cache, groupFlag);
1686     else
1687         model->removeGroups(it, 1, Compositor::Cache, groupFlag);
1688 }
1689
1690 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1691         v8::Local<v8::String>, const v8::AccessorInfo &info)
1692 {
1693     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1694     V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1695
1696     return v8::Integer::New(cacheItem->groupIndex(Compositor::Group(info.Data()->Int32Value())));
1697 }
1698
1699
1700 //---------------------------------------------------------------------------
1701
1702 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1703         QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1704     : QV8ObjectResource(metaType->v8Engine)
1705     , metaType(metaType)
1706     , contextData(0)
1707     , object(0)
1708     , attached(0)
1709     , incubationTask(0)
1710     , objectRef(0)
1711     , scriptRef(0)
1712     , groups(0)
1713     , index(modelIndex)
1714 {
1715     metaType->addref();
1716 }
1717
1718 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1719 {
1720     Q_ASSERT(scriptRef == 0);
1721     Q_ASSERT(objectRef == 0);
1722     Q_ASSERT(!object);
1723
1724     if (incubationTask && metaType->model)
1725         QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1726
1727     metaType->release();
1728
1729 }
1730
1731 void QQuickVisualDataModelItem::Dispose()
1732 {
1733     --scriptRef;
1734     if (isReferenced())
1735         return;
1736
1737     if (metaType->model) {
1738         QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1739         model->removeCacheItem(this);
1740     }
1741     delete this;
1742 }
1743
1744 /*
1745     This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1746     arguments instead of QQmlContext which means we don't have to construct the rather weighty
1747     wrapper class for every delegate item.
1748 */
1749 void QQuickVisualDataModelItem::incubateObject(
1750         QQmlComponent *component,
1751         QQmlEngine *engine,
1752         QQmlContextData *context,
1753         QQmlContextData *forContext)
1754 {
1755     QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
1756     QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
1757     QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
1758
1759     incubatorPriv->compiledData = componentPriv->cc;
1760     incubatorPriv->compiledData->addref();
1761     incubatorPriv->vme.init(
1762             context,
1763             componentPriv->cc,
1764             componentPriv->start,
1765             componentPriv->creationContext);
1766
1767     enginePriv->incubate(*incubationTask, forContext);
1768 }
1769
1770 void QQuickVisualDataModelItem::destroyObject()
1771 {
1772     Q_ASSERT(object);
1773     Q_ASSERT(contextData);
1774
1775     QObjectPrivate *p = QObjectPrivate::get(object);
1776     Q_ASSERT(p->declarativeData);
1777     QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1778     if (data->ownContext && data->context)
1779         data->context->clearContext();
1780     object->deleteLater();
1781
1782     if (attached) {
1783         attached->m_cacheItem = 0;
1784         attached = 0;
1785     }
1786
1787     contextData->destroy();
1788     contextData = 0;
1789     object = 0;
1790 }
1791
1792 QQuickVisualDataModelItem *QQuickVisualDataModelItem::dataForObject(QObject *object)
1793 {
1794     QObjectPrivate *p = QObjectPrivate::get(object);
1795     QQmlContextData *context = p->declarativeData
1796             ? static_cast<QQmlData *>(p->declarativeData)->context
1797             : 0;
1798     for (context = context ? context->parent : 0; context; context = context->parent) {
1799         if (QQuickVisualDataModelItem *cacheItem = qobject_cast<QQuickVisualDataModelItem *>(
1800                 context->contextObject)) {
1801             return cacheItem;
1802         }
1803     }
1804     return 0;
1805 }
1806
1807 int QQuickVisualDataModelItem::groupIndex(Compositor::Group group)
1808 {
1809     if (QQuickVisualDataModelPrivate * const model = metaType->model
1810             ? QQuickVisualDataModelPrivate::get(metaType->model)
1811             : 0) {
1812         return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
1813     }
1814     return -1;
1815 }
1816
1817 //---------------------------------------------------------------------------
1818
1819 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1820         QQuickVisualDataModelItemMetaType *metaType, QMetaObject *metaObject)
1821     : metaType(metaType)
1822     , metaObject(metaObject)
1823     , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1824     , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
1825 {
1826     // Don't reference count the meta-type here as that would create a circular reference.
1827     // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
1828     // destroying all delegates with attached objects.
1829     *static_cast<QMetaObject *>(this) = *metaObject;
1830 }
1831
1832 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1833 {
1834     ::free(metaObject);
1835 }
1836
1837 void QQuickVisualDataModelAttachedMetaObject::objectDestroyed(QObject *)
1838 {
1839     release();
1840 }
1841
1842 int QQuickVisualDataModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
1843 {
1844     QQuickVisualDataModelAttached *attached = static_cast<QQuickVisualDataModelAttached *>(object);
1845     if (call == QMetaObject::ReadProperty) {
1846         if (_id >= indexPropertyOffset) {
1847             Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
1848             *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
1849             return -1;
1850         } else if (_id >= memberPropertyOffset) {
1851             Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1852             *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1853             return -1;
1854         }
1855     } else if (call == QMetaObject::WriteProperty) {
1856         if (_id >= memberPropertyOffset) {
1857             if (!metaType->model)
1858                 return -1;
1859             QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1860             Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1861             const int groupFlag = 1 << group;
1862             const bool member = attached->m_cacheItem->groups & groupFlag;
1863             if (member && !*static_cast<bool *>(arguments[0])) {
1864                 Compositor::iterator it = model->m_compositor.find(
1865                         group, attached->m_currentIndex[group]);
1866                 model->removeGroups(it, 1, group, groupFlag);
1867             } else if (!member && *static_cast<bool *>(arguments[0])) {
1868                 for (int i = 1; i < metaType->groupCount; ++i) {
1869                     if (attached->m_cacheItem->groups & (1 << i)) {
1870                         Compositor::iterator it = model->m_compositor.find(
1871                                 Compositor::Group(i), attached->m_currentIndex[i]);
1872                         model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1873                         break;
1874                     }
1875                 }
1876             }
1877             return -1;
1878         }
1879     }
1880     return attached->qt_metacall(call, _id, arguments);
1881 }
1882
1883 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1884     : m_cacheItem(0)
1885     , m_previousGroups(0)
1886 {
1887     QQml_setParent_noEvent(this, parent);
1888 }
1889
1890 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1891         QQuickVisualDataModelItem *cacheItem, QObject *parent)
1892     : m_cacheItem(cacheItem)
1893     , m_previousGroups(cacheItem->groups)
1894 {
1895     QQml_setParent_noEvent(this, parent);
1896     if (QVDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
1897         for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1898             m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
1899     } else {
1900         QQuickVisualDataModelPrivate * const model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1901         Compositor::iterator it = model->m_compositor.find(
1902                 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
1903         for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1904             m_currentIndex[i] = m_previousIndex[i] = it.index[i];
1905     }
1906
1907     if (!cacheItem->metaType->metaObject)
1908         cacheItem->metaType->initializeMetaObject();
1909
1910     QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
1911     cacheItem->metaType->metaObject->addref();
1912 }
1913
1914 /*!
1915     \qmlattachedproperty int QtQuick2::VisualDataModel::model
1916
1917     This attached property holds the visual data model this delegate instance belongs to.
1918
1919     It is attached to each instance of the delegate.
1920 */
1921
1922 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1923 {
1924     return m_cacheItem ? m_cacheItem->metaType->model : 0;
1925 }
1926
1927 /*!
1928     \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1929
1930     This attached property holds the name of VisualDataGroups the item belongs to.
1931
1932     It is attached to each instance of the delegate.
1933 */
1934
1935 QStringList QQuickVisualDataModelAttached::groups() const
1936 {
1937     QStringList groups;
1938
1939     if (!m_cacheItem)
1940         return groups;
1941     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1942         if (m_cacheItem->groups & (1 << i))
1943             groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1944     }
1945     return groups;
1946 }
1947
1948 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1949 {
1950     if (!m_cacheItem)
1951         return;
1952
1953     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1954
1955     const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1956     const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1957     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1958     model->setGroups(it, 1, Compositor::Cache, groupFlags);
1959 }
1960
1961 bool QQuickVisualDataModelAttached::isUnresolved() const
1962 {
1963     if (!m_cacheItem)
1964         return false;
1965
1966     return m_cacheItem->groups & Compositor::UnresolvedFlag;
1967 }
1968
1969 /*!
1970     \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1971
1972     This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1973
1974     Changing this property will add or remove the item from the items group.
1975
1976     It is attached to each instance of the delegate.
1977 */
1978
1979 /*!
1980     \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1981
1982     This attached property holds the index of the item in the default \l items VisualDataGroup.
1983
1984     It is attached to each instance of the delegate.
1985 */
1986
1987 /*!
1988     \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1989
1990     This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1991
1992     Changing this property will add or remove the item from the items group.  Change with caution
1993     as removing an item from the persistedItems group will destroy the current instance if it is
1994     not referenced by a model.
1995
1996     It is attached to each instance of the delegate.
1997 */
1998
1999 /*!
2000     \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
2001
2002     This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
2003
2004     It is attached to each instance of the delegate.
2005 */
2006
2007 void QQuickVisualDataModelAttached::emitChanges()
2008 {
2009     const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2010     m_previousGroups = m_cacheItem->groups;
2011
2012     int indexChanges = 0;
2013     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2014         if (m_previousIndex[i] != m_currentIndex[i]) {
2015             m_previousIndex[i] = m_currentIndex[i];
2016             indexChanges |= (1 << i);
2017         }
2018     }
2019
2020     int notifierId = 0;
2021     const QMetaObject *meta = metaObject();
2022     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2023         if (groupChanges & (1 << i))
2024             QMetaObject::activate(this, meta, notifierId, 0);
2025     }
2026     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2027         if (indexChanges & (1 << i))
2028             QMetaObject::activate(this, meta, notifierId, 0);
2029     }
2030
2031     if (groupChanges)
2032         emit groupsChanged();
2033 }
2034
2035 //============================================================================
2036
2037 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
2038 {
2039     Q_ASSERT(!model);
2040     model = m;
2041     group = g;
2042 }
2043
2044 bool QQuickVisualDataGroupPrivate::isChangedConnected()
2045 {
2046     Q_Q(QQuickVisualDataGroup);
2047     IS_SIGNAL_CONNECTED(q, QQuickVisualDataGroup, changed, (const QQmlV8Handle &,const QQmlV8Handle &));
2048 }
2049
2050 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
2051 {
2052     Q_Q(QQuickVisualDataGroup);
2053     if (isChangedConnected() && !changeSet.isEmpty()) {
2054         v8::HandleScope handleScope;
2055         v8::Context::Scope contextScope(engine->context());
2056         v8::Local<v8::Object> removed  = engineData(engine)->array(engine, changeSet.removes());
2057         v8::Local<v8::Object> inserted = engineData(engine)->array(engine, changeSet.inserts());
2058         emit q->changed(QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
2059     }
2060     if (changeSet.difference() != 0)
2061         emit q->countChanged();
2062 }
2063
2064 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
2065 {
2066     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2067         it->emitModelUpdated(changeSet, reset);
2068     changeSet.clear();
2069 }
2070
2071 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
2072 {
2073     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2074         it->createdPackage(index, package);
2075 }
2076
2077 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
2078 {
2079     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2080         it->initPackage(index, package);
2081 }
2082
2083 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
2084 {
2085     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2086         it->destroyingPackage(package);
2087 }
2088
2089 /*!
2090     \qmlclass VisualDataGroup QQuickVisualDataGroup
2091     \inqmlmodule QtQuick 2
2092     \ingroup qtquick-models
2093     \brief Encapsulates a filtered set of visual data items
2094
2095 */
2096
2097 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2098     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2099 {
2100 }
2101
2102 QQuickVisualDataGroup::QQuickVisualDataGroup(
2103         const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2104     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2105 {
2106     Q_D(QQuickVisualDataGroup);
2107     d->name = name;
2108     d->setModel(model, Compositor::Group(index));
2109 }
2110
2111 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2112 {
2113 }
2114
2115 /*!
2116     \qmlproperty string QtQuick2::VisualDataGroup::name
2117
2118     This property holds the name of the group.
2119
2120     Each group in a model must have a unique name starting with a lower case letter.
2121 */
2122
2123 QString QQuickVisualDataGroup::name() const
2124 {
2125     Q_D(const QQuickVisualDataGroup);
2126     return d->name;
2127 }
2128
2129 void QQuickVisualDataGroup::setName(const QString &name)
2130 {
2131     Q_D(QQuickVisualDataGroup);
2132     if (d->model)
2133         return;
2134     if (d->name != name) {
2135         d->name = name;
2136         emit nameChanged();
2137     }
2138 }
2139
2140 /*!
2141     \qmlproperty int QtQuick2::VisualDataGroup::count
2142
2143     This property holds the number of items in the group.
2144 */
2145
2146 int QQuickVisualDataGroup::count() const
2147 {
2148     Q_D(const QQuickVisualDataGroup);
2149     if (!d->model)
2150         return 0;
2151     return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2152 }
2153
2154 /*!
2155     \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2156
2157     This property holds whether new items are assigned to this group by default.
2158 */
2159
2160 bool QQuickVisualDataGroup::defaultInclude() const
2161 {
2162     Q_D(const QQuickVisualDataGroup);
2163     return d->defaultInclude;
2164 }
2165
2166 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2167 {
2168     Q_D(QQuickVisualDataGroup);
2169     if (d->defaultInclude != include) {
2170         d->defaultInclude = include;
2171
2172         if (d->model) {
2173             if (include)
2174                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2175             else
2176                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2177         }
2178         emit defaultIncludeChanged();
2179     }
2180 }
2181
2182 /*!
2183     \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2184
2185     Returns a javascript object describing the item at \a index in the group.
2186
2187     The returned object contains the same information that is available to a delegate from the
2188     VisualDataModel attached as well as the model for that item.  It has the properties:
2189
2190     \list
2191     \li \b model The model data of the item.  This is the same as the model context property in
2192     a delegate
2193     \li \b groups A list the of names of groups the item is a member of.  This property can be
2194     written to change the item's membership.
2195     \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2196     Writing to this property will add or remove the item from the group.
2197     \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2198     \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName.  Writing to
2199     this property will add or remove the item from the group.
2200     \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2201     \endlist
2202 */
2203
2204 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2205 {
2206     Q_D(QQuickVisualDataGroup);
2207     if (!d->model)
2208         return QQmlV8Handle::fromHandle(v8::Undefined());;
2209
2210     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2211     if (index < 0 || index >= model->m_compositor.count(d->group)) {
2212         qmlInfo(this) << tr("get: index out of range");
2213         return QQmlV8Handle::fromHandle(v8::Undefined());
2214     }
2215
2216     Compositor::iterator it = model->m_compositor.find(d->group, index);
2217     QQuickVisualDataModelItem *cacheItem = it->inCache()
2218             ? model->m_cache.at(it.cacheIndex)
2219             : 0;
2220
2221     if (!cacheItem) {
2222         cacheItem = model->m_adaptorModel.createItem(
2223                 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2224         if (!cacheItem)
2225             return QQmlV8Handle::fromHandle(v8::Undefined());
2226         cacheItem->groups = it->flags;
2227
2228         model->m_cache.insert(it.cacheIndex, cacheItem);
2229         model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2230     }
2231
2232     if (model->m_cacheMetaType->constructor.IsEmpty())
2233         model->m_cacheMetaType->initializeConstructor();
2234     v8::Local<v8::Object> handle = model->m_cacheMetaType->constructor->NewInstance();
2235     handle->SetExternalResource(cacheItem);
2236     ++cacheItem->scriptRef;
2237
2238     return QQmlV8Handle::fromHandle(handle);
2239 }
2240
2241 bool QQuickVisualDataGroupPrivate::parseIndex(
2242         const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2243 {
2244     if (value->IsInt32()) {
2245         *index = value->Int32Value();
2246         return true;
2247     } else if (value->IsObject()) {
2248         v8::Local<v8::Object> object = value->ToObject();
2249         QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2250         if (QQuickVisualDataModelPrivate *model = cacheItem && cacheItem->metaType->model
2251                 ? QQuickVisualDataModelPrivate::get(cacheItem->metaType->model)
2252                 : 0) {
2253             *index = model->m_cache.indexOf(cacheItem);
2254             *group = Compositor::Cache;
2255             return true;
2256         }
2257     }
2258     return false;
2259 }
2260
2261 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2262 {
2263     Q_D(QQuickVisualDataGroup);
2264     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2265
2266     int index = model->m_compositor.count(d->group);
2267     Compositor::Group group = d->group;
2268
2269     if (args->Length() == 0)
2270         return;
2271
2272     int  i = 0;
2273     v8::Local<v8::Value> v = (*args)[i];
2274     if (d->parseIndex(v, &index, &group)) {
2275         if (index < 0 || index > model->m_compositor.count(group)) {
2276             qmlInfo(this) << tr("insert: index out of range");
2277             return;
2278         }
2279         if (++i == args->Length())
2280             return;
2281         v = (*args)[i];
2282     }
2283
2284     Compositor::insert_iterator before = index < model->m_compositor.count(group)
2285             ? model->m_compositor.findInsertPosition(group, index)
2286             : model->m_compositor.end();
2287
2288     int groups = 1 << d->group;
2289     if (++i < args->Length())
2290         groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2291
2292     if (v->IsArray()) {
2293         return;
2294     } else if (v->IsObject()) {
2295         model->insert(before, v->ToObject(), groups);
2296         model->emitChanges();
2297     }
2298 }
2299
2300 /*!
2301     \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2302     \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2303     \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2304
2305     Returns a reference to the instantiated item at \a index in the group.
2306
2307     All items returned by create are added to the persistedItems group.  Items in this
2308     group remain instantiated when not referenced by any view.
2309 */
2310
2311 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2312 {
2313     Q_D(QQuickVisualDataGroup);
2314     if (!d->model)
2315         return;
2316
2317     if (args->Length() == 0)
2318         return;
2319
2320     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2321
2322     int index = model->m_compositor.count(d->group);
2323     Compositor::Group group = d->group;
2324
2325     int  i = 0;
2326     v8::Local<v8::Value> v = (*args)[i];
2327     if (d->parseIndex(v, &index, &group))
2328         ++i;
2329
2330     if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2331         v = (*args)[i];
2332         if (v->IsObject()) {
2333             int groups = 1 << d->group;
2334             if (++i < args->Length())
2335                 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2336
2337             Compositor::insert_iterator before = index < model->m_compositor.count(group)
2338                     ? model->m_compositor.findInsertPosition(group, index)
2339                     : model->m_compositor.end();
2340
2341             index = before.index[d->group];
2342             group = d->group;
2343
2344             if (!model->insert(before, v->ToObject(), groups)) {
2345                 return;
2346             }
2347         }
2348     }
2349     if (index < 0 || index >= model->m_compositor.count(group)) {
2350         qmlInfo(this) << tr("create: index out of range");
2351         return;
2352     }
2353
2354     QObject *object = model->object(group, index, false);
2355     if (object) {
2356         QVector<Compositor::Insert> inserts;
2357         Compositor::iterator it = model->m_compositor.find(group, index);
2358         model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2359         model->itemsInserted(inserts);
2360         model->m_cache.at(it.cacheIndex)->releaseObject();
2361     }
2362
2363     args->returnValue(args->engine()->newQObject(object));
2364     model->emitChanges();
2365 }
2366
2367 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2368 {
2369     Q_D(QQuickVisualDataGroup);
2370     if (!d->model)
2371         return;
2372
2373     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2374
2375     if (args->Length() < 2)
2376         return;
2377
2378     int from = -1;
2379     int to = -1;
2380     Compositor::Group fromGroup = d->group;
2381     Compositor::Group toGroup = d->group;
2382
2383     v8::Local<v8::Value> v = (*args)[0];
2384     if (d->parseIndex(v, &from, &fromGroup)) {
2385         if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2386             qmlInfo(this) << tr("resolve: from index out of range");
2387             return;
2388         }
2389     } else {
2390         qmlInfo(this) << tr("resolve: from index invalid");
2391         return;
2392     }
2393
2394     v = (*args)[1];
2395     if (d->parseIndex(v, &to, &toGroup)) {
2396         if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2397             qmlInfo(this) << tr("resolve: to index out of range");
2398             return;
2399         }
2400     } else {
2401         qmlInfo(this) << tr("resolve: to index invalid");
2402         return;
2403     }
2404
2405     Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2406     Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2407
2408     if (!fromIt->isUnresolved()) {
2409         qmlInfo(this) << tr("resolve: from is not an unresolved item");
2410         return;
2411     }
2412     if (!toIt->list) {
2413         qmlInfo(this) << tr("resolve: to is not a model item");
2414         return;
2415     }
2416
2417     const int unresolvedFlags = fromIt->flags;
2418     const int resolvedFlags = toIt->flags;
2419     const int resolvedIndex = toIt.modelIndex();
2420     void * const resolvedList = toIt->list;
2421
2422     QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2423     cacheItem->groups &= ~Compositor::UnresolvedFlag;
2424
2425     if (toIt.cacheIndex > fromIt.cacheIndex)
2426         toIt.decrementIndexes(1, unresolvedFlags);
2427     if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2428         from += 1;
2429
2430     model->itemsMoved(
2431             QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2432             QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2433     model->itemsInserted(
2434             QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2435     toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2436     model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2437
2438     model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2439     model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2440
2441     if (resolvedFlags & Compositor::CacheFlag)
2442         model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2443
2444     Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2445
2446     if (!cacheItem->isReferenced()) {
2447         Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2448         model->m_cache.removeAt(toIt.cacheIndex);
2449         model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2450         delete cacheItem;
2451         Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2452     } else {
2453         cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2454         if (cacheItem->attached)
2455             cacheItem->attached->emitUnresolvedChanged();
2456     }
2457
2458     model->emitChanges();
2459 }
2460
2461 /*!
2462     \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2463
2464     Removes \a count items starting at \a index from the group.
2465 */
2466
2467 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2468 {
2469     Q_D(QQuickVisualDataGroup);
2470     if (!d->model)
2471         return;
2472     Compositor::Group group = d->group;
2473     int index = -1;
2474     int count = 1;
2475
2476     if (args->Length() == 0)
2477         return;
2478
2479     int i = 0;
2480     v8::Local<v8::Value> v = (*args)[i];
2481     if (!d->parseIndex(v, &index, &group)) {
2482         qmlInfo(this) << tr("remove: invalid index");
2483         return;
2484     }
2485
2486     if (++i < args->Length()) {
2487         v = (*args)[i];
2488         if (v->IsInt32())
2489             count = v->Int32Value();
2490     }
2491
2492     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2493     if (index < 0 || index >= model->m_compositor.count(group)) {
2494         qmlInfo(this) << tr("remove: index out of range");
2495     } else if (count != 0) {
2496         Compositor::iterator it = model->m_compositor.find(group, index);
2497         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2498             qmlInfo(this) << tr("remove: invalid count");
2499         } else {
2500             model->removeGroups(it, count, d->group, 1 << d->group);
2501         }
2502     }
2503 }
2504
2505 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2506         QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2507 {
2508     if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2509         return false;
2510
2511     if (args->Length() < 2)
2512         return false;
2513
2514     int i = 0;
2515     v8::Local<v8::Value> v = (*args)[i];
2516     if (!parseIndex(v, index, group))
2517         return false;
2518
2519     v = (*args)[++i];
2520     if (v->IsInt32()) {
2521         *count = v->Int32Value();
2522
2523         if (++i == args->Length())
2524             return false;
2525         v = (*args)[i];
2526     }
2527
2528     *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2529
2530     return true;
2531 }
2532
2533 /*!
2534     \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2535
2536     Adds \a count items starting at \a index to \a groups.
2537 */
2538
2539 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2540 {
2541     Q_D(QQuickVisualDataGroup);
2542     Compositor::Group group = d->group;
2543     int index = -1;
2544     int count = 1;
2545     int groups = 0;
2546
2547     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2548         return;
2549
2550     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2551     if (index < 0 || index >= model->m_compositor.count(group)) {
2552         qmlInfo(this) << tr("addGroups: index out of range");
2553     } else if (count != 0) {
2554         Compositor::iterator it = model->m_compositor.find(group, index);
2555         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2556             qmlInfo(this) << tr("addGroups: invalid count");
2557         } else {
2558             model->addGroups(it, count, d->group, groups);
2559         }
2560     }
2561 }
2562
2563 /*!
2564     \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2565
2566     Removes \a count items starting at \a index from \a groups.
2567 */
2568
2569 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2570 {
2571     Q_D(QQuickVisualDataGroup);
2572     Compositor::Group group = d->group;
2573     int index = -1;
2574     int count = 1;
2575     int groups = 0;
2576
2577     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2578         return;
2579
2580     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2581     if (index < 0 || index >= model->m_compositor.count(group)) {
2582         qmlInfo(this) << tr("removeGroups: index out of range");
2583     } else if (count != 0) {
2584         Compositor::iterator it = model->m_compositor.find(group, index);
2585         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2586             qmlInfo(this) << tr("removeGroups: invalid count");
2587         } else {
2588             model->removeGroups(it, count, d->group, groups);
2589         }
2590     }
2591 }
2592
2593 /*!
2594     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2595
2596     Sets the \a groups \a count items starting at \a index belong to.
2597 */
2598
2599 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2600 {
2601     Q_D(QQuickVisualDataGroup);
2602     Compositor::Group group = d->group;
2603     int index = -1;
2604     int count = 1;
2605     int groups = 0;
2606
2607     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2608         return;
2609
2610     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2611     if (index < 0 || index >= model->m_compositor.count(group)) {
2612         qmlInfo(this) << tr("setGroups: index out of range");
2613     } else if (count != 0) {
2614         Compositor::iterator it = model->m_compositor.find(group, index);
2615         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2616             qmlInfo(this) << tr("setGroups: invalid count");
2617         } else {
2618             model->setGroups(it, count, d->group, groups);
2619         }
2620     }
2621 }
2622
2623 /*!
2624     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2625
2626     Sets the \a groups \a count items starting at \a index belong to.
2627 */
2628
2629 /*!
2630     \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2631
2632     Moves \a count at \a from in a group \a to a new position.
2633 */
2634
2635 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2636 {
2637     Q_D(QQuickVisualDataGroup);
2638
2639     if (args->Length() < 2)
2640         return;
2641
2642     Compositor::Group fromGroup = d->group;
2643     Compositor::Group toGroup = d->group;
2644     int from = -1;
2645     int to = -1;
2646     int count = 1;
2647
2648     if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2649         qmlInfo(this) << tr("move: invalid from index");
2650         return;
2651     }
2652
2653     if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2654         qmlInfo(this) << tr("move: invalid to index");
2655         return;
2656     }
2657
2658     if (args->Length() > 2) {
2659         v8::Local<v8::Value> v = (*args)[2];
2660         if (v->IsInt32())
2661             count = v->Int32Value();
2662     }
2663
2664     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2665
2666     if (count < 0) {
2667         qmlInfo(this) << tr("move: invalid count");
2668     } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2669         qmlInfo(this) << tr("move: from index out of range");
2670     } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2671         qmlInfo(this) << tr("move: to index out of range");
2672     } else if (count > 0) {
2673         QVector<Compositor::Remove> removes;
2674         QVector<Compositor::Insert> inserts;
2675
2676         model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2677         model->itemsMoved(removes, inserts);
2678         model->emitChanges();
2679     }
2680
2681 }
2682
2683 /*!
2684     \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2685
2686     This handler is called when items have been removed from or inserted into the group.
2687
2688     Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2689     item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2690
2691     Each index is adjusted for previous changes with all removed items preceding any inserted
2692     items.
2693 */
2694
2695 //============================================================================
2696
2697 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2698     : QQuickVisualModel(*new QObjectPrivate, parent)
2699     , m_model(model)
2700     , m_part(part)
2701     , m_compositorGroup(Compositor::Cache)
2702     , m_inheritGroup(true)
2703 {
2704     QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2705     if (d->m_cacheMetaType) {
2706         QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2707         m_compositorGroup = Compositor::Default;
2708     } else {
2709         d->m_pendingParts.insert(this);
2710     }
2711 }
2712
2713 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2714 {
2715 }
2716
2717 QString QQuickVisualPartsModel::filterGroup() const
2718 {
2719     if (m_inheritGroup)
2720         return m_model->filterGroup();
2721     return m_filterGroup;
2722 }
2723
2724 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2725 {
2726     if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2727         qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2728         return;
2729     }
2730
2731     if (m_filterGroup != group || m_inheritGroup) {
2732         m_filterGroup = group;
2733         m_inheritGroup = false;
2734         updateFilterGroup();
2735
2736         emit filterGroupChanged();
2737     }
2738 }
2739
2740 void QQuickVisualPartsModel::resetFilterGroup()
2741 {
2742     if (!m_inheritGroup) {
2743         m_inheritGroup = true;
2744         updateFilterGroup();
2745         emit filterGroupChanged();
2746     }
2747 }
2748
2749 void QQuickVisualPartsModel::updateFilterGroup()
2750 {
2751     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2752     if (!model->m_cacheMetaType)
2753         return;
2754
2755     if (m_inheritGroup) {
2756         if (m_filterGroup == model->m_filterGroup)
2757             return;
2758         m_filterGroup = model->m_filterGroup;
2759     }
2760
2761     QQuickListCompositor::Group previousGroup = m_compositorGroup;
2762     m_compositorGroup = Compositor::Default;
2763     QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2764     for (int i = 1; i < model->m_groupCount; ++i) {
2765         if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2766             m_compositorGroup = Compositor::Group(i);
2767             break;
2768         }
2769     }
2770
2771     QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2772     if (m_compositorGroup != previousGroup) {
2773         QVector<QQuickChangeSet::Remove> removes;
2774         QVector<QQuickChangeSet::Insert> inserts;
2775         model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2776
2777         QQuickChangeSet changeSet;
2778         changeSet.apply(removes, inserts);
2779         if (!changeSet.isEmpty())
2780             emit modelUpdated(changeSet, false);
2781
2782         if (changeSet.difference() != 0)
2783             emit countChanged();
2784     }
2785 }
2786
2787 void QQuickVisualPartsModel::updateFilterGroup(
2788         Compositor::Group group, const QQuickChangeSet &changeSet)
2789 {
2790     if (!m_inheritGroup)
2791         return;
2792
2793     m_compositorGroup = group;
2794     QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2795
2796     if (!changeSet.isEmpty())
2797         emit modelUpdated(changeSet, false);
2798
2799     if (changeSet.difference() != 0)
2800         emit countChanged();
2801
2802     emit filterGroupChanged();
2803 }
2804
2805 int QQuickVisualPartsModel::count() const
2806 {
2807     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2808     return model->m_delegate
2809             ? model->m_compositor.count(m_compositorGroup)
2810             : 0;
2811 }
2812
2813 bool QQuickVisualPartsModel::isValid() const
2814 {
2815     return m_model->isValid();
2816 }
2817
2818 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2819 {
2820     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2821
2822     if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2823         qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2824         return 0;
2825     }
2826
2827     QObject *object = model->object(m_compositorGroup, index, asynchronous);
2828
2829     if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
2830         QObject *part = package->part(m_part);
2831         if (!part)
2832             return 0;
2833         if (QQuickItem *item = qmlobject_cast<QQuickItem *>(part)) {
2834             m_packaged.insertMulti(item, package);
2835             return item;
2836         }
2837     }
2838
2839     model->release(object);
2840     if (!model->m_delegateValidated) {
2841         if (object)
2842             qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2843         model->m_delegateValidated = true;
2844     }
2845
2846     return 0;
2847 }
2848
2849 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2850 {
2851     QQuickVisualModel::ReleaseFlags flags = 0;
2852
2853     QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2854     if (it != m_packaged.end()) {
2855         QQuickPackage *package = *it;
2856         QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2857         flags = model->release(package);
2858         m_packaged.erase(it);
2859         if (!m_packaged.contains(item))
2860             flags &= ~Referenced;
2861         if (flags & Destroyed)
2862             QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2863     }
2864     return flags;
2865 }
2866
2867 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2868 {
2869     return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2870 }
2871
2872 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2873 {
2874     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2875     model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2876     m_watchedRoles = roles;
2877 }
2878
2879 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2880 {
2881     QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2882     if (it != m_packaged.end()) {
2883         if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2884             return cacheItem->groupIndex(m_compositorGroup);
2885     }
2886     return -1;
2887 }
2888
2889 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2890 {
2891     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2892         emit createdItem(index, item);
2893 }
2894
2895 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2896 {
2897     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2898         emit initItem(index, item);
2899 }
2900
2901 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2902 {
2903     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part))) {
2904         Q_ASSERT(!m_packaged.contains(item));
2905         emit destroyingItem(item);
2906         item->setParentItem(0);
2907     }
2908 }
2909
2910 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2911 {
2912     emit modelUpdated(changeSet, reset);
2913     if (changeSet.difference() != 0)
2914         emit countChanged();
2915 }
2916
2917 //============================================================================
2918
2919 v8::Handle<v8::Value> get_change_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
2920 {
2921     return info.This()->GetInternalField(0);
2922 }
2923
2924 v8::Handle<v8::Value> get_change_count(v8::Local<v8::String>, const v8::AccessorInfo &info)
2925 {
2926     return info.This()->GetInternalField(1);
2927 }
2928
2929 v8::Handle<v8::Value> get_change_moveId(v8::Local<v8::String>, const v8::AccessorInfo &info)
2930 {
2931     return info.This()->GetInternalField(2);
2932 }
2933
2934 class QQuickVisualDataGroupChangeArray : public QV8ObjectResource
2935 {
2936     V8_RESOURCE_TYPE(ChangeSetArrayType)
2937 public:
2938     QQuickVisualDataGroupChangeArray(QV8Engine *engine)
2939         : QV8ObjectResource(engine)
2940     {
2941     }
2942
2943     virtual quint32 count() const = 0;
2944     virtual const QQuickChangeSet::Change &at(int index) const = 0;
2945
2946     static v8::Handle<v8::Value> get_change(quint32 index, const v8::AccessorInfo &info)
2947     {
2948         QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2949         V8ASSERT_TYPE(array, "Not a valid change array");
2950
2951         if (index >= array->count())
2952             return v8::Undefined();
2953
2954         const QQuickChangeSet::Change &change = array->at(index);
2955
2956         v8::Local<v8::Object> object = engineData(array->engine)->constructorChange->NewInstance();
2957         object->SetInternalField(0, v8::Int32::New(change.index));
2958         object->SetInternalField(1, v8::Int32::New(change.count));
2959         if (change.isMove())
2960             object->SetInternalField(2, v8::Int32::New(change.moveId));
2961
2962         return object;
2963     }
2964
2965     static v8::Handle<v8::Value> get_length(v8::Local<v8::String>, const v8::AccessorInfo &info)
2966     {
2967         QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2968         V8ASSERT_TYPE(array, "Not a valid change array");
2969
2970         return v8::Integer::New(array->count());
2971     }
2972
2973     static v8::Local<v8::Function> constructor()
2974     {
2975         v8::Local<v8::FunctionTemplate> changeArray = v8::FunctionTemplate::New();
2976         changeArray->InstanceTemplate()->SetHasExternalResource(true);
2977         changeArray->InstanceTemplate()->SetIndexedPropertyHandler(get_change);
2978         changeArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), get_length);
2979         return changeArray->GetFunction();
2980     }
2981 };
2982
2983 class QQuickVisualDataGroupRemoveArray : public QQuickVisualDataGroupChangeArray
2984 {
2985 public:
2986     QQuickVisualDataGroupRemoveArray(QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
2987         : QQuickVisualDataGroupChangeArray(engine)
2988         , changes(changes)
2989     {
2990     }
2991
2992     quint32 count() const { return changes.count(); }
2993     const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
2994
2995 private:
2996     QVector<QQuickChangeSet::Remove> changes;
2997 };
2998
2999 class QQuickVisualDataGroupInsertArray : public QQuickVisualDataGroupChangeArray
3000 {
3001 public:
3002     QQuickVisualDataGroupInsertArray(QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3003         : QQuickVisualDataGroupChangeArray(engine)
3004         , changes(changes)
3005     {
3006     }
3007
3008     quint32 count() const { return changes.count(); }
3009     const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3010
3011 private:
3012     QVector<QQuickChangeSet::Insert> changes;
3013 };
3014
3015 QQuickVisualDataModelEngineData::QQuickVisualDataModelEngineData(QV8Engine *)
3016 {
3017     strings = qPersistentNew(v8::Array::New(StringCount));
3018     strings->Set(Model, v8::String::New("model"));
3019     strings->Set(Groups, v8::String::New("groups"));
3020     strings->Set(IsUnresolved, v8::String::New("isUnresolved"));
3021     strings->Set(ItemsIndex, v8::String::New("itemsIndex"));
3022     strings->Set(PersistedItemsIndex, v8::String::New("persistedItemsIndex"));
3023     strings->Set(InItems, v8::String::New("inItems"));
3024     strings->Set(InPersistedItems, v8::String::New("inPersistedItems"));
3025
3026     v8::Local<v8::FunctionTemplate> change = v8::FunctionTemplate::New();
3027     change->InstanceTemplate()->SetAccessor(v8::String::New("index"), get_change_index);
3028     change->InstanceTemplate()->SetAccessor(v8::String::New("count"), get_change_count);
3029     change->InstanceTemplate()->SetAccessor(v8::String::New("moveId"), get_change_moveId);
3030     change->InstanceTemplate()->SetInternalFieldCount(3);
3031     constructorChange = qPersistentNew(change->GetFunction());
3032     constructorChangeArray = qPersistentNew(QQuickVisualDataGroupChangeArray::constructor());
3033 }
3034
3035 QQuickVisualDataModelEngineData::~QQuickVisualDataModelEngineData()
3036 {
3037     qPersistentDispose(strings);
3038     qPersistentDispose(constructorChange);
3039     qPersistentDispose(constructorChangeArray);
3040 }
3041
3042 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3043         QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3044 {
3045     v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3046     array->SetExternalResource(new QQuickVisualDataGroupRemoveArray(engine, changes));
3047     return array;
3048 }
3049
3050 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3051         QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3052 {
3053     v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3054     array->SetExternalResource(new QQuickVisualDataGroupInsertArray(engine, changes));
3055     return array;
3056 }
3057
3058 QT_END_NAMESPACE
3059