Use the convential form for the selectedText notify signal name.
[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     A VisualDataModel 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 VisualDataModel elements.
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 element.
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         return model->stringValue(it.modelIndex(), name);
959     }
960     return QString();
961 }
962
963 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
964 {
965     Q_D(QQuickVisualDataModel);
966     return d->stringValue(d->m_compositorGroup, index, name);
967 }
968
969 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
970 {
971     Q_D(const QQuickVisualDataModel);
972     if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
973         return cacheItem->groupIndex(d->m_compositorGroup);
974     return -1;
975 }
976
977 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
978 {
979     Q_D(QQuickVisualDataModel);
980     d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
981     d->m_watchedRoles = roles;
982 }
983
984 void QQuickVisualDataModelPrivate::addGroups(
985         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
986 {
987     QVector<Compositor::Insert> inserts;
988     m_compositor.setFlags(from, count, group, groupFlags, &inserts);
989     itemsInserted(inserts);
990     emitChanges();
991 }
992
993 void QQuickVisualDataModelPrivate::removeGroups(
994         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
995 {
996     QVector<Compositor::Remove> removes;
997     m_compositor.clearFlags(from, count, group, groupFlags, &removes);
998     itemsRemoved(removes);
999     emitChanges();
1000 }
1001
1002 void QQuickVisualDataModelPrivate::setGroups(
1003         Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1004 {
1005     QVector<Compositor::Remove> removes;
1006     QVector<Compositor::Insert> inserts;
1007
1008     m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1009     itemsInserted(inserts);
1010     const int removeFlags = ~groupFlags & Compositor::GroupMask;
1011
1012     from = m_compositor.find(from.group, from.index[from.group]);
1013     m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1014     itemsRemoved(removes);
1015     emitChanges();
1016 }
1017
1018 bool QQuickVisualDataModel::event(QEvent *e)
1019 {
1020     Q_D(QQuickVisualDataModel);
1021     if (e->type() == QEvent::UpdateRequest) {
1022         d->m_adaptorModel.fetchMore();
1023     } else if (e->type() == QEvent::User) {
1024         d->m_incubatorCleanupScheduled = false;
1025         qDeleteAll(d->m_finishedIncubating);
1026         d->m_finishedIncubating.clear();
1027     }
1028     return QQuickVisualModel::event(e);
1029 }
1030
1031 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1032 {
1033     if (!m_delegate)
1034         return;
1035
1036     QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1037
1038     foreach (const Compositor::Change &change, changes) {
1039         for (int i = 1; i < m_groupCount; ++i) {
1040             if (change.inGroup(i)) {
1041                 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
1042             }
1043         }
1044     }
1045
1046     for (int i = 1; i < m_groupCount; ++i)
1047         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1048 }
1049
1050 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QList<int> &roles)
1051 {
1052     Q_D(QQuickVisualDataModel);
1053     if (count <= 0 || !d->m_complete)
1054         return;
1055
1056     if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1057         QVector<Compositor::Change> changes;
1058         d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1059         d->itemsChanged(changes);
1060         d->emitChanges();
1061     }
1062 }
1063
1064 static void incrementIndexes(QQuickVisualDataModelItem *cacheItem, int count, const int *deltas)
1065 {
1066     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1067         for (int i = 1; i < count; ++i)
1068             incubationTask->index[i] += deltas[i];
1069     }
1070     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1071         for (int i = 1; i < count; ++i)
1072             attached->m_currentIndex[i] += deltas[i];
1073     }
1074 }
1075
1076 void QQuickVisualDataModelPrivate::itemsInserted(
1077         const QVector<Compositor::Insert> &inserts,
1078         QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1079         QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1080 {
1081     int cacheIndex = 0;
1082
1083     int inserted[Compositor::MaximumGroupCount];
1084     for (int i = 1; i < m_groupCount; ++i)
1085         inserted[i] = 0;
1086
1087     foreach (const Compositor::Insert &insert, inserts) {
1088         for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
1089             incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1090
1091         for (int i = 1; i < m_groupCount; ++i) {
1092             if (insert.inGroup(i)) {
1093                 (*translatedInserts)[i].append(
1094                         QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1095                 inserted[i] += insert.count;
1096             }
1097         }
1098
1099         if (!insert.inCache())
1100             continue;
1101
1102         if (movedItems && insert.isMove()) {
1103             QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1104             Q_ASSERT(items.count() == insert.count);
1105             m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1106         }
1107         if (insert.inGroup()) {
1108             for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1109                 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1110                 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1111
1112                 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1113                     for (int i = 1; i < m_groupCount; ++i)
1114                         incubationTask->index[i] = cacheItem->groups & (1 << i)
1115                                 ? insert.index[i] + offset
1116                                 : insert.index[i];
1117                 }
1118                 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1119                     for (int i = 1; i < m_groupCount; ++i)
1120                         attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1121                                 ? insert.index[i] + offset
1122                                 : insert.index[i];
1123                 }
1124             }
1125         } else {
1126             cacheIndex = insert.cacheIndex + insert.count;
1127         }
1128     }
1129     for (; cacheIndex < m_cache.count(); ++cacheIndex)
1130         incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1131 }
1132
1133 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1134 {
1135     QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1136     itemsInserted(inserts, &translatedInserts);
1137     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1138     if (!m_delegate)
1139         return;
1140
1141     for (int i = 1; i < m_groupCount; ++i)
1142         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1143 }
1144
1145 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1146 {
1147
1148     Q_D(QQuickVisualDataModel);
1149     if (count <= 0 || !d->m_complete)
1150         return;
1151
1152     d->m_count += count;
1153
1154     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1155         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1156         if (item->modelIndex() >= index)
1157             item->setModelIndex(item->modelIndex() + count);
1158     }
1159
1160     QVector<Compositor::Insert> inserts;
1161     d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1162     d->itemsInserted(inserts);
1163     d->emitChanges();
1164 }
1165
1166 void QQuickVisualDataModelPrivate::itemsRemoved(
1167         const QVector<Compositor::Remove> &removes,
1168         QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1169         QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1170 {
1171     int cacheIndex = 0;
1172     int removedCache = 0;
1173
1174     int removed[Compositor::MaximumGroupCount];
1175     for (int i = 1; i < m_groupCount; ++i)
1176         removed[i] = 0;
1177
1178     foreach (const Compositor::Remove &remove, removes) {
1179         for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
1180             incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1181
1182         for (int i = 1; i < m_groupCount; ++i) {
1183             if (remove.inGroup(i)) {
1184                 (*translatedRemoves)[i].append(
1185                         QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1186                 removed[i] -= remove.count;
1187             }
1188         }
1189
1190         if (!remove.inCache())
1191             continue;
1192
1193         if (movedItems && remove.isMove()) {
1194             movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1195             QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1196             QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1197             m_cache.erase(begin, end);
1198         } else {
1199             for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1200                 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1201                 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1202                     QObject *object = cacheItem->object;
1203                     cacheItem->destroyObject();
1204                     if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1205                         emitDestroyingPackage(package);
1206                     else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
1207                         emitDestroyingItem(item);
1208                     cacheItem->scriptRef -= 1;
1209                 }
1210                 if (!cacheItem->isReferenced()) {
1211                     m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1212                     m_cache.removeAt(cacheIndex);
1213                     delete cacheItem;
1214                     --cacheIndex;
1215                     ++removedCache;
1216                     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1217                 } else if (remove.groups() == cacheItem->groups) {
1218                     cacheItem->groups = 0;
1219                     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1220                         for (int i = 1; i < m_groupCount; ++i)
1221                             incubationTask->index[i] = -1;
1222                     }
1223                     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1224                         for (int i = 1; i < m_groupCount; ++i)
1225                             attached->m_currentIndex[i] = -1;
1226                     }
1227                 } else {
1228                     if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1229                         for (int i = 1; i < m_groupCount; ++i) {
1230                             if (remove.inGroup(i))
1231                                 incubationTask->index[i] = remove.index[i];
1232                         }
1233                     }
1234                     if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1235                         for (int i = 1; i < m_groupCount; ++i) {
1236                             if (remove.inGroup(i))
1237                                 attached->m_currentIndex[i] = remove.index[i];
1238                         }
1239                     }
1240                     cacheItem->groups &= ~remove.flags;
1241                 }
1242             }
1243         }
1244     }
1245
1246     for (; cacheIndex < m_cache.count(); ++cacheIndex)
1247         incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1248 }
1249
1250 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1251 {
1252     QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1253     itemsRemoved(removes, &translatedRemoves);
1254     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1255     if (!m_delegate)
1256         return;
1257
1258     for (int i = 1; i < m_groupCount; ++i)
1259        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1260 }
1261
1262 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1263 {
1264     Q_D(QQuickVisualDataModel);
1265     if (count <= 0|| !d->m_complete)
1266         return;
1267
1268     d->m_count -= count;
1269
1270     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1271         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1272         if (item->modelIndex() >= index + count)
1273             item->setModelIndex(item->modelIndex() - count);
1274         else  if (item->modelIndex() >= index)
1275             item->setModelIndex(-1);
1276     }
1277
1278     QVector<Compositor::Remove> removes;
1279     d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1280     d->itemsRemoved(removes);
1281
1282     d->emitChanges();
1283 }
1284
1285 void QQuickVisualDataModelPrivate::itemsMoved(
1286         const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1287 {
1288     QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1289
1290     QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1291     itemsRemoved(removes, &translatedRemoves, &movedItems);
1292
1293     QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1294     itemsInserted(inserts, &translatedInserts, &movedItems);
1295     Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1296     Q_ASSERT(movedItems.isEmpty());
1297     if (!m_delegate)
1298         return;
1299
1300     for (int i = 1; i < m_groupCount; ++i) {
1301         QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1302                     translatedRemoves.at(i),
1303                     translatedInserts.at(i));
1304     }
1305 }
1306
1307 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1308 {
1309     Q_D(QQuickVisualDataModel);
1310     if (count <= 0 || !d->m_complete)
1311         return;
1312
1313     const int minimum = qMin(from, to);
1314     const int maximum = qMax(from, to) + count;
1315     const int difference = from > to ? count : -count;
1316
1317     for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1318         QQuickVisualDataModelItem *item = d->m_cache.at(i);
1319         if (item->modelIndex() >= from && item->modelIndex() < from + count)
1320             item->setModelIndex(item->modelIndex() - from + to);
1321         else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1322             item->setModelIndex(item->modelIndex() + difference);
1323     }
1324
1325     QVector<Compositor::Remove> removes;
1326     QVector<Compositor::Insert> inserts;
1327     d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1328     d->itemsMoved(removes, inserts);
1329     d->emitChanges();
1330 }
1331
1332 template <typename T> v8::Local<v8::Array>
1333 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1334 {
1335     v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1336     v8::Local<v8::String> indexKey = v8::String::New("index");
1337     v8::Local<v8::String> countKey = v8::String::New("count");
1338     v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1339
1340     for (int i = 0; i < changes.count(); ++i) {
1341         v8::Local<v8::Object> object = v8::Object::New();
1342         object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1343         object->Set(countKey, v8::Integer::New(changes.at(i).count));
1344         object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1345         indexes->Set(i, object);
1346     }
1347     return indexes;
1348 }
1349
1350 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1351 {
1352     Q_Q(QQuickVisualDataModel);
1353     emit q->modelUpdated(changeSet, reset);
1354     if (changeSet.difference() != 0)
1355         emit q->countChanged();
1356 }
1357
1358 void QQuickVisualDataModelPrivate::emitChanges()
1359 {
1360     if (m_transaction || !m_complete)
1361         return;
1362
1363     m_transaction = true;
1364     QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1365     for (int i = 1; i < m_groupCount; ++i)
1366         QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1367     m_transaction = false;
1368
1369     const bool reset = m_reset;
1370     m_reset = false;
1371     for (int i = 1; i < m_groupCount; ++i)
1372         QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1373
1374     foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1375         if (cacheItem->attached)
1376             cacheItem->attached->emitChanges();
1377     }
1378 }
1379
1380 void QQuickVisualDataModel::_q_modelReset()
1381 {
1382     Q_D(QQuickVisualDataModel);
1383     if (!d->m_delegate)
1384         return;
1385
1386     int oldCount = d->m_count;
1387     d->m_adaptorModel.rootIndex = QModelIndex();
1388
1389     if (d->m_complete) {
1390         d->m_count = d->m_adaptorModel.count();
1391
1392         for (int i = 0, c = d->m_cache.count();  i < c; ++i) {
1393             QQuickVisualDataModelItem *item = d->m_cache.at(i);
1394             if (item->modelIndex() != -1)
1395                 item->setModelIndex(-1);
1396         }
1397
1398         QVector<Compositor::Remove> removes;
1399         QVector<Compositor::Insert> inserts;
1400         if (oldCount)
1401             d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1402         if (d->m_count)
1403             d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1404         d->itemsMoved(removes, inserts);
1405         d->m_reset = true;
1406
1407         if (d->m_adaptorModel.canFetchMore())
1408             d->m_adaptorModel.fetchMore();
1409
1410         d->emitChanges();
1411     }
1412     emit rootIndexChanged();
1413 }
1414
1415 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1416 {
1417     Q_D(QQuickVisualDataModel);
1418     if (parent == d->m_adaptorModel.rootIndex)
1419         _q_itemsInserted(begin, end - begin + 1);
1420 }
1421
1422 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1423 {
1424     Q_D(QQuickVisualDataModel);
1425     if (parent == d->m_adaptorModel.rootIndex)
1426         _q_itemsRemoved(begin, end - begin + 1);
1427 }
1428
1429 void QQuickVisualDataModel::_q_rowsMoved(
1430         const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1431         const QModelIndex &destinationParent, int destinationRow)
1432 {
1433    Q_D(QQuickVisualDataModel);
1434     const int count = sourceEnd - sourceStart + 1;
1435     if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1436         _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1437     } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1438         _q_itemsRemoved(sourceStart, count);
1439     } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1440         _q_itemsInserted(destinationRow, count);
1441     }
1442 }
1443
1444 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1445 {
1446     Q_D(QQuickVisualDataModel);
1447     if (begin.parent() == d->m_adaptorModel.rootIndex)
1448         _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, QList<int>());
1449 }
1450
1451 void QQuickVisualDataModel::_q_layoutChanged()
1452 {
1453     Q_D(QQuickVisualDataModel);
1454     _q_itemsChanged(0, d->m_count, QList<int>());
1455 }
1456
1457 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1458 {
1459     if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1460         if (cacheItem->object == obj) { // Don't create attached item for child objects.
1461             cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1462             return cacheItem->attached;
1463         }
1464     }
1465     return new QQuickVisualDataModelAttached(obj);
1466 }
1467
1468 bool QQuickVisualDataModelPrivate::insert(
1469         Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1470 {
1471     QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1472     if (!cacheItem)
1473         return false;
1474
1475     v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1476     for (uint i = 0; i < propertyNames->Length(); ++i) {
1477         v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1478         cacheItem->setValue(
1479                 m_cacheMetaType->v8Engine->toString(propertyName),
1480                 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1481     }
1482
1483     cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1484
1485     // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1486     itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1487
1488     before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1489     m_cache.insert(before.cacheIndex, cacheItem);
1490
1491     return true;
1492 }
1493
1494 //============================================================================
1495
1496 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1497         QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1498     : model(model)
1499     , groupCount(groupNames.count() + 1)
1500     , v8Engine(engine)
1501     , metaObject(0)
1502     , groupNames(groupNames)
1503 {
1504 }
1505
1506 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1507 {
1508     if (metaObject)
1509         metaObject->release();
1510     qPersistentDispose(constructor);
1511 }
1512
1513 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1514 {
1515     QMetaObjectBuilder builder;
1516     builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1517     builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1518     builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1519
1520     int notifierId = 0;
1521     for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1522         QString propertyName = QStringLiteral("in") + groupNames.at(i);
1523         propertyName.replace(2, 1, propertyName.at(2).toUpper());
1524         builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1525         QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1526                 propertyName.toUtf8(), "bool", notifierId);
1527         propertyBuilder.setWritable(true);
1528     }
1529     for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1530         const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1531         builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1532         QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1533                 propertyName.toUtf8(), "int", notifierId);
1534         propertyBuilder.setWritable(true);
1535     }
1536
1537     metaObject = new QQuickVisualDataModelAttachedMetaObject(this, builder.toMetaObject());
1538 }
1539
1540 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1541 {
1542     v8::HandleScope handleScope;
1543     v8::Context::Scope contextScope(v8Engine->context());
1544
1545     QQuickVisualDataModelEngineData *data = engineData(v8Engine);
1546
1547     constructor = qPersistentNew(v8::ObjectTemplate::New());
1548
1549     constructor->SetHasExternalResource(true);
1550     constructor->SetAccessor(data->model(), get_model);
1551     constructor->SetAccessor(data->groups(), get_groups, set_groups);
1552     constructor->SetAccessor(data->isUnresolved(), get_member, 0, v8::Int32::New(30));
1553     constructor->SetAccessor(data->inItems(), get_member, set_member, v8::Int32::New(1));
1554     constructor->SetAccessor(data->inPersistedItems(), get_member, set_member, v8::Int32::New(2));
1555     constructor->SetAccessor(data->itemsIndex(), get_index, 0, v8::Int32::New(1));
1556     constructor->SetAccessor(data->persistedItemsIndex(), get_index, 0, v8::Int32::New(2));
1557
1558     for (int i = 2; i < groupNames.count(); ++i) {
1559         QString propertyName = QStringLiteral("in") + groupNames.at(i);
1560         propertyName.replace(2, 1, propertyName.at(2).toUpper());
1561         constructor->SetAccessor(
1562                 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1563     }
1564     for (int i = 2; i < groupNames.count(); ++i) {
1565         const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1566         constructor->SetAccessor(
1567                 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1568     }
1569 }
1570
1571 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1572 {
1573     int groupFlags = 0;
1574     foreach (const QString &groupName, groups) {
1575         int index = groupNames.indexOf(groupName);
1576         if (index != -1)
1577             groupFlags |= 2 << index;
1578     }
1579     return groupFlags;
1580 }
1581
1582 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1583 {
1584     int groupFlags = 0;
1585     if (groups->IsString()) {
1586         const QString groupName = v8Engine->toString(groups);
1587         int index = groupNames.indexOf(groupName);
1588         if (index != -1)
1589             groupFlags |= 2 << index;
1590     } else if (groups->IsArray()) {
1591         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1592         for (uint i = 0; i < array->Length(); ++i) {
1593             const QString groupName = v8Engine->toString(array->Get(i));
1594             int index = groupNames.indexOf(groupName);
1595             if (index != -1)
1596                 groupFlags |= 2 << index;
1597         }
1598     }
1599     return groupFlags;
1600 }
1601
1602 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1603 {
1604     static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1605     qPersistentDispose(object);
1606 }
1607
1608 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1609 {
1610     static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1611     qPersistentDispose(object);
1612 }
1613
1614 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1615         v8::Local<v8::String>, const v8::AccessorInfo &info)
1616 {
1617     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1618     if (!cacheItem)
1619         V8THROW_ERROR("Not a valid VisualData object");
1620     if (!cacheItem->metaType->model)
1621         return v8::Undefined();
1622
1623     if (cacheItem->modelHandle.IsEmpty()) {
1624         cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1625         cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1626
1627         ++cacheItem->scriptRef;
1628     }
1629
1630     return cacheItem->modelHandle;
1631 }
1632
1633 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1634         v8::Local<v8::String>, const v8::AccessorInfo &info)
1635 {
1636     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1637     if (!cacheItem)
1638         V8THROW_ERROR("Not a valid VisualData object");
1639
1640     QStringList groups;
1641     for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1642         if (cacheItem->groups & (1 << i))
1643             groups.append(cacheItem->metaType->groupNames.at(i - 1));
1644     }
1645
1646     return cacheItem->engine->fromVariant(groups);
1647 }
1648
1649 void QQuickVisualDataModelItemMetaType::set_groups(
1650         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1651 {
1652     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1653     if (!cacheItem)
1654         V8THROW_ERROR_SETTER("Not a valid VisualData object");
1655
1656     if (!cacheItem->metaType->model)
1657         return;
1658     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1659
1660     const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1661     const int cacheIndex = model->m_cache.indexOf(cacheItem);
1662     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1663     model->setGroups(it, 1, Compositor::Cache, groupFlags);
1664 }
1665
1666 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1667         v8::Local<v8::String>, const v8::AccessorInfo &info)
1668 {
1669     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1670     if (!cacheItem)
1671         V8THROW_ERROR("Not a valid VisualData object");
1672
1673     return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1674 }
1675
1676 void QQuickVisualDataModelItemMetaType::set_member(
1677         v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1678 {
1679     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1680     if (!cacheItem)
1681         V8THROW_ERROR_SETTER("Not a valid VisualData object");
1682
1683     if (!cacheItem->metaType->model)
1684         return;
1685     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1686
1687     Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1688     const bool member = value->BooleanValue();
1689     const int groupFlag = (1 << group);
1690     if (member == ((cacheItem->groups & groupFlag) != 0))
1691         return;
1692
1693     const int cacheIndex = model->m_cache.indexOf(cacheItem);
1694     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1695     if (member)
1696         model->addGroups(it, 1, Compositor::Cache, groupFlag);
1697     else
1698         model->removeGroups(it, 1, Compositor::Cache, groupFlag);
1699 }
1700
1701 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1702         v8::Local<v8::String>, const v8::AccessorInfo &info)
1703 {
1704     QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1705     if (!cacheItem)
1706         V8THROW_ERROR("Not a valid VisualData object");
1707
1708     return v8::Integer::New(cacheItem->groupIndex(Compositor::Group(info.Data()->Int32Value())));
1709 }
1710
1711
1712 //---------------------------------------------------------------------------
1713
1714 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1715         QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1716     : QV8ObjectResource(metaType->v8Engine)
1717     , metaType(metaType)
1718     , contextData(0)
1719     , object(0)
1720     , attached(0)
1721     , incubationTask(0)
1722     , objectRef(0)
1723     , scriptRef(0)
1724     , groups(0)
1725     , index(modelIndex)
1726 {
1727     metaType->addref();
1728 }
1729
1730 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1731 {
1732     Q_ASSERT(scriptRef == 0);
1733     Q_ASSERT(objectRef == 0);
1734     Q_ASSERT(!object);
1735     Q_ASSERT(indexHandle.IsEmpty());
1736     Q_ASSERT(modelHandle.IsEmpty());
1737
1738     if (incubationTask && metaType->model)
1739         QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1740
1741     metaType->release();
1742
1743 }
1744
1745 void QQuickVisualDataModelItem::Dispose()
1746 {
1747     --scriptRef;
1748     if (isReferenced())
1749         return;
1750
1751     if (metaType->model) {
1752         QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1753         model->removeCacheItem(this);
1754     }
1755     delete this;
1756 }
1757
1758 /*
1759     This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1760     arguments instead of QQmlContext which means we don't have to construct the rather weighty
1761     wrapper class for every delegate item.
1762 */
1763 void QQuickVisualDataModelItem::incubateObject(
1764         QQmlComponent *component,
1765         QQmlEngine *engine,
1766         QQmlContextData *context,
1767         QQmlContextData *forContext)
1768 {
1769     QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
1770     QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
1771     QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
1772
1773     incubatorPriv->compiledData = componentPriv->cc;
1774     incubatorPriv->compiledData->addref();
1775     incubatorPriv->vme.init(
1776             context,
1777             componentPriv->cc,
1778             componentPriv->start,
1779             componentPriv->creationContext);
1780
1781     enginePriv->incubate(*incubationTask, forContext);
1782 }
1783
1784 void QQuickVisualDataModelItem::destroyObject()
1785 {
1786     Q_ASSERT(object);
1787     Q_ASSERT(contextData);
1788
1789     QObjectPrivate *p = QObjectPrivate::get(object);
1790     Q_ASSERT(p->declarativeData);
1791     QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1792     if (data->ownContext && data->context)
1793         data->context->clearContext();
1794     object->deleteLater();
1795
1796     if (attached) {
1797         attached->m_cacheItem = 0;
1798         attached = 0;
1799     }
1800
1801     contextData->destroy();
1802     contextData = 0;
1803     object = 0;
1804 }
1805
1806 QQuickVisualDataModelItem *QQuickVisualDataModelItem::dataForObject(QObject *object)
1807 {
1808     QObjectPrivate *p = QObjectPrivate::get(object);
1809     QQmlContextData *context = p->declarativeData
1810             ? static_cast<QQmlData *>(p->declarativeData)->context
1811             : 0;
1812     for (context = context ? context->parent : 0; context; context = context->parent) {
1813         if (QQuickVisualDataModelItem *cacheItem = qobject_cast<QQuickVisualDataModelItem *>(
1814                 context->contextObject)) {
1815             return cacheItem;
1816         }
1817     }
1818     return 0;
1819 }
1820
1821 int QQuickVisualDataModelItem::groupIndex(Compositor::Group group)
1822 {
1823     if (QQuickVisualDataModelPrivate * const model = metaType->model
1824             ? QQuickVisualDataModelPrivate::get(metaType->model)
1825             : 0) {
1826         return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
1827     }
1828     return -1;
1829 }
1830
1831 //---------------------------------------------------------------------------
1832
1833 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1834         QQuickVisualDataModelItemMetaType *metaType, QMetaObject *metaObject)
1835     : metaType(metaType)
1836     , metaObject(metaObject)
1837     , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1838     , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
1839 {
1840     // Don't reference count the meta-type here as that would create a circular reference.
1841     // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
1842     // destroying all delegates with attached objects.
1843     *static_cast<QMetaObject *>(this) = *metaObject;
1844 }
1845
1846 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1847 {
1848     ::free(metaObject);
1849 }
1850
1851 void QQuickVisualDataModelAttachedMetaObject::objectDestroyed(QObject *)
1852 {
1853     release();
1854 }
1855
1856 int QQuickVisualDataModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
1857 {
1858     QQuickVisualDataModelAttached *attached = static_cast<QQuickVisualDataModelAttached *>(object);
1859     if (call == QMetaObject::ReadProperty) {
1860         if (_id >= indexPropertyOffset) {
1861             Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
1862             *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
1863             return -1;
1864         } else if (_id >= memberPropertyOffset) {
1865             Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1866             *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1867             return -1;
1868         }
1869     } else if (call == QMetaObject::WriteProperty) {
1870         if (_id >= memberPropertyOffset) {
1871             if (!metaType->model)
1872                 return -1;
1873             QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1874             Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1875             const int groupFlag = 1 << group;
1876             const bool member = attached->m_cacheItem->groups & groupFlag;
1877             if (member && !*static_cast<bool *>(arguments[0])) {
1878                 Compositor::iterator it = model->m_compositor.find(
1879                         group, attached->m_currentIndex[group]);
1880                 model->removeGroups(it, 1, group, groupFlag);
1881             } else if (!member && *static_cast<bool *>(arguments[0])) {
1882                 for (int i = 1; i < metaType->groupCount; ++i) {
1883                     if (attached->m_cacheItem->groups & (1 << i)) {
1884                         Compositor::iterator it = model->m_compositor.find(
1885                                 Compositor::Group(i), attached->m_currentIndex[i]);
1886                         model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1887                         break;
1888                     }
1889                 }
1890             }
1891             return -1;
1892         }
1893     }
1894     return attached->qt_metacall(call, _id, arguments);
1895 }
1896
1897 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1898     : m_cacheItem(0)
1899     , m_previousGroups(0)
1900     , m_modelChanged(false)
1901 {
1902     QQml_setParent_noEvent(this, parent);
1903 }
1904
1905 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1906         QQuickVisualDataModelItem *cacheItem, QObject *parent)
1907     : m_cacheItem(cacheItem)
1908     , m_previousGroups(cacheItem->groups)
1909     , m_modelChanged(false)
1910 {
1911     QQml_setParent_noEvent(this, parent);
1912     if (QVDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
1913         for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1914             m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
1915     } else {
1916         QQuickVisualDataModelPrivate * const model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1917         Compositor::iterator it = model->m_compositor.find(
1918                 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
1919         for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1920             m_currentIndex[i] = m_previousIndex[i] = it.index[i];
1921     }
1922
1923     if (!cacheItem->metaType->metaObject)
1924         cacheItem->metaType->initializeMetaObject();
1925
1926     QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
1927     cacheItem->metaType->metaObject->addref();
1928 }
1929
1930 /*!
1931     \qmlattachedproperty int QtQuick2::VisualDataModel::model
1932
1933     This attached property holds the visual data model this delegate instance belongs to.
1934
1935     It is attached to each instance of the delegate.
1936 */
1937
1938 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1939 {
1940     return m_cacheItem ? m_cacheItem->metaType->model : 0;
1941 }
1942
1943 /*!
1944     \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1945
1946     This attached property holds the name of VisualDataGroups the item belongs to.
1947
1948     It is attached to each instance of the delegate.
1949 */
1950
1951 QStringList QQuickVisualDataModelAttached::groups() const
1952 {
1953     QStringList groups;
1954
1955     if (!m_cacheItem)
1956         return groups;
1957     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1958         if (m_cacheItem->groups & (1 << i))
1959             groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1960     }
1961     return groups;
1962 }
1963
1964 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1965 {
1966     if (!m_cacheItem)
1967         return;
1968
1969     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1970
1971     const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1972     const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1973     Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1974     model->setGroups(it, 1, Compositor::Cache, groupFlags);
1975 }
1976
1977 bool QQuickVisualDataModelAttached::isUnresolved() const
1978 {
1979     if (!m_cacheItem)
1980         return false;
1981
1982     return m_cacheItem->groups & Compositor::UnresolvedFlag;
1983 }
1984
1985 /*!
1986     \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1987
1988     This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1989
1990     Changing this property will add or remove the item from the items group.
1991
1992     It is attached to each instance of the delegate.
1993 */
1994
1995 /*!
1996     \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1997
1998     This attached property holds the index of the item in the default \l items VisualDataGroup.
1999
2000     It is attached to each instance of the delegate.
2001 */
2002
2003 /*!
2004     \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
2005
2006     This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
2007
2008     Changing this property will add or remove the item from the items group.  Change with caution
2009     as removing an item from the persistedItems group will destroy the current instance if it is
2010     not referenced by a model.
2011
2012     It is attached to each instance of the delegate.
2013 */
2014
2015 /*!
2016     \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
2017
2018     This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
2019
2020     It is attached to each instance of the delegate.
2021 */
2022
2023 void QQuickVisualDataModelAttached::emitChanges()
2024 {
2025     if (m_modelChanged) {
2026         m_modelChanged = false;
2027         emit modelChanged();
2028     }
2029
2030     const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2031     m_previousGroups = m_cacheItem->groups;
2032
2033     int indexChanges = 0;
2034     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2035         if (m_previousIndex[i] != m_currentIndex[i]) {
2036             m_previousIndex[i] = m_currentIndex[i];
2037             indexChanges |= (1 << i);
2038         }
2039     }
2040
2041     int notifierId = 0;
2042     const QMetaObject *meta = metaObject();
2043     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2044         if (groupChanges & (1 << i))
2045             QMetaObject::activate(this, meta, notifierId, 0);
2046     }
2047     for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2048         if (indexChanges & (1 << i))
2049             QMetaObject::activate(this, meta, notifierId, 0);
2050     }
2051
2052     if (groupChanges)
2053         emit groupsChanged();
2054 }
2055
2056 //============================================================================
2057
2058 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
2059 {
2060     Q_ASSERT(!model);
2061     model = m;
2062     group = g;
2063 }
2064
2065 bool QQuickVisualDataGroupPrivate::isChangedConnected()
2066 {
2067     Q_Q(QQuickVisualDataGroup);
2068     IS_SIGNAL_CONNECTED(q, QQuickVisualDataGroup, changed, (const QQmlV8Handle &,const QQmlV8Handle &));
2069 }
2070
2071 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
2072 {
2073     Q_Q(QQuickVisualDataGroup);
2074     if (isChangedConnected() && !changeSet.isEmpty()) {
2075         v8::HandleScope handleScope;
2076         v8::Context::Scope contextScope(engine->context());
2077         v8::Local<v8::Object> removed  = engineData(engine)->array(engine, changeSet.removes());
2078         v8::Local<v8::Object> inserted = engineData(engine)->array(engine, changeSet.inserts());
2079         emit q->changed(QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
2080     }
2081     if (changeSet.difference() != 0)
2082         emit q->countChanged();
2083 }
2084
2085 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
2086 {
2087     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2088         it->emitModelUpdated(changeSet, reset);
2089     changeSet.clear();
2090 }
2091
2092 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
2093 {
2094     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2095         it->createdPackage(index, package);
2096 }
2097
2098 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
2099 {
2100     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2101         it->initPackage(index, package);
2102 }
2103
2104 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
2105 {
2106     for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2107         it->destroyingPackage(package);
2108 }
2109
2110 /*!
2111     \qmlclass VisualDataGroup QQuickVisualDataGroup
2112     \inqmlmodule QtQuick 2
2113     \ingroup qtquick-models
2114     \brief Encapsulates a filtered set of visual data items
2115
2116 */
2117
2118 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2119     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2120 {
2121 }
2122
2123 QQuickVisualDataGroup::QQuickVisualDataGroup(
2124         const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2125     : QObject(*new QQuickVisualDataGroupPrivate, parent)
2126 {
2127     Q_D(QQuickVisualDataGroup);
2128     d->name = name;
2129     d->setModel(model, Compositor::Group(index));
2130 }
2131
2132 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2133 {
2134 }
2135
2136 /*!
2137     \qmlproperty string QtQuick2::VisualDataGroup::name
2138
2139     This property holds the name of the group.
2140
2141     Each group in a model must have a unique name starting with a lower case letter.
2142 */
2143
2144 QString QQuickVisualDataGroup::name() const
2145 {
2146     Q_D(const QQuickVisualDataGroup);
2147     return d->name;
2148 }
2149
2150 void QQuickVisualDataGroup::setName(const QString &name)
2151 {
2152     Q_D(QQuickVisualDataGroup);
2153     if (d->model)
2154         return;
2155     if (d->name != name) {
2156         d->name = name;
2157         emit nameChanged();
2158     }
2159 }
2160
2161 /*!
2162     \qmlproperty int QtQuick2::VisualDataGroup::count
2163
2164     This property holds the number of items in the group.
2165 */
2166
2167 int QQuickVisualDataGroup::count() const
2168 {
2169     Q_D(const QQuickVisualDataGroup);
2170     if (!d->model)
2171         return 0;
2172     return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2173 }
2174
2175 /*!
2176     \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2177
2178     This property holds whether new items are assigned to this group by default.
2179 */
2180
2181 bool QQuickVisualDataGroup::defaultInclude() const
2182 {
2183     Q_D(const QQuickVisualDataGroup);
2184     return d->defaultInclude;
2185 }
2186
2187 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2188 {
2189     Q_D(QQuickVisualDataGroup);
2190     if (d->defaultInclude != include) {
2191         d->defaultInclude = include;
2192
2193         if (d->model) {
2194             if (include)
2195                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2196             else
2197                 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2198         }
2199         emit defaultIncludeChanged();
2200     }
2201 }
2202
2203 /*!
2204     \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2205
2206     Returns a javascript object describing the item at \a index in the group.
2207
2208     The returned object contains the same information that is available to a delegate from the
2209     VisualDataModel attached as well as the model for that item.  It has the properties:
2210
2211     \list
2212     \li \b model The model data of the item.  This is the same as the model context property in
2213     a delegate
2214     \li \b groups A list the of names of groups the item is a member of.  This property can be
2215     written to change the item's membership.
2216     \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2217     Writing to this property will add or remove the item from the group.
2218     \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2219     \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName.  Writing to
2220     this property will add or remove the item from the group.
2221     \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2222     \endlist
2223 */
2224
2225 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2226 {
2227     Q_D(QQuickVisualDataGroup);
2228     if (!d->model)
2229         return QQmlV8Handle::fromHandle(v8::Undefined());;
2230
2231     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2232     if (index < 0 || index >= model->m_compositor.count(d->group)) {
2233         qmlInfo(this) << tr("get: index out of range");
2234         return QQmlV8Handle::fromHandle(v8::Undefined());
2235     }
2236
2237     Compositor::iterator it = model->m_compositor.find(d->group, index);
2238     QQuickVisualDataModelItem *cacheItem = it->inCache()
2239             ? model->m_cache.at(it.cacheIndex)
2240             : 0;
2241
2242     if (!cacheItem) {
2243         cacheItem = model->m_adaptorModel.createItem(
2244                 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2245         if (!cacheItem)
2246             return QQmlV8Handle::fromHandle(v8::Undefined());
2247         cacheItem->groups = it->flags;
2248
2249         model->m_cache.insert(it.cacheIndex, cacheItem);
2250         model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2251     }
2252
2253     if (cacheItem->indexHandle.IsEmpty()) {
2254         if (model->m_cacheMetaType->constructor.IsEmpty())
2255             model->m_cacheMetaType->initializeConstructor();
2256         cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
2257         cacheItem->indexHandle->SetExternalResource(cacheItem);
2258         cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
2259
2260         ++cacheItem->scriptRef;
2261     }
2262
2263     return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
2264 }
2265
2266 bool QQuickVisualDataGroupPrivate::parseIndex(
2267         const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2268 {
2269     if (value->IsInt32()) {
2270         *index = value->Int32Value();
2271         return true;
2272     } else if (value->IsObject()) {
2273         v8::Local<v8::Object> object = value->ToObject();
2274         QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2275         if (QQuickVisualDataModelPrivate *model = cacheItem && cacheItem->metaType->model
2276                 ? QQuickVisualDataModelPrivate::get(cacheItem->metaType->model)
2277                 : 0) {
2278             *index = model->m_cache.indexOf(cacheItem);
2279             *group = Compositor::Cache;
2280             return true;
2281         }
2282     }
2283     return false;
2284 }
2285
2286 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2287 {
2288     Q_D(QQuickVisualDataGroup);
2289     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2290
2291     int index = model->m_compositor.count(d->group);
2292     Compositor::Group group = d->group;
2293
2294     if (args->Length() == 0)
2295         return;
2296
2297     int  i = 0;
2298     v8::Local<v8::Value> v = (*args)[i];
2299     if (d->parseIndex(v, &index, &group)) {
2300         if (index < 0 || index > model->m_compositor.count(group)) {
2301             qmlInfo(this) << tr("insert: index out of range");
2302             return;
2303         }
2304         if (++i == args->Length())
2305             return;
2306         v = (*args)[i];
2307     }
2308
2309     Compositor::insert_iterator before = index < model->m_compositor.count(group)
2310             ? model->m_compositor.findInsertPosition(group, index)
2311             : model->m_compositor.end();
2312
2313     int groups = 1 << d->group;
2314     if (++i < args->Length())
2315         groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2316
2317     if (v->IsArray()) {
2318         return;
2319     } else if (v->IsObject()) {
2320         model->insert(before, v->ToObject(), groups);
2321         model->emitChanges();
2322     }
2323 }
2324
2325 /*!
2326     \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2327     \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2328     \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2329
2330     Returns a reference to the instantiated item at \a index in the group.
2331
2332     All items returned by create are added to the persistedItems group.  Items in this
2333     group remain instantiated when not referenced by any view.
2334 */
2335
2336 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2337 {
2338     Q_D(QQuickVisualDataGroup);
2339     if (!d->model)
2340         return;
2341
2342     if (args->Length() == 0)
2343         return;
2344
2345     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2346
2347     int index = model->m_compositor.count(d->group);
2348     Compositor::Group group = d->group;
2349
2350     int  i = 0;
2351     v8::Local<v8::Value> v = (*args)[i];
2352     if (d->parseIndex(v, &index, &group))
2353         ++i;
2354
2355     if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2356         v = (*args)[i];
2357         if (v->IsObject()) {
2358             int groups = 1 << d->group;
2359             if (++i < args->Length())
2360                 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2361
2362             Compositor::insert_iterator before = index < model->m_compositor.count(group)
2363                     ? model->m_compositor.findInsertPosition(group, index)
2364                     : model->m_compositor.end();
2365
2366             index = before.index[d->group];
2367             group = d->group;
2368
2369             if (!model->insert(before, v->ToObject(), groups)) {
2370                 return;
2371             }
2372         }
2373     }
2374     if (index < 0 || index >= model->m_compositor.count(group)) {
2375         qmlInfo(this) << tr("create: index out of range");
2376         return;
2377     }
2378
2379     QObject *object = model->object(group, index, false);
2380     if (object) {
2381         QVector<Compositor::Insert> inserts;
2382         Compositor::iterator it = model->m_compositor.find(group, index);
2383         model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2384         model->itemsInserted(inserts);
2385         model->m_cache.at(it.cacheIndex)->releaseObject();
2386     }
2387
2388     args->returnValue(args->engine()->newQObject(object));
2389     model->emitChanges();
2390 }
2391
2392 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2393 {
2394     Q_D(QQuickVisualDataGroup);
2395     if (!d->model)
2396         return;
2397
2398     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2399
2400     if (args->Length() < 2)
2401         return;
2402
2403     int from = -1;
2404     int to = -1;
2405     Compositor::Group fromGroup = d->group;
2406     Compositor::Group toGroup = d->group;
2407
2408     v8::Local<v8::Value> v = (*args)[0];
2409     if (d->parseIndex(v, &from, &fromGroup)) {
2410         if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2411             qmlInfo(this) << tr("resolve: from index out of range");
2412             return;
2413         }
2414     } else {
2415         qmlInfo(this) << tr("resolve: from index invalid");
2416         return;
2417     }
2418
2419     v = (*args)[1];
2420     if (d->parseIndex(v, &to, &toGroup)) {
2421         if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2422             qmlInfo(this) << tr("resolve: to index out of range");
2423             return;
2424         }
2425     } else {
2426         qmlInfo(this) << tr("resolve: to index invalid");
2427         return;
2428     }
2429
2430     Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2431     Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2432
2433     if (!fromIt->isUnresolved()) {
2434         qmlInfo(this) << tr("resolve: from is not an unresolved item");
2435         return;
2436     }
2437     if (!toIt->list) {
2438         qmlInfo(this) << tr("resolve: to is not a model item");
2439         return;
2440     }
2441
2442     const int unresolvedFlags = fromIt->flags;
2443     const int resolvedFlags = toIt->flags;
2444     const int resolvedIndex = toIt.modelIndex();
2445     void * const resolvedList = toIt->list;
2446
2447     QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2448     cacheItem->groups &= ~Compositor::UnresolvedFlag;
2449
2450     if (toIt.cacheIndex > fromIt.cacheIndex)
2451         toIt.decrementIndexes(1, unresolvedFlags);
2452     if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2453         from += 1;
2454
2455     model->itemsMoved(
2456             QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2457             QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2458     model->itemsInserted(
2459             QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2460     toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2461     model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2462
2463     model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2464     model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2465
2466     if (resolvedFlags & Compositor::CacheFlag)
2467         model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2468
2469     Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2470
2471     if (!cacheItem->isReferenced()) {
2472         Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2473         model->m_cache.removeAt(toIt.cacheIndex);
2474         model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2475         delete cacheItem;
2476         Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2477     } else {
2478         cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2479         if (cacheItem->attached)
2480             cacheItem->attached->emitUnresolvedChanged();
2481     }
2482
2483     model->emitChanges();
2484 }
2485
2486 /*!
2487     \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2488
2489     Removes \a count items starting at \a index from the group.
2490 */
2491
2492 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2493 {
2494     Q_D(QQuickVisualDataGroup);
2495     if (!d->model)
2496         return;
2497     Compositor::Group group = d->group;
2498     int index = -1;
2499     int count = 1;
2500
2501     if (args->Length() == 0)
2502         return;
2503
2504     int i = 0;
2505     v8::Local<v8::Value> v = (*args)[i];
2506     if (!d->parseIndex(v, &index, &group)) {
2507         qmlInfo(this) << tr("remove: invalid index");
2508         return;
2509     }
2510
2511     if (++i < args->Length()) {
2512         v = (*args)[i];
2513         if (v->IsInt32())
2514             count = v->Int32Value();
2515     }
2516
2517     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2518     if (index < 0 || index >= model->m_compositor.count(group)) {
2519         qmlInfo(this) << tr("remove: index out of range");
2520     } else if (count != 0) {
2521         Compositor::iterator it = model->m_compositor.find(group, index);
2522         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2523             qmlInfo(this) << tr("remove: invalid count");
2524         } else {
2525             model->removeGroups(it, count, d->group, 1 << d->group);
2526         }
2527     }
2528 }
2529
2530 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2531         QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2532 {
2533     if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2534         return false;
2535
2536     if (args->Length() < 2)
2537         return false;
2538
2539     int i = 0;
2540     v8::Local<v8::Value> v = (*args)[i];
2541     if (!parseIndex(v, index, group))
2542         return false;
2543
2544     v = (*args)[++i];
2545     if (v->IsInt32()) {
2546         *count = v->Int32Value();
2547
2548         if (++i == args->Length())
2549             return false;
2550         v = (*args)[i];
2551     }
2552
2553     *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2554
2555     return true;
2556 }
2557
2558 /*!
2559     \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2560
2561     Adds \a count items starting at \a index to \a groups.
2562 */
2563
2564 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2565 {
2566     Q_D(QQuickVisualDataGroup);
2567     Compositor::Group group = d->group;
2568     int index = -1;
2569     int count = 1;
2570     int groups = 0;
2571
2572     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2573         return;
2574
2575     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2576     if (index < 0 || index >= model->m_compositor.count(group)) {
2577         qmlInfo(this) << tr("addGroups: index out of range");
2578     } else if (count != 0) {
2579         Compositor::iterator it = model->m_compositor.find(group, index);
2580         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2581             qmlInfo(this) << tr("addGroups: invalid count");
2582         } else {
2583             model->addGroups(it, count, d->group, groups);
2584         }
2585     }
2586 }
2587
2588 /*!
2589     \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2590
2591     Removes \a count items starting at \a index from \a groups.
2592 */
2593
2594 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2595 {
2596     Q_D(QQuickVisualDataGroup);
2597     Compositor::Group group = d->group;
2598     int index = -1;
2599     int count = 1;
2600     int groups = 0;
2601
2602     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2603         return;
2604
2605     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2606     if (index < 0 || index >= model->m_compositor.count(group)) {
2607         qmlInfo(this) << tr("removeGroups: index out of range");
2608     } else if (count != 0) {
2609         Compositor::iterator it = model->m_compositor.find(group, index);
2610         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2611             qmlInfo(this) << tr("removeGroups: invalid count");
2612         } else {
2613             model->removeGroups(it, count, d->group, groups);
2614         }
2615     }
2616 }
2617
2618 /*!
2619     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2620
2621     Sets the \a groups \a count items starting at \a index belong to.
2622 */
2623
2624 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2625 {
2626     Q_D(QQuickVisualDataGroup);
2627     Compositor::Group group = d->group;
2628     int index = -1;
2629     int count = 1;
2630     int groups = 0;
2631
2632     if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2633         return;
2634
2635     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2636     if (index < 0 || index >= model->m_compositor.count(group)) {
2637         qmlInfo(this) << tr("setGroups: index out of range");
2638     } else if (count != 0) {
2639         Compositor::iterator it = model->m_compositor.find(group, index);
2640         if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2641             qmlInfo(this) << tr("setGroups: invalid count");
2642         } else {
2643             model->setGroups(it, count, d->group, groups);
2644         }
2645     }
2646 }
2647
2648 /*!
2649     \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2650
2651     Sets the \a groups \a count items starting at \a index belong to.
2652 */
2653
2654 /*!
2655     \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2656
2657     Moves \a count at \a from in a group \a to a new position.
2658 */
2659
2660 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2661 {
2662     Q_D(QQuickVisualDataGroup);
2663
2664     if (args->Length() < 2)
2665         return;
2666
2667     Compositor::Group fromGroup = d->group;
2668     Compositor::Group toGroup = d->group;
2669     int from = -1;
2670     int to = -1;
2671     int count = 1;
2672
2673     if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2674         qmlInfo(this) << tr("move: invalid from index");
2675         return;
2676     }
2677
2678     if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2679         qmlInfo(this) << tr("move: invalid to index");
2680         return;
2681     }
2682
2683     if (args->Length() > 2) {
2684         v8::Local<v8::Value> v = (*args)[2];
2685         if (v->IsInt32())
2686             count = v->Int32Value();
2687     }
2688
2689     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2690
2691     if (count < 0) {
2692         qmlInfo(this) << tr("move: invalid count");
2693     } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2694         qmlInfo(this) << tr("move: from index out of range");
2695     } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2696         qmlInfo(this) << tr("move: to index out of range");
2697     } else if (count > 0) {
2698         QVector<Compositor::Remove> removes;
2699         QVector<Compositor::Insert> inserts;
2700
2701         model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2702         model->itemsMoved(removes, inserts);
2703         model->emitChanges();
2704     }
2705
2706 }
2707
2708 /*!
2709     \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2710
2711     This handler is called when items have been removed from or inserted into the group.
2712
2713     Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2714     item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2715
2716     Each index is adjusted for previous changes with all removed items preceding any inserted
2717     items.
2718 */
2719
2720 //============================================================================
2721
2722 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2723     : QQuickVisualModel(*new QObjectPrivate, parent)
2724     , m_model(model)
2725     , m_part(part)
2726     , m_compositorGroup(Compositor::Cache)
2727     , m_inheritGroup(true)
2728 {
2729     QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2730     if (d->m_cacheMetaType) {
2731         QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2732         m_compositorGroup = Compositor::Default;
2733     } else {
2734         d->m_pendingParts.insert(this);
2735     }
2736 }
2737
2738 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2739 {
2740 }
2741
2742 QString QQuickVisualPartsModel::filterGroup() const
2743 {
2744     if (m_inheritGroup)
2745         return m_model->filterGroup();
2746     return m_filterGroup;
2747 }
2748
2749 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2750 {
2751     if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2752         qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2753         return;
2754     }
2755
2756     if (m_filterGroup != group || m_inheritGroup) {
2757         m_filterGroup = group;
2758         m_inheritGroup = false;
2759         updateFilterGroup();
2760
2761         emit filterGroupChanged();
2762     }
2763 }
2764
2765 void QQuickVisualPartsModel::resetFilterGroup()
2766 {
2767     if (!m_inheritGroup) {
2768         m_inheritGroup = true;
2769         updateFilterGroup();
2770         emit filterGroupChanged();
2771     }
2772 }
2773
2774 void QQuickVisualPartsModel::updateFilterGroup()
2775 {
2776     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2777     if (!model->m_cacheMetaType)
2778         return;
2779
2780     if (m_inheritGroup) {
2781         if (m_filterGroup == model->m_filterGroup)
2782             return;
2783         m_filterGroup = model->m_filterGroup;
2784     }
2785
2786     QQuickListCompositor::Group previousGroup = m_compositorGroup;
2787     m_compositorGroup = Compositor::Default;
2788     QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2789     for (int i = 1; i < model->m_groupCount; ++i) {
2790         if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2791             m_compositorGroup = Compositor::Group(i);
2792             break;
2793         }
2794     }
2795
2796     QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2797     if (m_compositorGroup != previousGroup) {
2798         QVector<QQuickChangeSet::Remove> removes;
2799         QVector<QQuickChangeSet::Insert> inserts;
2800         model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2801
2802         QQuickChangeSet changeSet;
2803         changeSet.apply(removes, inserts);
2804         if (!changeSet.isEmpty())
2805             emit modelUpdated(changeSet, false);
2806
2807         if (changeSet.difference() != 0)
2808             emit countChanged();
2809     }
2810 }
2811
2812 void QQuickVisualPartsModel::updateFilterGroup(
2813         Compositor::Group group, const QQuickChangeSet &changeSet)
2814 {
2815     if (!m_inheritGroup)
2816         return;
2817
2818     m_compositorGroup = group;
2819     QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2820
2821     if (!changeSet.isEmpty())
2822         emit modelUpdated(changeSet, false);
2823
2824     if (changeSet.difference() != 0)
2825         emit countChanged();
2826
2827     emit filterGroupChanged();
2828 }
2829
2830 int QQuickVisualPartsModel::count() const
2831 {
2832     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2833     return model->m_delegate
2834             ? model->m_compositor.count(m_compositorGroup)
2835             : 0;
2836 }
2837
2838 bool QQuickVisualPartsModel::isValid() const
2839 {
2840     return m_model->isValid();
2841 }
2842
2843 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2844 {
2845     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2846
2847     if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2848         qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2849         return 0;
2850     }
2851
2852     QObject *object = model->object(m_compositorGroup, index, asynchronous);
2853
2854     if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
2855         QObject *part = package->part(m_part);
2856         if (!part)
2857             return 0;
2858         if (QQuickItem *item = qmlobject_cast<QQuickItem *>(part)) {
2859             m_packaged.insertMulti(item, package);
2860             return item;
2861         }
2862     }
2863
2864     model->release(object);
2865     if (!model->m_delegateValidated) {
2866         if (object)
2867             qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2868         model->m_delegateValidated = true;
2869     }
2870
2871     return 0;
2872 }
2873
2874 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2875 {
2876     QQuickVisualModel::ReleaseFlags flags = 0;
2877
2878     QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2879     if (it != m_packaged.end()) {
2880         QQuickPackage *package = *it;
2881         QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2882         flags = model->release(package);
2883         m_packaged.erase(it);
2884         if (!m_packaged.contains(item))
2885             flags &= ~Referenced;
2886         if (flags & Destroyed)
2887             QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2888     }
2889     return flags;
2890 }
2891
2892 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2893 {
2894     return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2895 }
2896
2897 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2898 {
2899     QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2900     model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2901     m_watchedRoles = roles;
2902 }
2903
2904 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2905 {
2906     QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2907     if (it != m_packaged.end()) {
2908         if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2909             return cacheItem->groupIndex(m_compositorGroup);
2910     }
2911     return -1;
2912 }
2913
2914 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2915 {
2916     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2917         emit createdItem(index, item);
2918 }
2919
2920 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2921 {
2922     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2923         emit initItem(index, item);
2924 }
2925
2926 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2927 {
2928     if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part))) {
2929         Q_ASSERT(!m_packaged.contains(item));
2930         emit destroyingItem(item);
2931         item->setParentItem(0);
2932     }
2933 }
2934
2935 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2936 {
2937     emit modelUpdated(changeSet, reset);
2938     if (changeSet.difference() != 0)
2939         emit countChanged();
2940 }
2941
2942 //============================================================================
2943
2944 v8::Handle<v8::Value> get_change_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
2945 {
2946     return info.This()->GetInternalField(0);
2947 }
2948
2949 v8::Handle<v8::Value> get_change_count(v8::Local<v8::String>, const v8::AccessorInfo &info)
2950 {
2951     return info.This()->GetInternalField(1);
2952 }
2953
2954 v8::Handle<v8::Value> get_change_moveId(v8::Local<v8::String>, const v8::AccessorInfo &info)
2955 {
2956     return info.This()->GetInternalField(2);
2957 }
2958
2959 class QQuickVisualDataGroupChangeArray : public QV8ObjectResource
2960 {
2961     V8_RESOURCE_TYPE(ChangeSetArrayType)
2962 public:
2963     QQuickVisualDataGroupChangeArray(QV8Engine *engine)
2964         : QV8ObjectResource(engine)
2965     {
2966     }
2967
2968     virtual quint32 count() const = 0;
2969     virtual const QQuickChangeSet::Change &at(int index) const = 0;
2970
2971     static v8::Handle<v8::Value> get_change(quint32 index, const v8::AccessorInfo &info)
2972     {
2973         QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2974         if (!array)
2975             V8THROW_ERROR("Not a valid change array");
2976
2977         if (index >= array->count())
2978             return v8::Undefined();
2979
2980         const QQuickChangeSet::Change &change = array->at(index);
2981
2982         v8::Local<v8::Object> object = engineData(array->engine)->constructorChange->NewInstance();
2983         object->SetInternalField(0, v8::Int32::New(change.index));
2984         object->SetInternalField(1, v8::Int32::New(change.count));
2985         if (change.isMove())
2986             object->SetInternalField(2, v8::Int32::New(change.moveId));
2987
2988         return object;
2989     }
2990
2991     static v8::Handle<v8::Value> get_length(v8::Local<v8::String>, const v8::AccessorInfo &info)
2992     {
2993         QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2994         if (!array)
2995             V8THROW_ERROR("Not a valid change array");
2996
2997         return v8::Integer::New(array->count());
2998     }
2999
3000     static v8::Local<v8::Function> constructor()
3001     {
3002         v8::Local<v8::FunctionTemplate> changeArray = v8::FunctionTemplate::New();
3003         changeArray->InstanceTemplate()->SetHasExternalResource(true);
3004         changeArray->InstanceTemplate()->SetIndexedPropertyHandler(get_change);
3005         changeArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), get_length);
3006         return changeArray->GetFunction();
3007     }
3008 };
3009
3010 class QQuickVisualDataGroupRemoveArray : public QQuickVisualDataGroupChangeArray
3011 {
3012 public:
3013     QQuickVisualDataGroupRemoveArray(QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3014         : QQuickVisualDataGroupChangeArray(engine)
3015         , changes(changes)
3016     {
3017     }
3018
3019     quint32 count() const { return changes.count(); }
3020     const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3021
3022 private:
3023     QVector<QQuickChangeSet::Remove> changes;
3024 };
3025
3026 class QQuickVisualDataGroupInsertArray : public QQuickVisualDataGroupChangeArray
3027 {
3028 public:
3029     QQuickVisualDataGroupInsertArray(QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3030         : QQuickVisualDataGroupChangeArray(engine)
3031         , changes(changes)
3032     {
3033     }
3034
3035     quint32 count() const { return changes.count(); }
3036     const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3037
3038 private:
3039     QVector<QQuickChangeSet::Insert> changes;
3040 };
3041
3042 QQuickVisualDataModelEngineData::QQuickVisualDataModelEngineData(QV8Engine *)
3043 {
3044     strings = qPersistentNew(v8::Array::New(StringCount));
3045     strings->Set(Model, v8::String::New("model"));
3046     strings->Set(Groups, v8::String::New("groups"));
3047     strings->Set(IsUnresolved, v8::String::New("isUnresolved"));
3048     strings->Set(ItemsIndex, v8::String::New("itemsIndex"));
3049     strings->Set(PersistedItemsIndex, v8::String::New("persistedItemsIndex"));
3050     strings->Set(InItems, v8::String::New("inItems"));
3051     strings->Set(InPersistedItems, v8::String::New("inPersistedItems"));
3052
3053     v8::Local<v8::FunctionTemplate> change = v8::FunctionTemplate::New();
3054     change->InstanceTemplate()->SetAccessor(v8::String::New("index"), get_change_index);
3055     change->InstanceTemplate()->SetAccessor(v8::String::New("count"), get_change_count);
3056     change->InstanceTemplate()->SetAccessor(v8::String::New("moveId"), get_change_moveId);
3057     change->InstanceTemplate()->SetInternalFieldCount(3);
3058     constructorChange = qPersistentNew(change->GetFunction());
3059     constructorChangeArray = qPersistentNew(QQuickVisualDataGroupChangeArray::constructor());
3060 }
3061
3062 QQuickVisualDataModelEngineData::~QQuickVisualDataModelEngineData()
3063 {
3064     qPersistentDispose(strings);
3065     qPersistentDispose(constructorChange);
3066     qPersistentDispose(constructorChangeArray);
3067 }
3068
3069 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3070         QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3071 {
3072     v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3073     array->SetExternalResource(new QQuickVisualDataGroupRemoveArray(engine, changes));
3074     return array;
3075 }
3076
3077 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3078         QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3079 {
3080     v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3081     array->SetExternalResource(new QQuickVisualDataGroupInsertArray(engine, changes));
3082     return array;
3083 }
3084
3085 QT_END_NAMESPACE
3086