1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickvisualdatamodel_p_p.h"
43 #include "qquickitem.h"
45 #include <QtQml/qqmlinfo.h>
47 #include <private/qquickpackage_p.h>
48 #include <private/qmetaobjectbuilder_p.h>
49 #include <private/qquickvisualadaptormodel_p.h>
50 #include <private/qquickchangeset_p.h>
51 #include <private/qqmlengine_p.h>
52 #include <private/qqmlcomponent_p.h>
53 #include <private/qqmlincubator_p.h>
54 #include <private/qqmlcompiler_p.h>
58 class QQuickVisualDataModelEngineData : public QV8Engine::Deletable
73 QQuickVisualDataModelEngineData(QV8Engine *engine);
74 ~QQuickVisualDataModelEngineData();
76 v8::Local<v8::Object> array(
77 QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes);
78 v8::Local<v8::Object> array(
79 QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes);
80 v8::Local<v8::Object> array(
81 QV8Engine *engine, const QVector<QQuickChangeSet::Change> &changes);
84 inline v8::Local<v8::String> model() { return strings->Get(Model)->ToString(); }
85 inline v8::Local<v8::String> groups() { return strings->Get(Groups)->ToString(); }
86 inline v8::Local<v8::String> isUnresolved() { return strings->Get(IsUnresolved)->ToString(); }
87 inline v8::Local<v8::String> itemsIndex() { return strings->Get(ItemsIndex)->ToString(); }
88 inline v8::Local<v8::String> persistedItemsIndex() { return strings->Get(PersistedItemsIndex)->ToString(); }
89 inline v8::Local<v8::String> inItems() { return strings->Get(InItems)->ToString(); }
90 inline v8::Local<v8::String> inPersistedItems() { return strings->Get(InPersistedItems)->ToString(); }
92 v8::Persistent<v8::Array> strings;
93 v8::Persistent<v8::Function> constructorChange;
94 v8::Persistent<v8::Function> constructorChangeArray;
97 V8_DEFINE_EXTENSION(QQuickVisualDataModelEngineData, engineData)
100 void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
102 prop.setWritable(false);
105 QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
107 QQuickVisualDataModelParts *parts = static_cast<QQuickVisualDataModelParts *>(object());
108 QQuickVisualPartsModel *m = new QQuickVisualPartsModel(
109 parts->model, QString::fromUtf8(name(id)), parts);
110 parts->models.append(m);
111 return QVariant::fromValue(static_cast<QObject *>(m));
114 QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
115 : QObject(parent), model(parent)
117 new QQuickVisualDataModelPartsMetaObject(this);
120 //---------------------------------------------------------------------------
123 \qmlclass VisualDataModel QQuickVisualDataModel
124 \inqmlmodule QtQuick 2
125 \ingroup qtquick-models
126 \brief Encapsulates a model and delegate
128 A VisualDataModel encapsulates a model and the delegate that will
129 be instantiated for items in the model.
131 It is usually not necessary to create VisualDataModel elements.
132 However, it can be useful for manipulating and accessing the \l modelIndex
133 when a QAbstractItemModel subclass is used as the
134 model. Also, VisualDataModel is used together with \l Package to
135 provide delegates to multiple views.
137 The example below illustrates using a VisualDataModel with a ListView.
139 \snippet qml/visualdatamodel.qml 0
142 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QQmlContext *ctxt)
147 , m_filterGroup(QStringLiteral("items"))
149 , m_groupCount(Compositor::MinimumGroupCount)
150 , m_compositorGroup(Compositor::Cache)
152 , m_delegateValidated(false)
154 , m_transaction(false)
155 , m_incubatorCleanupScheduled(false)
158 , m_persistedItems(0)
162 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
164 qDeleteAll(m_finishedIncubating);
167 m_cacheMetaType->release();
170 void QQuickVisualDataModelPrivate::init()
172 Q_Q(QQuickVisualDataModel);
173 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
175 m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
176 m_items->setDefaultInclude(true);
177 m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
178 QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
181 QQuickVisualDataModel::QQuickVisualDataModel()
182 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
184 Q_D(QQuickVisualDataModel);
188 QQuickVisualDataModel::QQuickVisualDataModel(QQmlContext *ctxt, QObject *parent)
189 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
191 Q_D(QQuickVisualDataModel);
195 QQuickVisualDataModel::~QQuickVisualDataModel()
197 Q_D(QQuickVisualDataModel);
199 foreach (QQuickVisualDataModelItem *cacheItem, d->m_cache) {
200 if (cacheItem->object) {
201 delete cacheItem->object;
203 cacheItem->object = 0;
204 cacheItem->contextData->destroy();
205 cacheItem->contextData = 0;
206 cacheItem->scriptRef -= 1;
208 cacheItem->groups &= ~Compositor::UnresolvedFlag;
209 cacheItem->objectRef = 0;
210 if (!cacheItem->isReferenced())
216 void QQuickVisualDataModel::classBegin()
218 Q_D(QQuickVisualDataModel);
220 d->m_context = qmlContext(this);
223 void QQuickVisualDataModel::componentComplete()
225 Q_D(QQuickVisualDataModel);
226 d->m_complete = true;
228 int defaultGroups = 0;
229 QStringList groupNames;
230 groupNames.append(QStringLiteral("items"));
231 groupNames.append(QStringLiteral("persistedItems"));
232 if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
233 defaultGroups |= Compositor::DefaultFlag;
234 if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
235 defaultGroups |= Compositor::PersistedFlag;
236 for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
237 QString name = d->m_groups[i]->name();
238 if (name.isEmpty()) {
239 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
242 } else if (name.at(0).isUpper()) {
243 qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
244 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
248 groupNames.append(name);
250 QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
251 group->setModel(this, Compositor::Group(i));
252 if (group->defaultInclude)
253 defaultGroups |= (1 << i);
257 d->m_cacheMetaType = new QQuickVisualDataModelItemMetaType(
258 QQmlEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
260 d->m_compositor.setGroupCount(d->m_groupCount);
261 d->m_compositor.setDefaultGroups(defaultGroups);
262 d->updateFilterGroup();
264 while (!d->m_pendingParts.isEmpty())
265 static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
267 QVector<Compositor::Insert> inserts;
268 d->m_count = d->m_adaptorModel.count();
269 d->m_compositor.append(
273 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
275 d->itemsInserted(inserts);
278 if (d->m_adaptorModel.canFetchMore())
279 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
283 \qmlproperty model QtQuick2::VisualDataModel::model
284 This property holds the model providing data for the VisualDataModel.
286 The model provides a set of data that is used to create the items
287 for a view. For large or dynamic datasets the model is usually
288 provided by a C++ model object. The C++ model object must be a \l
289 {QAbstractItemModel} subclass or a simple list.
291 Models can also be created directly in QML, using a \l{ListModel} or
294 \sa {qmlmodels}{Data Models}
296 QVariant QQuickVisualDataModel::model() const
298 Q_D(const QQuickVisualDataModel);
299 return d->m_adaptorModel.model();
302 void QQuickVisualDataModel::setModel(const QVariant &model)
304 Q_D(QQuickVisualDataModel);
307 _q_itemsRemoved(0, d->m_count);
309 d->m_adaptorModel.setModel(model, this, d->m_context->engine());
310 d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
311 for (int i = 0; d->m_parts && i < d->m_parts->models.count(); ++i) {
312 d->m_adaptorModel.replaceWatchedRoles(
313 QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
317 _q_itemsInserted(0, d->m_adaptorModel.count());
318 if (d->m_adaptorModel.canFetchMore())
319 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
324 \qmlproperty Component QtQuick2::VisualDataModel::delegate
326 The delegate provides a template defining each item instantiated by a view.
327 The index is exposed as an accessible \c index property. Properties of the
328 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
330 QQmlComponent *QQuickVisualDataModel::delegate() const
332 Q_D(const QQuickVisualDataModel);
333 return d->m_delegate;
336 void QQuickVisualDataModel::setDelegate(QQmlComponent *delegate)
338 Q_D(QQuickVisualDataModel);
339 if (d->m_transaction) {
340 qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
343 bool wasValid = d->m_delegate != 0;
344 d->m_delegate = delegate;
345 d->m_delegateValidated = false;
346 if (wasValid && d->m_complete) {
347 for (int i = 1; i < d->m_groupCount; ++i) {
348 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
349 0, d->m_compositor.count(Compositor::Group(i)));
352 if (d->m_complete && d->m_delegate) {
353 for (int i = 1; i < d->m_groupCount; ++i) {
354 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
355 0, d->m_compositor.count(Compositor::Group(i)));
362 \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
364 QAbstractItemModel provides a hierarchical tree of data, whereas
365 QML only operates on list data. \c rootIndex allows the children of
366 any node in a QAbstractItemModel to be provided by this model.
368 This property only affects models of type QAbstractItemModel that
369 are hierarchical (e.g, a tree model).
371 For example, here is a simple interactive file system browser.
372 When a directory name is clicked, the view's \c rootIndex is set to the
373 QModelIndex node of the clicked directory, thus updating the view to show
374 the new directory's contents.
377 \snippet qml/visualdatamodel_rootindex/main.cpp 0
380 \snippet qml/visualdatamodel_rootindex/view.qml 0
382 If the \l model is a QAbstractItemModel subclass, the delegate can also
383 reference a \c hasModelChildren property (optionally qualified by a
384 \e model. prefix) that indicates whether the delegate's model item has
388 \sa modelIndex(), parentModelIndex()
390 QVariant QQuickVisualDataModel::rootIndex() const
392 Q_D(const QQuickVisualDataModel);
393 return QVariant::fromValue(d->m_adaptorModel.rootIndex);
396 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
398 Q_D(QQuickVisualDataModel);
400 QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
401 if (d->m_adaptorModel.rootIndex != modelIndex) {
402 const int oldCount = d->m_count;
403 d->m_adaptorModel.rootIndex = modelIndex;
404 if (d->m_adaptorModel.canFetchMore())
405 d->m_adaptorModel.fetchMore();
407 const int newCount = d->m_adaptorModel.count();
409 _q_itemsRemoved(0, oldCount);
411 _q_itemsInserted(0, newCount);
413 emit rootIndexChanged();
418 \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
420 QAbstractItemModel provides a hierarchical tree of data, whereas
421 QML only operates on list data. This function assists in using
424 Returns a QModelIndex for the specified index.
425 This value can be assigned to rootIndex.
429 QVariant QQuickVisualDataModel::modelIndex(int idx) const
431 Q_D(const QQuickVisualDataModel);
432 return d->m_adaptorModel.modelIndex(idx);
436 \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
438 QAbstractItemModel provides a hierarchical tree of data, whereas
439 QML only operates on list data. This function assists in using
442 Returns a QModelIndex for the parent of the current rootIndex.
443 This value can be assigned to rootIndex.
447 QVariant QQuickVisualDataModel::parentModelIndex() const
449 Q_D(const QQuickVisualDataModel);
450 return d->m_adaptorModel.parentModelIndex();
454 \qmlproperty int QtQuick2::VisualDataModel::count
457 int QQuickVisualDataModel::count() const
459 Q_D(const QQuickVisualDataModel);
462 return d->m_compositor.count(d->m_compositorGroup);
465 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
467 QQuickVisualDataModel::ReleaseFlags stat = 0;
471 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(object)) {
472 if (cacheItem->releaseObject()) {
473 cacheItem->destroyObject();
474 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
475 emitDestroyingItem(item);
476 if (cacheItem->incubationTask) {
477 releaseIncubator(cacheItem->incubationTask);
478 cacheItem->incubationTask = 0;
480 cacheItem->Dispose();
481 stat |= QQuickVisualModel::Destroyed;
483 stat |= QQuickVisualDataModel::Referenced;
490 Returns ReleaseStatus flags.
493 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
495 Q_D(QQuickVisualDataModel);
496 QQuickVisualModel::ReleaseFlags stat = d->release(item);
497 if (stat & Destroyed)
498 item->setParentItem(0);
502 // Cancel a requested async item
503 void QQuickVisualDataModel::cancel(int index)
505 Q_D(QQuickVisualDataModel);
506 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
507 qWarning() << "VisualDataModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
511 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
512 QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
514 if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
515 d->releaseIncubator(cacheItem->incubationTask);
516 cacheItem->incubationTask = 0;
518 if (cacheItem->object) {
519 QObject *object = cacheItem->object;
520 cacheItem->destroyObject();
521 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
522 d->emitDestroyingItem(item);
523 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
524 d->emitDestroyingPackage(package);
527 cacheItem->scriptRef -= 1;
529 if (!cacheItem->isReferenced()) {
530 d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
531 d->m_cache.removeAt(it.cacheIndex);
533 Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
538 void QQuickVisualDataModelPrivate::group_append(
539 QQmlListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
541 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
544 if (d->m_groupCount == Compositor::MaximumGroupCount) {
545 qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
548 d->m_groups[d->m_groupCount] = group;
549 d->m_groupCount += 1;
552 int QQuickVisualDataModelPrivate::group_count(
553 QQmlListProperty<QQuickVisualDataGroup> *property)
555 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
556 return d->m_groupCount - 1;
559 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
560 QQmlListProperty<QQuickVisualDataGroup> *property, int index)
562 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
563 return index >= 0 && index < d->m_groupCount - 1
564 ? d->m_groups[index + 1]
569 \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
571 This property holds a visual data model's group definitions.
573 Groups define a sub-set of the items in a visual data model and can be used to filter
576 For every group defined in a VisualDataModel two attached properties are added to each
577 delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
578 item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
579 index of the item in that group.
581 The following example illustrates using groups to select items in a model.
583 \snippet qml/visualdatagroup.qml 0
586 QQmlListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
588 Q_D(QQuickVisualDataModel);
589 return QQmlListProperty<QQuickVisualDataGroup>(
592 QQuickVisualDataModelPrivate::group_append,
593 QQuickVisualDataModelPrivate::group_count,
594 QQuickVisualDataModelPrivate::group_at);
598 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
600 This property holds visual data model's default group to which all new items are added.
603 QQuickVisualDataGroup *QQuickVisualDataModel::items()
605 Q_D(QQuickVisualDataModel);
610 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
612 This property holds visual data model's persisted items group.
614 Items in this group are not destroyed when released by a view, instead they are persisted
615 until removed from the group.
617 An item can be removed from the persistedItems group by setting the
618 VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
619 at that time it will be destroyed. Adding an item to this group will not create a new
622 Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
626 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
628 Q_D(QQuickVisualDataModel);
629 return d->m_persistedItems;
633 \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
635 This property holds the name of the group used to filter the visual data model.
637 Only items which belong to this group are visible to a view.
639 By default this is the \l items group.
642 QString QQuickVisualDataModel::filterGroup() const
644 Q_D(const QQuickVisualDataModel);
645 return d->m_filterGroup;
648 void QQuickVisualDataModel::setFilterGroup(const QString &group)
650 Q_D(QQuickVisualDataModel);
652 if (d->m_transaction) {
653 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
657 if (d->m_filterGroup != group) {
658 d->m_filterGroup = group;
659 d->updateFilterGroup();
660 emit filterGroupChanged();
664 void QQuickVisualDataModel::resetFilterGroup()
666 setFilterGroup(QStringLiteral("items"));
669 void QQuickVisualDataModelPrivate::updateFilterGroup()
671 Q_Q(QQuickVisualDataModel);
672 if (!m_cacheMetaType)
675 QQuickListCompositor::Group previousGroup = m_compositorGroup;
676 m_compositorGroup = Compositor::Default;
677 for (int i = 1; i < m_groupCount; ++i) {
678 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
679 m_compositorGroup = Compositor::Group(i);
684 QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
685 if (m_compositorGroup != previousGroup) {
686 QVector<QQuickChangeSet::Remove> removes;
687 QVector<QQuickChangeSet::Insert> inserts;
688 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
690 QQuickChangeSet changeSet;
691 changeSet.apply(removes, inserts);
692 emit q->modelUpdated(changeSet, false);
694 if (changeSet.difference() != 0)
695 emit q->countChanged();
698 foreach (QQuickVisualPartsModel *model, m_parts->models)
699 model->updateFilterGroup(m_compositorGroup, changeSet);
705 \qmlproperty object QtQuick2::VisualDataModel::parts
707 The \a parts property selects a VisualDataModel which creates
708 delegates from the part named. This is used in conjunction with
709 the \l Package element.
711 For example, the code below selects a model which creates
712 delegates named \e list from a \l Package:
718 Item { Package.name: "list" }
724 width: 200; height:200
725 model: visualModel.parts.list
732 QObject *QQuickVisualDataModel::parts()
734 Q_D(QQuickVisualDataModel);
736 d->m_parts = new QQuickVisualDataModelParts(this);
740 void QQuickVisualDataModelPrivate::emitCreatedPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
742 for (int i = 1; i < m_groupCount; ++i)
743 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
746 void QQuickVisualDataModelPrivate::emitInitPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
748 for (int i = 1; i < m_groupCount; ++i)
749 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
752 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
754 for (int i = 1; i < m_groupCount; ++i)
755 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
758 void QVDMIncubationTask::statusChanged(Status status)
760 vdm->incubatorStatusChanged(this, status);
763 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
765 Q_Q(QQuickVisualDataModel);
766 if (!incubationTask->isError())
767 incubationTask->clear();
768 m_finishedIncubating.append(incubationTask);
769 if (!m_incubatorCleanupScheduled) {
770 m_incubatorCleanupScheduled = true;
771 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
775 void QQuickVisualDataModelPrivate::removeCacheItem(QQuickVisualDataModelItem *cacheItem)
777 int cidx = m_cache.indexOf(cacheItem);
779 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
780 m_cache.removeAt(cidx);
782 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
785 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
787 Q_Q(QQuickVisualDataModel);
788 if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
791 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
792 cacheItem->incubationTask = 0;
793 incubationTask->incubating = 0;
794 releaseIncubator(incubationTask);
796 if (status == QQmlIncubator::Ready) {
797 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
798 emitCreatedItem(incubationTask, item);
799 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
800 emitCreatedPackage(incubationTask, package);
801 } else if (status == QQmlIncubator::Error) {
802 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
805 if (!cacheItem->isObjectReferenced()) {
806 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
807 emitDestroyingItem(item);
808 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
809 emitDestroyingPackage(package);
810 delete cacheItem->object;
811 cacheItem->object = 0;
812 cacheItem->scriptRef -= 1;
813 cacheItem->contextData->destroy();
814 cacheItem->contextData = 0;
815 if (!cacheItem->isReferenced()) {
816 removeCacheItem(cacheItem);
822 void QVDMIncubationTask::setInitialState(QObject *o)
824 vdm->setInitialState(this, o);
827 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
829 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
830 cacheItem->object = o;
832 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
833 emitInitItem(incubationTask, item);
834 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
835 emitInitPackage(incubationTask, package);
838 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous)
840 Q_Q(QQuickVisualDataModel);
841 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
842 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
846 Compositor::iterator it = m_compositor.find(group, index);
848 QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
851 cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), it.modelIndex());
855 cacheItem->groups = it->flags;
857 m_cache.insert(it.cacheIndex, cacheItem);
858 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
859 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
862 // Bump the reference counts temporarily so neither the content data or the delegate object
863 // are deleted if incubatorStatusChanged() is called synchronously.
864 cacheItem->scriptRef += 1;
865 cacheItem->referenceObject();
867 if (cacheItem->incubationTask) {
868 if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
869 // previously requested async - now needed immediately
870 cacheItem->incubationTask->forceCompletion();
872 } else if (!cacheItem->object) {
873 QQmlContext *creationContext = m_delegate->creationContext();
875 cacheItem->scriptRef += 1;
877 cacheItem->incubationTask = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
878 cacheItem->incubationTask->incubating = cacheItem;
879 cacheItem->incubationTask->clear();
881 for (int i = 1; i < m_groupCount; ++i)
882 cacheItem->incubationTask->index[i] = it.index[i];
884 QQmlContextData *ctxt = new QQmlContextData;
885 ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context));
886 ctxt->contextObject = cacheItem;
887 cacheItem->contextData = ctxt;
889 if (m_adaptorModel.hasProxyObject()) {
890 if (QQuickVisualAdaptorModelProxyInterface *proxy
891 = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
892 ctxt = new QQmlContextData;
893 ctxt->setParent(cacheItem->contextData, true);
894 ctxt->contextObject = proxy->proxiedObject();
898 cacheItem->incubateObject(
902 QQmlContextData::get(m_context));
905 if (index == m_compositor.count(group) - 1 && m_adaptorModel.canFetchMore())
906 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
908 // Remove the temporary reference count.
909 cacheItem->scriptRef -= 1;
910 if (cacheItem->object)
911 return cacheItem->object;
913 cacheItem->releaseObject();
914 if (!cacheItem->isReferenced()) {
915 removeCacheItem(cacheItem);
923 If asynchronous is true or the component is being loaded asynchronously due
924 to an ancestor being loaded asynchronously, item() may return 0. In this
925 case itemCreated() will be emitted when the item is available. The item
926 at this stage does not have any references, so item() must be called again
927 to ensure a reference is held. Any call to item() which returns a valid item
928 must be matched by a call to release() in order to destroy the item.
930 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
932 Q_D(QQuickVisualDataModel);
933 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
934 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
938 QObject *object = d->object(d->m_compositorGroup, index, asynchronous);
942 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
946 if (!d->m_delegateValidated) {
948 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
949 d->m_delegateValidated = true;
954 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
956 Compositor::iterator it = m_compositor.find(group, index);
957 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
959 int dot = name.indexOf(QLatin1Char('.'));
961 role = name.left(dot);
962 QVariant value = model->value(it.modelIndex(), role);
964 QObject *obj = qvariant_cast<QObject*>(value);
968 dot = name.indexOf(QLatin1Char('.'), from);
969 value = obj->property(name.mid(from, dot-from).toUtf8());
971 return value.toString();
976 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
978 Q_D(QQuickVisualDataModel);
979 return d->stringValue(d->m_compositorGroup, index, name);
982 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
984 Q_D(const QQuickVisualDataModel);
985 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
986 return cacheItem->groupIndex(d->m_compositorGroup);
990 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
992 Q_D(QQuickVisualDataModel);
993 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
994 d->m_watchedRoles = roles;
997 void QQuickVisualDataModelPrivate::addGroups(
998 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1000 QVector<Compositor::Insert> inserts;
1001 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1002 itemsInserted(inserts);
1006 void QQuickVisualDataModelPrivate::removeGroups(
1007 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1009 QVector<Compositor::Remove> removes;
1010 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
1011 itemsRemoved(removes);
1015 void QQuickVisualDataModelPrivate::setGroups(
1016 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1018 QVector<Compositor::Remove> removes;
1019 QVector<Compositor::Insert> inserts;
1021 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1022 itemsInserted(inserts);
1023 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1025 from = m_compositor.find(from.group, from.index[from.group]);
1026 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1027 itemsRemoved(removes);
1031 bool QQuickVisualDataModel::event(QEvent *e)
1033 Q_D(QQuickVisualDataModel);
1034 if (e->type() == QEvent::UpdateRequest) {
1035 d->m_adaptorModel.fetchMore();
1036 } else if (e->type() == QEvent::User) {
1037 d->m_incubatorCleanupScheduled = false;
1038 qDeleteAll(d->m_finishedIncubating);
1039 d->m_finishedIncubating.clear();
1041 return QQuickVisualModel::event(e);
1044 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1049 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1051 foreach (const Compositor::Change &change, changes) {
1052 for (int i = 1; i < m_groupCount; ++i) {
1053 if (change.inGroup(i)) {
1054 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
1059 for (int i = 1; i < m_groupCount; ++i)
1060 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1063 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QList<int> &roles)
1065 Q_D(QQuickVisualDataModel);
1066 if (count <= 0 || !d->m_complete)
1069 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1070 QVector<Compositor::Change> changes;
1071 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1072 d->itemsChanged(changes);
1077 static void incrementIndexes(QQuickVisualDataModelItem *cacheItem, int count, const int *deltas)
1079 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1080 for (int i = 1; i < count; ++i)
1081 incubationTask->index[i] += deltas[i];
1083 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1084 for (int i = 1; i < count; ++i)
1085 attached->m_currentIndex[i] += deltas[i];
1089 void QQuickVisualDataModelPrivate::itemsInserted(
1090 const QVector<Compositor::Insert> &inserts,
1091 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1092 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1096 int inserted[Compositor::MaximumGroupCount];
1097 for (int i = 1; i < m_groupCount; ++i)
1100 foreach (const Compositor::Insert &insert, inserts) {
1101 for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
1102 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1104 for (int i = 1; i < m_groupCount; ++i) {
1105 if (insert.inGroup(i)) {
1106 (*translatedInserts)[i].append(
1107 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1108 inserted[i] += insert.count;
1112 if (!insert.inCache())
1115 if (movedItems && insert.isMove()) {
1116 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1117 Q_ASSERT(items.count() == insert.count);
1118 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1120 if (insert.inGroup()) {
1121 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1122 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1123 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1125 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1126 for (int i = 1; i < m_groupCount; ++i)
1127 incubationTask->index[i] = cacheItem->groups & (1 << i)
1128 ? insert.index[i] + offset
1131 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1132 for (int i = 1; i < m_groupCount; ++i)
1133 attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1134 ? insert.index[i] + offset
1139 cacheIndex = insert.cacheIndex + insert.count;
1142 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1143 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1146 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1148 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1149 itemsInserted(inserts, &translatedInserts);
1150 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1154 for (int i = 1; i < m_groupCount; ++i)
1155 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1158 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1161 Q_D(QQuickVisualDataModel);
1162 if (count <= 0 || !d->m_complete)
1165 d->m_count += count;
1167 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1168 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1169 if (item->modelIndex() >= index)
1170 item->setModelIndex(item->modelIndex() + count);
1173 QVector<Compositor::Insert> inserts;
1174 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1175 d->itemsInserted(inserts);
1179 void QQuickVisualDataModelPrivate::itemsRemoved(
1180 const QVector<Compositor::Remove> &removes,
1181 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1182 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1185 int removedCache = 0;
1187 int removed[Compositor::MaximumGroupCount];
1188 for (int i = 1; i < m_groupCount; ++i)
1191 foreach (const Compositor::Remove &remove, removes) {
1192 for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
1193 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1195 for (int i = 1; i < m_groupCount; ++i) {
1196 if (remove.inGroup(i)) {
1197 (*translatedRemoves)[i].append(
1198 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1199 removed[i] -= remove.count;
1203 if (!remove.inCache())
1206 if (movedItems && remove.isMove()) {
1207 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1208 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1209 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1210 m_cache.erase(begin, end);
1212 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1213 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1214 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1215 QObject *object = cacheItem->object;
1216 cacheItem->destroyObject();
1217 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1218 emitDestroyingPackage(package);
1219 else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
1220 emitDestroyingItem(item);
1221 cacheItem->scriptRef -= 1;
1223 if (!cacheItem->isReferenced()) {
1224 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1225 m_cache.removeAt(cacheIndex);
1229 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1230 } else if (remove.groups() == cacheItem->groups) {
1231 cacheItem->groups = 0;
1232 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1233 for (int i = 1; i < m_groupCount; ++i)
1234 incubationTask->index[i] = -1;
1236 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1237 for (int i = 1; i < m_groupCount; ++i)
1238 attached->m_currentIndex[i] = -1;
1241 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1242 for (int i = 1; i < m_groupCount; ++i) {
1243 if (remove.inGroup(i))
1244 incubationTask->index[i] = remove.index[i];
1247 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1248 for (int i = 1; i < m_groupCount; ++i) {
1249 if (remove.inGroup(i))
1250 attached->m_currentIndex[i] = remove.index[i];
1253 cacheItem->groups &= ~remove.flags;
1259 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1260 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1263 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1265 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1266 itemsRemoved(removes, &translatedRemoves);
1267 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1271 for (int i = 1; i < m_groupCount; ++i)
1272 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1275 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1277 Q_D(QQuickVisualDataModel);
1278 if (count <= 0|| !d->m_complete)
1281 d->m_count -= count;
1283 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1284 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1285 if (item->modelIndex() >= index + count)
1286 item->setModelIndex(item->modelIndex() - count);
1287 else if (item->modelIndex() >= index)
1288 item->setModelIndex(-1);
1291 QVector<Compositor::Remove> removes;
1292 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1293 d->itemsRemoved(removes);
1298 void QQuickVisualDataModelPrivate::itemsMoved(
1299 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1301 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1303 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1304 itemsRemoved(removes, &translatedRemoves, &movedItems);
1306 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1307 itemsInserted(inserts, &translatedInserts, &movedItems);
1308 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1309 Q_ASSERT(movedItems.isEmpty());
1313 for (int i = 1; i < m_groupCount; ++i) {
1314 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1315 translatedRemoves.at(i),
1316 translatedInserts.at(i));
1320 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1322 Q_D(QQuickVisualDataModel);
1323 if (count <= 0 || !d->m_complete)
1326 const int minimum = qMin(from, to);
1327 const int maximum = qMax(from, to) + count;
1328 const int difference = from > to ? count : -count;
1330 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1331 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1332 if (item->modelIndex() >= from && item->modelIndex() < from + count)
1333 item->setModelIndex(item->modelIndex() - from + to);
1334 else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1335 item->setModelIndex(item->modelIndex() + difference);
1338 QVector<Compositor::Remove> removes;
1339 QVector<Compositor::Insert> inserts;
1340 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1341 d->itemsMoved(removes, inserts);
1345 template <typename T> v8::Local<v8::Array>
1346 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1348 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1349 v8::Local<v8::String> indexKey = v8::String::New("index");
1350 v8::Local<v8::String> countKey = v8::String::New("count");
1351 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1353 for (int i = 0; i < changes.count(); ++i) {
1354 v8::Local<v8::Object> object = v8::Object::New();
1355 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1356 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1357 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1358 indexes->Set(i, object);
1363 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1365 Q_Q(QQuickVisualDataModel);
1366 emit q->modelUpdated(changeSet, reset);
1367 if (changeSet.difference() != 0)
1368 emit q->countChanged();
1371 void QQuickVisualDataModelPrivate::emitChanges()
1373 if (m_transaction || !m_complete)
1376 m_transaction = true;
1377 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1378 for (int i = 1; i < m_groupCount; ++i)
1379 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1380 m_transaction = false;
1382 const bool reset = m_reset;
1384 for (int i = 1; i < m_groupCount; ++i)
1385 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1387 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1388 if (cacheItem->attached)
1389 cacheItem->attached->emitChanges();
1393 void QQuickVisualDataModel::_q_modelReset()
1395 Q_D(QQuickVisualDataModel);
1399 int oldCount = d->m_count;
1400 d->m_adaptorModel.rootIndex = QModelIndex();
1402 if (d->m_complete) {
1403 d->m_count = d->m_adaptorModel.count();
1405 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1406 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1407 if (item->modelIndex() != -1)
1408 item->setModelIndex(-1);
1411 QVector<Compositor::Remove> removes;
1412 QVector<Compositor::Insert> inserts;
1414 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1416 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1417 d->itemsMoved(removes, inserts);
1420 if (d->m_adaptorModel.canFetchMore())
1421 d->m_adaptorModel.fetchMore();
1425 emit rootIndexChanged();
1428 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1430 Q_D(QQuickVisualDataModel);
1431 if (parent == d->m_adaptorModel.rootIndex)
1432 _q_itemsInserted(begin, end - begin + 1);
1435 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1437 Q_D(QQuickVisualDataModel);
1438 if (parent == d->m_adaptorModel.rootIndex)
1439 _q_itemsRemoved(begin, end - begin + 1);
1442 void QQuickVisualDataModel::_q_rowsMoved(
1443 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1444 const QModelIndex &destinationParent, int destinationRow)
1446 Q_D(QQuickVisualDataModel);
1447 const int count = sourceEnd - sourceStart + 1;
1448 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1449 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1450 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1451 _q_itemsRemoved(sourceStart, count);
1452 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1453 _q_itemsInserted(destinationRow, count);
1457 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1459 Q_D(QQuickVisualDataModel);
1460 if (begin.parent() == d->m_adaptorModel.rootIndex)
1461 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, QList<int>());
1464 void QQuickVisualDataModel::_q_layoutChanged()
1466 Q_D(QQuickVisualDataModel);
1467 _q_itemsChanged(0, d->m_count, QList<int>());
1470 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1472 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1473 if (cacheItem->object == obj) { // Don't create attached item for child objects.
1474 cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1475 return cacheItem->attached;
1478 return new QQuickVisualDataModelAttached(obj);
1481 bool QQuickVisualDataModelPrivate::insert(
1482 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1484 QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1488 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1489 for (uint i = 0; i < propertyNames->Length(); ++i) {
1490 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1491 cacheItem->setValue(
1492 m_cacheMetaType->v8Engine->toString(propertyName),
1493 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1496 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1498 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1499 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1501 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1502 m_cache.insert(before.cacheIndex, cacheItem);
1507 //============================================================================
1509 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1510 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1512 , groupCount(groupNames.count() + 1)
1515 , groupNames(groupNames)
1519 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1522 metaObject->release();
1523 qPersistentDispose(constructor);
1526 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1528 QMetaObjectBuilder builder;
1529 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1530 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1531 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1534 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1535 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1536 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1537 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1538 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1539 propertyName.toUtf8(), "bool", notifierId);
1540 propertyBuilder.setWritable(true);
1542 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1543 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1544 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1545 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1546 propertyName.toUtf8(), "int", notifierId);
1547 propertyBuilder.setWritable(true);
1550 metaObject = new QQuickVisualDataModelAttachedMetaObject(this, builder.toMetaObject());
1553 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1555 v8::HandleScope handleScope;
1556 v8::Context::Scope contextScope(v8Engine->context());
1558 QQuickVisualDataModelEngineData *data = engineData(v8Engine);
1560 constructor = qPersistentNew(v8::ObjectTemplate::New());
1562 constructor->SetHasExternalResource(true);
1563 constructor->SetAccessor(data->model(), get_model);
1564 constructor->SetAccessor(data->groups(), get_groups, set_groups);
1565 constructor->SetAccessor(data->isUnresolved(), get_member, 0, v8::Int32::New(30));
1566 constructor->SetAccessor(data->inItems(), get_member, set_member, v8::Int32::New(1));
1567 constructor->SetAccessor(data->inPersistedItems(), get_member, set_member, v8::Int32::New(2));
1568 constructor->SetAccessor(data->itemsIndex(), get_index, 0, v8::Int32::New(1));
1569 constructor->SetAccessor(data->persistedItemsIndex(), get_index, 0, v8::Int32::New(2));
1571 for (int i = 2; i < groupNames.count(); ++i) {
1572 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1573 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1574 constructor->SetAccessor(
1575 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1577 for (int i = 2; i < groupNames.count(); ++i) {
1578 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1579 constructor->SetAccessor(
1580 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1584 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1587 foreach (const QString &groupName, groups) {
1588 int index = groupNames.indexOf(groupName);
1590 groupFlags |= 2 << index;
1595 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1598 if (groups->IsString()) {
1599 const QString groupName = v8Engine->toString(groups);
1600 int index = groupNames.indexOf(groupName);
1602 groupFlags |= 2 << index;
1603 } else if (groups->IsArray()) {
1604 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1605 for (uint i = 0; i < array->Length(); ++i) {
1606 const QString groupName = v8Engine->toString(array->Get(i));
1607 int index = groupNames.indexOf(groupName);
1609 groupFlags |= 2 << index;
1615 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1617 static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1618 qPersistentDispose(object);
1621 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1623 static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1624 qPersistentDispose(object);
1627 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1628 v8::Local<v8::String>, const v8::AccessorInfo &info)
1630 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1632 V8THROW_ERROR("Not a valid VisualData object");
1633 if (!cacheItem->metaType->model)
1634 return v8::Undefined();
1636 if (cacheItem->modelHandle.IsEmpty()) {
1637 cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1638 cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1640 ++cacheItem->scriptRef;
1643 return cacheItem->modelHandle;
1646 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1647 v8::Local<v8::String>, const v8::AccessorInfo &info)
1649 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1651 V8THROW_ERROR("Not a valid VisualData object");
1654 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1655 if (cacheItem->groups & (1 << i))
1656 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1659 return cacheItem->engine->fromVariant(groups);
1662 void QQuickVisualDataModelItemMetaType::set_groups(
1663 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1665 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1667 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1669 if (!cacheItem->metaType->model)
1671 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1673 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1674 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1675 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1676 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1679 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1680 v8::Local<v8::String>, const v8::AccessorInfo &info)
1682 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1684 V8THROW_ERROR("Not a valid VisualData object");
1686 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1689 void QQuickVisualDataModelItemMetaType::set_member(
1690 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1692 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1694 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1696 if (!cacheItem->metaType->model)
1698 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1700 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1701 const bool member = value->BooleanValue();
1702 const int groupFlag = (1 << group);
1703 if (member == ((cacheItem->groups & groupFlag) != 0))
1706 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1707 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1709 model->addGroups(it, 1, Compositor::Cache, groupFlag);
1711 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
1714 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1715 v8::Local<v8::String>, const v8::AccessorInfo &info)
1717 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1719 V8THROW_ERROR("Not a valid VisualData object");
1721 return v8::Integer::New(cacheItem->groupIndex(Compositor::Group(info.Data()->Int32Value())));
1725 //---------------------------------------------------------------------------
1727 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1728 QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1729 : QV8ObjectResource(metaType->v8Engine)
1730 , metaType(metaType)
1743 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1745 Q_ASSERT(scriptRef == 0);
1746 Q_ASSERT(objectRef == 0);
1748 Q_ASSERT(indexHandle.IsEmpty());
1749 Q_ASSERT(modelHandle.IsEmpty());
1751 if (incubationTask && metaType->model)
1752 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1754 metaType->release();
1758 void QQuickVisualDataModelItem::Dispose()
1764 if (metaType->model) {
1765 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1766 model->removeCacheItem(this);
1772 This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1773 arguments instead of QQmlContext which means we don't have to construct the rather weighty
1774 wrapper class for every delegate item.
1776 void QQuickVisualDataModelItem::incubateObject(
1777 QQmlComponent *component,
1779 QQmlContextData *context,
1780 QQmlContextData *forContext)
1782 QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
1783 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
1784 QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
1786 incubatorPriv->compiledData = componentPriv->cc;
1787 incubatorPriv->compiledData->addref();
1788 incubatorPriv->vme.init(
1791 componentPriv->start,
1792 componentPriv->creationContext);
1794 enginePriv->incubate(*incubationTask, forContext);
1797 void QQuickVisualDataModelItem::destroyObject()
1800 Q_ASSERT(contextData);
1802 QObjectPrivate *p = QObjectPrivate::get(object);
1803 Q_ASSERT(p->declarativeData);
1804 QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1805 if (data->ownContext && data->context)
1806 data->context->clearContext();
1807 object->deleteLater();
1810 attached->m_cacheItem = 0;
1814 contextData->destroy();
1819 QQuickVisualDataModelItem *QQuickVisualDataModelItem::dataForObject(QObject *object)
1821 QObjectPrivate *p = QObjectPrivate::get(object);
1822 QQmlContextData *context = p->declarativeData
1823 ? static_cast<QQmlData *>(p->declarativeData)->context
1825 for (context = context ? context->parent : 0; context; context = context->parent) {
1826 if (QQuickVisualDataModelItem *cacheItem = qobject_cast<QQuickVisualDataModelItem *>(
1827 context->contextObject)) {
1834 int QQuickVisualDataModelItem::groupIndex(Compositor::Group group)
1836 if (QQuickVisualDataModelPrivate * const model = metaType->model
1837 ? QQuickVisualDataModelPrivate::get(metaType->model)
1839 return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
1844 //---------------------------------------------------------------------------
1846 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1847 QQuickVisualDataModelItemMetaType *metaType, QMetaObject *metaObject)
1848 : metaType(metaType)
1849 , metaObject(metaObject)
1850 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1851 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
1853 // Don't reference count the meta-type here as that would create a circular reference.
1854 // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
1855 // destroying all delegates with attached objects.
1856 *static_cast<QMetaObject *>(this) = *metaObject;
1859 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1864 void QQuickVisualDataModelAttachedMetaObject::objectDestroyed(QObject *)
1869 int QQuickVisualDataModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
1871 QQuickVisualDataModelAttached *attached = static_cast<QQuickVisualDataModelAttached *>(object);
1872 if (call == QMetaObject::ReadProperty) {
1873 if (_id >= indexPropertyOffset) {
1874 Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
1875 *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
1877 } else if (_id >= memberPropertyOffset) {
1878 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1879 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1882 } else if (call == QMetaObject::WriteProperty) {
1883 if (_id >= memberPropertyOffset) {
1884 if (!metaType->model)
1886 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1887 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1888 const int groupFlag = 1 << group;
1889 const bool member = attached->m_cacheItem->groups & groupFlag;
1890 if (member && !*static_cast<bool *>(arguments[0])) {
1891 Compositor::iterator it = model->m_compositor.find(
1892 group, attached->m_currentIndex[group]);
1893 model->removeGroups(it, 1, group, groupFlag);
1894 } else if (!member && *static_cast<bool *>(arguments[0])) {
1895 for (int i = 1; i < metaType->groupCount; ++i) {
1896 if (attached->m_cacheItem->groups & (1 << i)) {
1897 Compositor::iterator it = model->m_compositor.find(
1898 Compositor::Group(i), attached->m_currentIndex[i]);
1899 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1907 return attached->qt_metacall(call, _id, arguments);
1910 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1912 , m_previousGroups(0)
1913 , m_modelChanged(false)
1915 QQml_setParent_noEvent(this, parent);
1918 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1919 QQuickVisualDataModelItem *cacheItem, QObject *parent)
1920 : m_cacheItem(cacheItem)
1921 , m_previousGroups(cacheItem->groups)
1922 , m_modelChanged(false)
1924 QQml_setParent_noEvent(this, parent);
1925 if (QVDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
1926 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1927 m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
1929 QQuickVisualDataModelPrivate * const model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1930 Compositor::iterator it = model->m_compositor.find(
1931 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
1932 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1933 m_currentIndex[i] = m_previousIndex[i] = it.index[i];
1936 if (!cacheItem->metaType->metaObject)
1937 cacheItem->metaType->initializeMetaObject();
1939 QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
1940 cacheItem->metaType->metaObject->addref();
1944 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1946 This attached property holds the visual data model this delegate instance belongs to.
1948 It is attached to each instance of the delegate.
1951 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1953 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1957 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1959 This attached property holds the name of VisualDataGroups the item belongs to.
1961 It is attached to each instance of the delegate.
1964 QStringList QQuickVisualDataModelAttached::groups() const
1970 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1971 if (m_cacheItem->groups & (1 << i))
1972 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1977 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1982 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1984 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1985 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1986 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1987 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1990 bool QQuickVisualDataModelAttached::isUnresolved() const
1995 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1999 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
2001 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
2003 Changing this property will add or remove the item from the items group.
2005 It is attached to each instance of the delegate.
2009 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
2011 This attached property holds the index of the item in the default \l items VisualDataGroup.
2013 It is attached to each instance of the delegate.
2017 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
2019 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
2021 Changing this property will add or remove the item from the items group. Change with caution
2022 as removing an item from the persistedItems group will destroy the current instance if it is
2023 not referenced by a model.
2025 It is attached to each instance of the delegate.
2029 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
2031 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
2033 It is attached to each instance of the delegate.
2036 void QQuickVisualDataModelAttached::emitChanges()
2038 if (m_modelChanged) {
2039 m_modelChanged = false;
2040 emit modelChanged();
2043 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2044 m_previousGroups = m_cacheItem->groups;
2046 int indexChanges = 0;
2047 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2048 if (m_previousIndex[i] != m_currentIndex[i]) {
2049 m_previousIndex[i] = m_currentIndex[i];
2050 indexChanges |= (1 << i);
2055 const QMetaObject *meta = metaObject();
2056 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2057 if (groupChanges & (1 << i))
2058 QMetaObject::activate(this, meta, notifierId, 0);
2060 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2061 if (indexChanges & (1 << i))
2062 QMetaObject::activate(this, meta, notifierId, 0);
2066 emit groupsChanged();
2069 //============================================================================
2071 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
2078 bool QQuickVisualDataGroupPrivate::isChangedConnected()
2080 Q_Q(QQuickVisualDataGroup);
2081 IS_SIGNAL_CONNECTED(q, QQuickVisualDataGroup, changed, (const QQmlV8Handle &,const QQmlV8Handle &));
2084 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
2086 Q_Q(QQuickVisualDataGroup);
2087 if (isChangedConnected() && !changeSet.isEmpty()) {
2088 v8::HandleScope handleScope;
2089 v8::Context::Scope contextScope(engine->context());
2090 v8::Local<v8::Object> removed = engineData(engine)->array(engine, changeSet.removes());
2091 v8::Local<v8::Object> inserted = engineData(engine)->array(engine, changeSet.inserts());
2092 emit q->changed(QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
2094 if (changeSet.difference() != 0)
2095 emit q->countChanged();
2098 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
2100 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2101 it->emitModelUpdated(changeSet, reset);
2105 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
2107 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2108 it->createdPackage(index, package);
2111 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
2113 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2114 it->initPackage(index, package);
2117 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
2119 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2120 it->destroyingPackage(package);
2124 \qmlclass VisualDataGroup QQuickVisualDataGroup
2125 \inqmlmodule QtQuick 2
2126 \ingroup qtquick-models
2127 \brief Encapsulates a filtered set of visual data items
2131 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2132 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2136 QQuickVisualDataGroup::QQuickVisualDataGroup(
2137 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2138 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2140 Q_D(QQuickVisualDataGroup);
2142 d->setModel(model, Compositor::Group(index));
2145 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2150 \qmlproperty string QtQuick2::VisualDataGroup::name
2152 This property holds the name of the group.
2154 Each group in a model must have a unique name starting with a lower case letter.
2157 QString QQuickVisualDataGroup::name() const
2159 Q_D(const QQuickVisualDataGroup);
2163 void QQuickVisualDataGroup::setName(const QString &name)
2165 Q_D(QQuickVisualDataGroup);
2168 if (d->name != name) {
2175 \qmlproperty int QtQuick2::VisualDataGroup::count
2177 This property holds the number of items in the group.
2180 int QQuickVisualDataGroup::count() const
2182 Q_D(const QQuickVisualDataGroup);
2185 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2189 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2191 This property holds whether new items are assigned to this group by default.
2194 bool QQuickVisualDataGroup::defaultInclude() const
2196 Q_D(const QQuickVisualDataGroup);
2197 return d->defaultInclude;
2200 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2202 Q_D(QQuickVisualDataGroup);
2203 if (d->defaultInclude != include) {
2204 d->defaultInclude = include;
2208 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2210 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2212 emit defaultIncludeChanged();
2217 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2219 Returns a javascript object describing the item at \a index in the group.
2221 The returned object contains the same information that is available to a delegate from the
2222 VisualDataModel attached as well as the model for that item. It has the properties:
2225 \li \b model The model data of the item. This is the same as the model context property in
2227 \li \b groups A list the of names of groups the item is a member of. This property can be
2228 written to change the item's membership.
2229 \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2230 Writing to this property will add or remove the item from the group.
2231 \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2232 \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName. Writing to
2233 this property will add or remove the item from the group.
2234 \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2238 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2240 Q_D(QQuickVisualDataGroup);
2242 return QQmlV8Handle::fromHandle(v8::Undefined());;
2244 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2245 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2246 qmlInfo(this) << tr("get: index out of range");
2247 return QQmlV8Handle::fromHandle(v8::Undefined());
2250 Compositor::iterator it = model->m_compositor.find(d->group, index);
2251 QQuickVisualDataModelItem *cacheItem = it->inCache()
2252 ? model->m_cache.at(it.cacheIndex)
2256 cacheItem = model->m_adaptorModel.createItem(
2257 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2259 return QQmlV8Handle::fromHandle(v8::Undefined());
2260 cacheItem->groups = it->flags;
2262 model->m_cache.insert(it.cacheIndex, cacheItem);
2263 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2266 if (cacheItem->indexHandle.IsEmpty()) {
2267 if (model->m_cacheMetaType->constructor.IsEmpty())
2268 model->m_cacheMetaType->initializeConstructor();
2269 cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
2270 cacheItem->indexHandle->SetExternalResource(cacheItem);
2271 cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
2273 ++cacheItem->scriptRef;
2276 return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
2279 bool QQuickVisualDataGroupPrivate::parseIndex(
2280 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2282 if (value->IsInt32()) {
2283 *index = value->Int32Value();
2285 } else if (value->IsObject()) {
2286 v8::Local<v8::Object> object = value->ToObject();
2287 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2288 if (QQuickVisualDataModelPrivate *model = cacheItem && cacheItem->metaType->model
2289 ? QQuickVisualDataModelPrivate::get(cacheItem->metaType->model)
2291 *index = model->m_cache.indexOf(cacheItem);
2292 *group = Compositor::Cache;
2299 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2301 Q_D(QQuickVisualDataGroup);
2302 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2304 int index = model->m_compositor.count(d->group);
2305 Compositor::Group group = d->group;
2307 if (args->Length() == 0)
2311 v8::Local<v8::Value> v = (*args)[i];
2312 if (d->parseIndex(v, &index, &group)) {
2313 if (index < 0 || index > model->m_compositor.count(group)) {
2314 qmlInfo(this) << tr("insert: index out of range");
2317 if (++i == args->Length())
2322 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2323 ? model->m_compositor.findInsertPosition(group, index)
2324 : model->m_compositor.end();
2326 int groups = 1 << d->group;
2327 if (++i < args->Length())
2328 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2332 } else if (v->IsObject()) {
2333 model->insert(before, v->ToObject(), groups);
2334 model->emitChanges();
2339 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2340 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2341 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2343 Returns a reference to the instantiated item at \a index in the group.
2345 All items returned by create are added to the persistedItems group. Items in this
2346 group remain instantiated when not referenced by any view.
2349 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2351 Q_D(QQuickVisualDataGroup);
2355 if (args->Length() == 0)
2358 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2360 int index = model->m_compositor.count(d->group);
2361 Compositor::Group group = d->group;
2364 v8::Local<v8::Value> v = (*args)[i];
2365 if (d->parseIndex(v, &index, &group))
2368 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2370 if (v->IsObject()) {
2371 int groups = 1 << d->group;
2372 if (++i < args->Length())
2373 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2375 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2376 ? model->m_compositor.findInsertPosition(group, index)
2377 : model->m_compositor.end();
2379 index = before.index[d->group];
2382 if (!model->insert(before, v->ToObject(), groups)) {
2387 if (index < 0 || index >= model->m_compositor.count(group)) {
2388 qmlInfo(this) << tr("create: index out of range");
2392 QObject *object = model->object(group, index, false);
2394 QVector<Compositor::Insert> inserts;
2395 Compositor::iterator it = model->m_compositor.find(group, index);
2396 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2397 model->itemsInserted(inserts);
2398 model->m_cache.at(it.cacheIndex)->releaseObject();
2401 args->returnValue(args->engine()->newQObject(object));
2402 model->emitChanges();
2405 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2407 Q_D(QQuickVisualDataGroup);
2411 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2413 if (args->Length() < 2)
2418 Compositor::Group fromGroup = d->group;
2419 Compositor::Group toGroup = d->group;
2421 v8::Local<v8::Value> v = (*args)[0];
2422 if (d->parseIndex(v, &from, &fromGroup)) {
2423 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2424 qmlInfo(this) << tr("resolve: from index out of range");
2428 qmlInfo(this) << tr("resolve: from index invalid");
2433 if (d->parseIndex(v, &to, &toGroup)) {
2434 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2435 qmlInfo(this) << tr("resolve: to index out of range");
2439 qmlInfo(this) << tr("resolve: to index invalid");
2443 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2444 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2446 if (!fromIt->isUnresolved()) {
2447 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2451 qmlInfo(this) << tr("resolve: to is not a model item");
2455 const int unresolvedFlags = fromIt->flags;
2456 const int resolvedFlags = toIt->flags;
2457 const int resolvedIndex = toIt.modelIndex();
2458 void * const resolvedList = toIt->list;
2460 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2461 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2463 if (toIt.cacheIndex > fromIt.cacheIndex)
2464 toIt.decrementIndexes(1, unresolvedFlags);
2465 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2469 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2470 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2471 model->itemsInserted(
2472 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2473 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2474 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2476 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2477 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2479 if (resolvedFlags & Compositor::CacheFlag)
2480 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2482 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2484 if (!cacheItem->isReferenced()) {
2485 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2486 model->m_cache.removeAt(toIt.cacheIndex);
2487 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2489 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2491 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2492 if (cacheItem->attached)
2493 cacheItem->attached->emitUnresolvedChanged();
2496 model->emitChanges();
2500 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2502 Removes \a count items starting at \a index from the group.
2505 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2507 Q_D(QQuickVisualDataGroup);
2510 Compositor::Group group = d->group;
2514 if (args->Length() == 0)
2518 v8::Local<v8::Value> v = (*args)[i];
2519 if (!d->parseIndex(v, &index, &group)) {
2520 qmlInfo(this) << tr("remove: invalid index");
2524 if (++i < args->Length()) {
2527 count = v->Int32Value();
2530 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2531 if (index < 0 || index >= model->m_compositor.count(group)) {
2532 qmlInfo(this) << tr("remove: index out of range");
2533 } else if (count != 0) {
2534 Compositor::iterator it = model->m_compositor.find(group, index);
2535 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2536 qmlInfo(this) << tr("remove: invalid count");
2538 model->removeGroups(it, count, d->group, 1 << d->group);
2543 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2544 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2546 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2549 if (args->Length() < 2)
2553 v8::Local<v8::Value> v = (*args)[i];
2554 if (!parseIndex(v, index, group))
2559 *count = v->Int32Value();
2561 if (++i == args->Length())
2566 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2572 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2574 Adds \a count items starting at \a index to \a groups.
2577 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2579 Q_D(QQuickVisualDataGroup);
2580 Compositor::Group group = d->group;
2585 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2588 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2589 if (index < 0 || index >= model->m_compositor.count(group)) {
2590 qmlInfo(this) << tr("addGroups: index out of range");
2591 } else if (count != 0) {
2592 Compositor::iterator it = model->m_compositor.find(group, index);
2593 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2594 qmlInfo(this) << tr("addGroups: invalid count");
2596 model->addGroups(it, count, d->group, groups);
2602 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2604 Removes \a count items starting at \a index from \a groups.
2607 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2609 Q_D(QQuickVisualDataGroup);
2610 Compositor::Group group = d->group;
2615 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2618 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2619 if (index < 0 || index >= model->m_compositor.count(group)) {
2620 qmlInfo(this) << tr("removeGroups: index out of range");
2621 } else if (count != 0) {
2622 Compositor::iterator it = model->m_compositor.find(group, index);
2623 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2624 qmlInfo(this) << tr("removeGroups: invalid count");
2626 model->removeGroups(it, count, d->group, groups);
2632 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2634 Sets the \a groups \a count items starting at \a index belong to.
2637 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2639 Q_D(QQuickVisualDataGroup);
2640 Compositor::Group group = d->group;
2645 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2648 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2649 if (index < 0 || index >= model->m_compositor.count(group)) {
2650 qmlInfo(this) << tr("setGroups: index out of range");
2651 } else if (count != 0) {
2652 Compositor::iterator it = model->m_compositor.find(group, index);
2653 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2654 qmlInfo(this) << tr("setGroups: invalid count");
2656 model->setGroups(it, count, d->group, groups);
2662 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2664 Sets the \a groups \a count items starting at \a index belong to.
2668 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2670 Moves \a count at \a from in a group \a to a new position.
2673 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2675 Q_D(QQuickVisualDataGroup);
2677 if (args->Length() < 2)
2680 Compositor::Group fromGroup = d->group;
2681 Compositor::Group toGroup = d->group;
2686 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2687 qmlInfo(this) << tr("move: invalid from index");
2691 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2692 qmlInfo(this) << tr("move: invalid to index");
2696 if (args->Length() > 2) {
2697 v8::Local<v8::Value> v = (*args)[2];
2699 count = v->Int32Value();
2702 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2705 qmlInfo(this) << tr("move: invalid count");
2706 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2707 qmlInfo(this) << tr("move: from index out of range");
2708 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2709 qmlInfo(this) << tr("move: to index out of range");
2710 } else if (count > 0) {
2711 QVector<Compositor::Remove> removes;
2712 QVector<Compositor::Insert> inserts;
2714 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2715 model->itemsMoved(removes, inserts);
2716 model->emitChanges();
2722 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2724 This handler is called when items have been removed from or inserted into the group.
2726 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2727 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2729 Each index is adjusted for previous changes with all removed items preceding any inserted
2733 //============================================================================
2735 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2736 : QQuickVisualModel(*new QObjectPrivate, parent)
2739 , m_compositorGroup(Compositor::Cache)
2740 , m_inheritGroup(true)
2742 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2743 if (d->m_cacheMetaType) {
2744 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2745 m_compositorGroup = Compositor::Default;
2747 d->m_pendingParts.insert(this);
2751 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2755 QString QQuickVisualPartsModel::filterGroup() const
2758 return m_model->filterGroup();
2759 return m_filterGroup;
2762 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2764 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2765 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2769 if (m_filterGroup != group || m_inheritGroup) {
2770 m_filterGroup = group;
2771 m_inheritGroup = false;
2772 updateFilterGroup();
2774 emit filterGroupChanged();
2778 void QQuickVisualPartsModel::resetFilterGroup()
2780 if (!m_inheritGroup) {
2781 m_inheritGroup = true;
2782 updateFilterGroup();
2783 emit filterGroupChanged();
2787 void QQuickVisualPartsModel::updateFilterGroup()
2789 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2790 if (!model->m_cacheMetaType)
2793 if (m_inheritGroup) {
2794 if (m_filterGroup == model->m_filterGroup)
2796 m_filterGroup = model->m_filterGroup;
2799 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2800 m_compositorGroup = Compositor::Default;
2801 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2802 for (int i = 1; i < model->m_groupCount; ++i) {
2803 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2804 m_compositorGroup = Compositor::Group(i);
2809 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2810 if (m_compositorGroup != previousGroup) {
2811 QVector<QQuickChangeSet::Remove> removes;
2812 QVector<QQuickChangeSet::Insert> inserts;
2813 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2815 QQuickChangeSet changeSet;
2816 changeSet.apply(removes, inserts);
2817 if (!changeSet.isEmpty())
2818 emit modelUpdated(changeSet, false);
2820 if (changeSet.difference() != 0)
2821 emit countChanged();
2825 void QQuickVisualPartsModel::updateFilterGroup(
2826 Compositor::Group group, const QQuickChangeSet &changeSet)
2828 if (!m_inheritGroup)
2831 m_compositorGroup = group;
2832 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2834 if (!changeSet.isEmpty())
2835 emit modelUpdated(changeSet, false);
2837 if (changeSet.difference() != 0)
2838 emit countChanged();
2840 emit filterGroupChanged();
2843 int QQuickVisualPartsModel::count() const
2845 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2846 return model->m_delegate
2847 ? model->m_compositor.count(m_compositorGroup)
2851 bool QQuickVisualPartsModel::isValid() const
2853 return m_model->isValid();
2856 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2858 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2860 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2861 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2865 QObject *object = model->object(m_compositorGroup, index, asynchronous);
2867 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
2868 QObject *part = package->part(m_part);
2871 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(part)) {
2872 m_packaged.insertMulti(item, package);
2877 model->release(object);
2878 if (!model->m_delegateValidated) {
2880 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2881 model->m_delegateValidated = true;
2887 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2889 QQuickVisualModel::ReleaseFlags flags = 0;
2891 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2892 if (it != m_packaged.end()) {
2893 QQuickPackage *package = *it;
2894 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2895 flags = model->release(package);
2896 m_packaged.erase(it);
2897 if (!m_packaged.contains(item))
2898 flags &= ~Referenced;
2899 if (flags & Destroyed)
2900 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2905 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2907 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2910 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2912 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2913 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2914 m_watchedRoles = roles;
2917 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2919 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2920 if (it != m_packaged.end()) {
2921 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2922 return cacheItem->groupIndex(m_compositorGroup);
2927 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2929 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2930 emit createdItem(index, item);
2933 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2935 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2936 emit initItem(index, item);
2939 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2941 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part))) {
2942 Q_ASSERT(!m_packaged.contains(item));
2943 emit destroyingItem(item);
2944 item->setParentItem(0);
2948 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2950 emit modelUpdated(changeSet, reset);
2951 if (changeSet.difference() != 0)
2952 emit countChanged();
2955 //============================================================================
2957 v8::Handle<v8::Value> get_change_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
2959 return info.This()->GetInternalField(0);
2962 v8::Handle<v8::Value> get_change_count(v8::Local<v8::String>, const v8::AccessorInfo &info)
2964 return info.This()->GetInternalField(1);
2967 v8::Handle<v8::Value> get_change_moveId(v8::Local<v8::String>, const v8::AccessorInfo &info)
2969 return info.This()->GetInternalField(2);
2972 class QQuickVisualDataGroupChangeArray : public QV8ObjectResource
2974 V8_RESOURCE_TYPE(ChangeSetArrayType)
2976 QQuickVisualDataGroupChangeArray(QV8Engine *engine)
2977 : QV8ObjectResource(engine)
2981 virtual quint32 count() const = 0;
2982 virtual const QQuickChangeSet::Change &at(int index) const = 0;
2984 static v8::Handle<v8::Value> get_change(quint32 index, const v8::AccessorInfo &info)
2986 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2988 V8THROW_ERROR("Not a valid change array");
2990 if (index >= array->count())
2991 return v8::Undefined();
2993 const QQuickChangeSet::Change &change = array->at(index);
2995 v8::Local<v8::Object> object = engineData(array->engine)->constructorChange->NewInstance();
2996 object->SetInternalField(0, v8::Int32::New(change.index));
2997 object->SetInternalField(1, v8::Int32::New(change.count));
2998 if (change.isMove())
2999 object->SetInternalField(2, v8::Int32::New(change.moveId));
3004 static v8::Handle<v8::Value> get_length(v8::Local<v8::String>, const v8::AccessorInfo &info)
3006 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
3008 V8THROW_ERROR("Not a valid change array");
3010 return v8::Integer::New(array->count());
3013 static v8::Local<v8::Function> constructor()
3015 v8::Local<v8::FunctionTemplate> changeArray = v8::FunctionTemplate::New();
3016 changeArray->InstanceTemplate()->SetHasExternalResource(true);
3017 changeArray->InstanceTemplate()->SetIndexedPropertyHandler(get_change);
3018 changeArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), get_length);
3019 return changeArray->GetFunction();
3023 class QQuickVisualDataGroupRemoveArray : public QQuickVisualDataGroupChangeArray
3026 QQuickVisualDataGroupRemoveArray(QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3027 : QQuickVisualDataGroupChangeArray(engine)
3032 quint32 count() const { return changes.count(); }
3033 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3036 QVector<QQuickChangeSet::Remove> changes;
3039 class QQuickVisualDataGroupInsertArray : public QQuickVisualDataGroupChangeArray
3042 QQuickVisualDataGroupInsertArray(QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3043 : QQuickVisualDataGroupChangeArray(engine)
3048 quint32 count() const { return changes.count(); }
3049 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3052 QVector<QQuickChangeSet::Insert> changes;
3055 QQuickVisualDataModelEngineData::QQuickVisualDataModelEngineData(QV8Engine *)
3057 strings = qPersistentNew(v8::Array::New(StringCount));
3058 strings->Set(Model, v8::String::New("model"));
3059 strings->Set(Groups, v8::String::New("groups"));
3060 strings->Set(IsUnresolved, v8::String::New("isUnresolved"));
3061 strings->Set(ItemsIndex, v8::String::New("itemsIndex"));
3062 strings->Set(PersistedItemsIndex, v8::String::New("persistedItemsIndex"));
3063 strings->Set(InItems, v8::String::New("inItems"));
3064 strings->Set(InPersistedItems, v8::String::New("inPersistedItems"));
3066 v8::Local<v8::FunctionTemplate> change = v8::FunctionTemplate::New();
3067 change->InstanceTemplate()->SetAccessor(v8::String::New("index"), get_change_index);
3068 change->InstanceTemplate()->SetAccessor(v8::String::New("count"), get_change_count);
3069 change->InstanceTemplate()->SetAccessor(v8::String::New("moveId"), get_change_moveId);
3070 change->InstanceTemplate()->SetInternalFieldCount(3);
3071 constructorChange = qPersistentNew(change->GetFunction());
3072 constructorChangeArray = qPersistentNew(QQuickVisualDataGroupChangeArray::constructor());
3075 QQuickVisualDataModelEngineData::~QQuickVisualDataModelEngineData()
3077 qPersistentDispose(strings);
3078 qPersistentDispose(constructorChange);
3079 qPersistentDispose(constructorChangeArray);
3082 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3083 QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3085 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3086 array->SetExternalResource(new QQuickVisualDataGroupRemoveArray(engine, changes));
3090 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3091 QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3093 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3094 array->SetExternalResource(new QQuickVisualDataGroupInsertArray(engine, changes));