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