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