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