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