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>()) {
958 return model->stringValue(it.modelIndex(), name);
963 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
965 Q_D(QQuickVisualDataModel);
966 return d->stringValue(d->m_compositorGroup, index, name);
969 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
971 Q_D(const QQuickVisualDataModel);
972 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
973 return cacheItem->groupIndex(d->m_compositorGroup);
977 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
979 Q_D(QQuickVisualDataModel);
980 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
981 d->m_watchedRoles = roles;
984 void QQuickVisualDataModelPrivate::addGroups(
985 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
987 QVector<Compositor::Insert> inserts;
988 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
989 itemsInserted(inserts);
993 void QQuickVisualDataModelPrivate::removeGroups(
994 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
996 QVector<Compositor::Remove> removes;
997 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
998 itemsRemoved(removes);
1002 void QQuickVisualDataModelPrivate::setGroups(
1003 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1005 QVector<Compositor::Remove> removes;
1006 QVector<Compositor::Insert> inserts;
1008 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1009 itemsInserted(inserts);
1010 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1012 from = m_compositor.find(from.group, from.index[from.group]);
1013 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1014 itemsRemoved(removes);
1018 bool QQuickVisualDataModel::event(QEvent *e)
1020 Q_D(QQuickVisualDataModel);
1021 if (e->type() == QEvent::UpdateRequest) {
1022 d->m_adaptorModel.fetchMore();
1023 } else if (e->type() == QEvent::User) {
1024 d->m_incubatorCleanupScheduled = false;
1025 qDeleteAll(d->m_finishedIncubating);
1026 d->m_finishedIncubating.clear();
1028 return QQuickVisualModel::event(e);
1031 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1036 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1038 foreach (const Compositor::Change &change, changes) {
1039 for (int i = 1; i < m_groupCount; ++i) {
1040 if (change.inGroup(i)) {
1041 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
1046 for (int i = 1; i < m_groupCount; ++i)
1047 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1050 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QList<int> &roles)
1052 Q_D(QQuickVisualDataModel);
1053 if (count <= 0 || !d->m_complete)
1056 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1057 QVector<Compositor::Change> changes;
1058 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1059 d->itemsChanged(changes);
1064 static void incrementIndexes(QQuickVisualDataModelItem *cacheItem, int count, const int *deltas)
1066 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1067 for (int i = 1; i < count; ++i)
1068 incubationTask->index[i] += deltas[i];
1070 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1071 for (int i = 1; i < count; ++i)
1072 attached->m_currentIndex[i] += deltas[i];
1076 void QQuickVisualDataModelPrivate::itemsInserted(
1077 const QVector<Compositor::Insert> &inserts,
1078 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1079 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1083 int inserted[Compositor::MaximumGroupCount];
1084 for (int i = 1; i < m_groupCount; ++i)
1087 foreach (const Compositor::Insert &insert, inserts) {
1088 for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
1089 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1091 for (int i = 1; i < m_groupCount; ++i) {
1092 if (insert.inGroup(i)) {
1093 (*translatedInserts)[i].append(
1094 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1095 inserted[i] += insert.count;
1099 if (!insert.inCache())
1102 if (movedItems && insert.isMove()) {
1103 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1104 Q_ASSERT(items.count() == insert.count);
1105 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1107 if (insert.inGroup()) {
1108 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1109 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1110 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1112 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1113 for (int i = 1; i < m_groupCount; ++i)
1114 incubationTask->index[i] = cacheItem->groups & (1 << i)
1115 ? insert.index[i] + offset
1118 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1119 for (int i = 1; i < m_groupCount; ++i)
1120 attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1121 ? insert.index[i] + offset
1126 cacheIndex = insert.cacheIndex + insert.count;
1129 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1130 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1133 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1135 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1136 itemsInserted(inserts, &translatedInserts);
1137 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1141 for (int i = 1; i < m_groupCount; ++i)
1142 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1145 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1148 Q_D(QQuickVisualDataModel);
1149 if (count <= 0 || !d->m_complete)
1152 d->m_count += count;
1154 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1155 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1156 if (item->modelIndex() >= index)
1157 item->setModelIndex(item->modelIndex() + count);
1160 QVector<Compositor::Insert> inserts;
1161 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1162 d->itemsInserted(inserts);
1166 void QQuickVisualDataModelPrivate::itemsRemoved(
1167 const QVector<Compositor::Remove> &removes,
1168 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1169 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1172 int removedCache = 0;
1174 int removed[Compositor::MaximumGroupCount];
1175 for (int i = 1; i < m_groupCount; ++i)
1178 foreach (const Compositor::Remove &remove, removes) {
1179 for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
1180 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1182 for (int i = 1; i < m_groupCount; ++i) {
1183 if (remove.inGroup(i)) {
1184 (*translatedRemoves)[i].append(
1185 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1186 removed[i] -= remove.count;
1190 if (!remove.inCache())
1193 if (movedItems && remove.isMove()) {
1194 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1195 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1196 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1197 m_cache.erase(begin, end);
1199 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1200 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1201 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1202 QObject *object = cacheItem->object;
1203 cacheItem->destroyObject();
1204 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1205 emitDestroyingPackage(package);
1206 else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
1207 emitDestroyingItem(item);
1208 cacheItem->scriptRef -= 1;
1210 if (!cacheItem->isReferenced()) {
1211 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1212 m_cache.removeAt(cacheIndex);
1216 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1217 } else if (remove.groups() == cacheItem->groups) {
1218 cacheItem->groups = 0;
1219 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1220 for (int i = 1; i < m_groupCount; ++i)
1221 incubationTask->index[i] = -1;
1223 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1224 for (int i = 1; i < m_groupCount; ++i)
1225 attached->m_currentIndex[i] = -1;
1228 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1229 for (int i = 1; i < m_groupCount; ++i) {
1230 if (remove.inGroup(i))
1231 incubationTask->index[i] = remove.index[i];
1234 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1235 for (int i = 1; i < m_groupCount; ++i) {
1236 if (remove.inGroup(i))
1237 attached->m_currentIndex[i] = remove.index[i];
1240 cacheItem->groups &= ~remove.flags;
1246 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1247 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1250 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1252 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1253 itemsRemoved(removes, &translatedRemoves);
1254 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1258 for (int i = 1; i < m_groupCount; ++i)
1259 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1262 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1264 Q_D(QQuickVisualDataModel);
1265 if (count <= 0|| !d->m_complete)
1268 d->m_count -= count;
1270 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1271 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1272 if (item->modelIndex() >= index + count)
1273 item->setModelIndex(item->modelIndex() - count);
1274 else if (item->modelIndex() >= index)
1275 item->setModelIndex(-1);
1278 QVector<Compositor::Remove> removes;
1279 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1280 d->itemsRemoved(removes);
1285 void QQuickVisualDataModelPrivate::itemsMoved(
1286 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1288 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1290 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1291 itemsRemoved(removes, &translatedRemoves, &movedItems);
1293 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1294 itemsInserted(inserts, &translatedInserts, &movedItems);
1295 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1296 Q_ASSERT(movedItems.isEmpty());
1300 for (int i = 1; i < m_groupCount; ++i) {
1301 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1302 translatedRemoves.at(i),
1303 translatedInserts.at(i));
1307 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1309 Q_D(QQuickVisualDataModel);
1310 if (count <= 0 || !d->m_complete)
1313 const int minimum = qMin(from, to);
1314 const int maximum = qMax(from, to) + count;
1315 const int difference = from > to ? count : -count;
1317 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1318 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1319 if (item->modelIndex() >= from && item->modelIndex() < from + count)
1320 item->setModelIndex(item->modelIndex() - from + to);
1321 else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1322 item->setModelIndex(item->modelIndex() + difference);
1325 QVector<Compositor::Remove> removes;
1326 QVector<Compositor::Insert> inserts;
1327 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1328 d->itemsMoved(removes, inserts);
1332 template <typename T> v8::Local<v8::Array>
1333 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1335 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1336 v8::Local<v8::String> indexKey = v8::String::New("index");
1337 v8::Local<v8::String> countKey = v8::String::New("count");
1338 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1340 for (int i = 0; i < changes.count(); ++i) {
1341 v8::Local<v8::Object> object = v8::Object::New();
1342 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1343 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1344 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1345 indexes->Set(i, object);
1350 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1352 Q_Q(QQuickVisualDataModel);
1353 emit q->modelUpdated(changeSet, reset);
1354 if (changeSet.difference() != 0)
1355 emit q->countChanged();
1358 void QQuickVisualDataModelPrivate::emitChanges()
1360 if (m_transaction || !m_complete)
1363 m_transaction = true;
1364 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1365 for (int i = 1; i < m_groupCount; ++i)
1366 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1367 m_transaction = false;
1369 const bool reset = m_reset;
1371 for (int i = 1; i < m_groupCount; ++i)
1372 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1374 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1375 if (cacheItem->attached)
1376 cacheItem->attached->emitChanges();
1380 void QQuickVisualDataModel::_q_modelReset()
1382 Q_D(QQuickVisualDataModel);
1386 int oldCount = d->m_count;
1387 d->m_adaptorModel.rootIndex = QModelIndex();
1389 if (d->m_complete) {
1390 d->m_count = d->m_adaptorModel.count();
1392 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1393 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1394 if (item->modelIndex() != -1)
1395 item->setModelIndex(-1);
1398 QVector<Compositor::Remove> removes;
1399 QVector<Compositor::Insert> inserts;
1401 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1403 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1404 d->itemsMoved(removes, inserts);
1407 if (d->m_adaptorModel.canFetchMore())
1408 d->m_adaptorModel.fetchMore();
1412 emit rootIndexChanged();
1415 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1417 Q_D(QQuickVisualDataModel);
1418 if (parent == d->m_adaptorModel.rootIndex)
1419 _q_itemsInserted(begin, end - begin + 1);
1422 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1424 Q_D(QQuickVisualDataModel);
1425 if (parent == d->m_adaptorModel.rootIndex)
1426 _q_itemsRemoved(begin, end - begin + 1);
1429 void QQuickVisualDataModel::_q_rowsMoved(
1430 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1431 const QModelIndex &destinationParent, int destinationRow)
1433 Q_D(QQuickVisualDataModel);
1434 const int count = sourceEnd - sourceStart + 1;
1435 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1436 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1437 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1438 _q_itemsRemoved(sourceStart, count);
1439 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1440 _q_itemsInserted(destinationRow, count);
1444 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1446 Q_D(QQuickVisualDataModel);
1447 if (begin.parent() == d->m_adaptorModel.rootIndex)
1448 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, QList<int>());
1451 void QQuickVisualDataModel::_q_layoutChanged()
1453 Q_D(QQuickVisualDataModel);
1454 _q_itemsChanged(0, d->m_count, QList<int>());
1457 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1459 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1460 if (cacheItem->object == obj) { // Don't create attached item for child objects.
1461 cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1462 return cacheItem->attached;
1465 return new QQuickVisualDataModelAttached(obj);
1468 bool QQuickVisualDataModelPrivate::insert(
1469 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1471 QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1475 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1476 for (uint i = 0; i < propertyNames->Length(); ++i) {
1477 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1478 cacheItem->setValue(
1479 m_cacheMetaType->v8Engine->toString(propertyName),
1480 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1483 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1485 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1486 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1488 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1489 m_cache.insert(before.cacheIndex, cacheItem);
1494 //============================================================================
1496 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1497 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1499 , groupCount(groupNames.count() + 1)
1502 , groupNames(groupNames)
1506 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1509 metaObject->release();
1510 qPersistentDispose(constructor);
1513 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1515 QMetaObjectBuilder builder;
1516 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1517 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1518 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1521 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1522 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1523 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1524 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1525 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1526 propertyName.toUtf8(), "bool", notifierId);
1527 propertyBuilder.setWritable(true);
1529 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1530 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1531 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1532 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1533 propertyName.toUtf8(), "int", notifierId);
1534 propertyBuilder.setWritable(true);
1537 metaObject = new QQuickVisualDataModelAttachedMetaObject(this, builder.toMetaObject());
1540 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1542 v8::HandleScope handleScope;
1543 v8::Context::Scope contextScope(v8Engine->context());
1545 QQuickVisualDataModelEngineData *data = engineData(v8Engine);
1547 constructor = qPersistentNew(v8::ObjectTemplate::New());
1549 constructor->SetHasExternalResource(true);
1550 constructor->SetAccessor(data->model(), get_model);
1551 constructor->SetAccessor(data->groups(), get_groups, set_groups);
1552 constructor->SetAccessor(data->isUnresolved(), get_member, 0, v8::Int32::New(30));
1553 constructor->SetAccessor(data->inItems(), get_member, set_member, v8::Int32::New(1));
1554 constructor->SetAccessor(data->inPersistedItems(), get_member, set_member, v8::Int32::New(2));
1555 constructor->SetAccessor(data->itemsIndex(), get_index, 0, v8::Int32::New(1));
1556 constructor->SetAccessor(data->persistedItemsIndex(), get_index, 0, v8::Int32::New(2));
1558 for (int i = 2; i < groupNames.count(); ++i) {
1559 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1560 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1561 constructor->SetAccessor(
1562 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1564 for (int i = 2; i < groupNames.count(); ++i) {
1565 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1566 constructor->SetAccessor(
1567 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1571 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1574 foreach (const QString &groupName, groups) {
1575 int index = groupNames.indexOf(groupName);
1577 groupFlags |= 2 << index;
1582 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1585 if (groups->IsString()) {
1586 const QString groupName = v8Engine->toString(groups);
1587 int index = groupNames.indexOf(groupName);
1589 groupFlags |= 2 << index;
1590 } else if (groups->IsArray()) {
1591 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1592 for (uint i = 0; i < array->Length(); ++i) {
1593 const QString groupName = v8Engine->toString(array->Get(i));
1594 int index = groupNames.indexOf(groupName);
1596 groupFlags |= 2 << index;
1602 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1604 static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1605 qPersistentDispose(object);
1608 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1610 static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1611 qPersistentDispose(object);
1614 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1615 v8::Local<v8::String>, const v8::AccessorInfo &info)
1617 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1619 V8THROW_ERROR("Not a valid VisualData object");
1620 if (!cacheItem->metaType->model)
1621 return v8::Undefined();
1623 if (cacheItem->modelHandle.IsEmpty()) {
1624 cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1625 cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1627 ++cacheItem->scriptRef;
1630 return cacheItem->modelHandle;
1633 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1634 v8::Local<v8::String>, const v8::AccessorInfo &info)
1636 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1638 V8THROW_ERROR("Not a valid VisualData object");
1641 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1642 if (cacheItem->groups & (1 << i))
1643 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1646 return cacheItem->engine->fromVariant(groups);
1649 void QQuickVisualDataModelItemMetaType::set_groups(
1650 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1652 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1654 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1656 if (!cacheItem->metaType->model)
1658 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1660 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1661 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1662 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1663 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1666 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1667 v8::Local<v8::String>, const v8::AccessorInfo &info)
1669 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1671 V8THROW_ERROR("Not a valid VisualData object");
1673 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1676 void QQuickVisualDataModelItemMetaType::set_member(
1677 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1679 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1681 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1683 if (!cacheItem->metaType->model)
1685 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1687 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1688 const bool member = value->BooleanValue();
1689 const int groupFlag = (1 << group);
1690 if (member == ((cacheItem->groups & groupFlag) != 0))
1693 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1694 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1696 model->addGroups(it, 1, Compositor::Cache, groupFlag);
1698 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
1701 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1702 v8::Local<v8::String>, const v8::AccessorInfo &info)
1704 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1706 V8THROW_ERROR("Not a valid VisualData object");
1708 return v8::Integer::New(cacheItem->groupIndex(Compositor::Group(info.Data()->Int32Value())));
1712 //---------------------------------------------------------------------------
1714 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1715 QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1716 : QV8ObjectResource(metaType->v8Engine)
1717 , metaType(metaType)
1730 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1732 Q_ASSERT(scriptRef == 0);
1733 Q_ASSERT(objectRef == 0);
1735 Q_ASSERT(indexHandle.IsEmpty());
1736 Q_ASSERT(modelHandle.IsEmpty());
1738 if (incubationTask && metaType->model)
1739 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1741 metaType->release();
1745 void QQuickVisualDataModelItem::Dispose()
1751 if (metaType->model) {
1752 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1753 model->removeCacheItem(this);
1759 This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1760 arguments instead of QQmlContext which means we don't have to construct the rather weighty
1761 wrapper class for every delegate item.
1763 void QQuickVisualDataModelItem::incubateObject(
1764 QQmlComponent *component,
1766 QQmlContextData *context,
1767 QQmlContextData *forContext)
1769 QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
1770 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
1771 QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
1773 incubatorPriv->compiledData = componentPriv->cc;
1774 incubatorPriv->compiledData->addref();
1775 incubatorPriv->vme.init(
1778 componentPriv->start,
1779 componentPriv->creationContext);
1781 enginePriv->incubate(*incubationTask, forContext);
1784 void QQuickVisualDataModelItem::destroyObject()
1787 Q_ASSERT(contextData);
1789 QObjectPrivate *p = QObjectPrivate::get(object);
1790 Q_ASSERT(p->declarativeData);
1791 QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1792 if (data->ownContext && data->context)
1793 data->context->clearContext();
1794 object->deleteLater();
1797 attached->m_cacheItem = 0;
1801 contextData->destroy();
1806 QQuickVisualDataModelItem *QQuickVisualDataModelItem::dataForObject(QObject *object)
1808 QObjectPrivate *p = QObjectPrivate::get(object);
1809 QQmlContextData *context = p->declarativeData
1810 ? static_cast<QQmlData *>(p->declarativeData)->context
1812 for (context = context ? context->parent : 0; context; context = context->parent) {
1813 if (QQuickVisualDataModelItem *cacheItem = qobject_cast<QQuickVisualDataModelItem *>(
1814 context->contextObject)) {
1821 int QQuickVisualDataModelItem::groupIndex(Compositor::Group group)
1823 if (QQuickVisualDataModelPrivate * const model = metaType->model
1824 ? QQuickVisualDataModelPrivate::get(metaType->model)
1826 return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
1831 //---------------------------------------------------------------------------
1833 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1834 QQuickVisualDataModelItemMetaType *metaType, QMetaObject *metaObject)
1835 : metaType(metaType)
1836 , metaObject(metaObject)
1837 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1838 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
1840 // Don't reference count the meta-type here as that would create a circular reference.
1841 // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
1842 // destroying all delegates with attached objects.
1843 *static_cast<QMetaObject *>(this) = *metaObject;
1846 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1851 void QQuickVisualDataModelAttachedMetaObject::objectDestroyed(QObject *)
1856 int QQuickVisualDataModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
1858 QQuickVisualDataModelAttached *attached = static_cast<QQuickVisualDataModelAttached *>(object);
1859 if (call == QMetaObject::ReadProperty) {
1860 if (_id >= indexPropertyOffset) {
1861 Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
1862 *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
1864 } else if (_id >= memberPropertyOffset) {
1865 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1866 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1869 } else if (call == QMetaObject::WriteProperty) {
1870 if (_id >= memberPropertyOffset) {
1871 if (!metaType->model)
1873 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1874 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1875 const int groupFlag = 1 << group;
1876 const bool member = attached->m_cacheItem->groups & groupFlag;
1877 if (member && !*static_cast<bool *>(arguments[0])) {
1878 Compositor::iterator it = model->m_compositor.find(
1879 group, attached->m_currentIndex[group]);
1880 model->removeGroups(it, 1, group, groupFlag);
1881 } else if (!member && *static_cast<bool *>(arguments[0])) {
1882 for (int i = 1; i < metaType->groupCount; ++i) {
1883 if (attached->m_cacheItem->groups & (1 << i)) {
1884 Compositor::iterator it = model->m_compositor.find(
1885 Compositor::Group(i), attached->m_currentIndex[i]);
1886 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1894 return attached->qt_metacall(call, _id, arguments);
1897 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1899 , m_previousGroups(0)
1900 , m_modelChanged(false)
1902 QQml_setParent_noEvent(this, parent);
1905 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1906 QQuickVisualDataModelItem *cacheItem, QObject *parent)
1907 : m_cacheItem(cacheItem)
1908 , m_previousGroups(cacheItem->groups)
1909 , m_modelChanged(false)
1911 QQml_setParent_noEvent(this, parent);
1912 if (QVDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
1913 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1914 m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
1916 QQuickVisualDataModelPrivate * const model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1917 Compositor::iterator it = model->m_compositor.find(
1918 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
1919 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1920 m_currentIndex[i] = m_previousIndex[i] = it.index[i];
1923 if (!cacheItem->metaType->metaObject)
1924 cacheItem->metaType->initializeMetaObject();
1926 QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
1927 cacheItem->metaType->metaObject->addref();
1931 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1933 This attached property holds the visual data model this delegate instance belongs to.
1935 It is attached to each instance of the delegate.
1938 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1940 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1944 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1946 This attached property holds the name of VisualDataGroups the item belongs to.
1948 It is attached to each instance of the delegate.
1951 QStringList QQuickVisualDataModelAttached::groups() const
1957 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1958 if (m_cacheItem->groups & (1 << i))
1959 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1964 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1969 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1971 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1972 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1973 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1974 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1977 bool QQuickVisualDataModelAttached::isUnresolved() const
1982 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1986 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1988 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1990 Changing this property will add or remove the item from the items group.
1992 It is attached to each instance of the delegate.
1996 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1998 This attached property holds the index of the item in the default \l items VisualDataGroup.
2000 It is attached to each instance of the delegate.
2004 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
2006 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
2008 Changing this property will add or remove the item from the items group. Change with caution
2009 as removing an item from the persistedItems group will destroy the current instance if it is
2010 not referenced by a model.
2012 It is attached to each instance of the delegate.
2016 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
2018 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
2020 It is attached to each instance of the delegate.
2023 void QQuickVisualDataModelAttached::emitChanges()
2025 if (m_modelChanged) {
2026 m_modelChanged = false;
2027 emit modelChanged();
2030 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2031 m_previousGroups = m_cacheItem->groups;
2033 int indexChanges = 0;
2034 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2035 if (m_previousIndex[i] != m_currentIndex[i]) {
2036 m_previousIndex[i] = m_currentIndex[i];
2037 indexChanges |= (1 << i);
2042 const QMetaObject *meta = metaObject();
2043 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2044 if (groupChanges & (1 << i))
2045 QMetaObject::activate(this, meta, notifierId, 0);
2047 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2048 if (indexChanges & (1 << i))
2049 QMetaObject::activate(this, meta, notifierId, 0);
2053 emit groupsChanged();
2056 //============================================================================
2058 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
2065 bool QQuickVisualDataGroupPrivate::isChangedConnected()
2067 Q_Q(QQuickVisualDataGroup);
2068 IS_SIGNAL_CONNECTED(q, QQuickVisualDataGroup, changed, (const QQmlV8Handle &,const QQmlV8Handle &));
2071 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
2073 Q_Q(QQuickVisualDataGroup);
2074 if (isChangedConnected() && !changeSet.isEmpty()) {
2075 v8::HandleScope handleScope;
2076 v8::Context::Scope contextScope(engine->context());
2077 v8::Local<v8::Object> removed = engineData(engine)->array(engine, changeSet.removes());
2078 v8::Local<v8::Object> inserted = engineData(engine)->array(engine, changeSet.inserts());
2079 emit q->changed(QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
2081 if (changeSet.difference() != 0)
2082 emit q->countChanged();
2085 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
2087 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2088 it->emitModelUpdated(changeSet, reset);
2092 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
2094 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2095 it->createdPackage(index, package);
2098 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
2100 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2101 it->initPackage(index, package);
2104 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
2106 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2107 it->destroyingPackage(package);
2111 \qmlclass VisualDataGroup QQuickVisualDataGroup
2112 \inqmlmodule QtQuick 2
2113 \ingroup qtquick-models
2114 \brief Encapsulates a filtered set of visual data items
2118 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2119 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2123 QQuickVisualDataGroup::QQuickVisualDataGroup(
2124 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2125 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2127 Q_D(QQuickVisualDataGroup);
2129 d->setModel(model, Compositor::Group(index));
2132 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2137 \qmlproperty string QtQuick2::VisualDataGroup::name
2139 This property holds the name of the group.
2141 Each group in a model must have a unique name starting with a lower case letter.
2144 QString QQuickVisualDataGroup::name() const
2146 Q_D(const QQuickVisualDataGroup);
2150 void QQuickVisualDataGroup::setName(const QString &name)
2152 Q_D(QQuickVisualDataGroup);
2155 if (d->name != name) {
2162 \qmlproperty int QtQuick2::VisualDataGroup::count
2164 This property holds the number of items in the group.
2167 int QQuickVisualDataGroup::count() const
2169 Q_D(const QQuickVisualDataGroup);
2172 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2176 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2178 This property holds whether new items are assigned to this group by default.
2181 bool QQuickVisualDataGroup::defaultInclude() const
2183 Q_D(const QQuickVisualDataGroup);
2184 return d->defaultInclude;
2187 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2189 Q_D(QQuickVisualDataGroup);
2190 if (d->defaultInclude != include) {
2191 d->defaultInclude = include;
2195 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2197 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2199 emit defaultIncludeChanged();
2204 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2206 Returns a javascript object describing the item at \a index in the group.
2208 The returned object contains the same information that is available to a delegate from the
2209 VisualDataModel attached as well as the model for that item. It has the properties:
2212 \li \b model The model data of the item. This is the same as the model context property in
2214 \li \b groups A list the of names of groups the item is a member of. This property can be
2215 written to change the item's membership.
2216 \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2217 Writing to this property will add or remove the item from the group.
2218 \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2219 \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName. Writing to
2220 this property will add or remove the item from the group.
2221 \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2225 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2227 Q_D(QQuickVisualDataGroup);
2229 return QQmlV8Handle::fromHandle(v8::Undefined());;
2231 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2232 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2233 qmlInfo(this) << tr("get: index out of range");
2234 return QQmlV8Handle::fromHandle(v8::Undefined());
2237 Compositor::iterator it = model->m_compositor.find(d->group, index);
2238 QQuickVisualDataModelItem *cacheItem = it->inCache()
2239 ? model->m_cache.at(it.cacheIndex)
2243 cacheItem = model->m_adaptorModel.createItem(
2244 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2246 return QQmlV8Handle::fromHandle(v8::Undefined());
2247 cacheItem->groups = it->flags;
2249 model->m_cache.insert(it.cacheIndex, cacheItem);
2250 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2253 if (cacheItem->indexHandle.IsEmpty()) {
2254 if (model->m_cacheMetaType->constructor.IsEmpty())
2255 model->m_cacheMetaType->initializeConstructor();
2256 cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
2257 cacheItem->indexHandle->SetExternalResource(cacheItem);
2258 cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
2260 ++cacheItem->scriptRef;
2263 return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
2266 bool QQuickVisualDataGroupPrivate::parseIndex(
2267 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2269 if (value->IsInt32()) {
2270 *index = value->Int32Value();
2272 } else if (value->IsObject()) {
2273 v8::Local<v8::Object> object = value->ToObject();
2274 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2275 if (QQuickVisualDataModelPrivate *model = cacheItem && cacheItem->metaType->model
2276 ? QQuickVisualDataModelPrivate::get(cacheItem->metaType->model)
2278 *index = model->m_cache.indexOf(cacheItem);
2279 *group = Compositor::Cache;
2286 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2288 Q_D(QQuickVisualDataGroup);
2289 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2291 int index = model->m_compositor.count(d->group);
2292 Compositor::Group group = d->group;
2294 if (args->Length() == 0)
2298 v8::Local<v8::Value> v = (*args)[i];
2299 if (d->parseIndex(v, &index, &group)) {
2300 if (index < 0 || index > model->m_compositor.count(group)) {
2301 qmlInfo(this) << tr("insert: index out of range");
2304 if (++i == args->Length())
2309 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2310 ? model->m_compositor.findInsertPosition(group, index)
2311 : model->m_compositor.end();
2313 int groups = 1 << d->group;
2314 if (++i < args->Length())
2315 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2319 } else if (v->IsObject()) {
2320 model->insert(before, v->ToObject(), groups);
2321 model->emitChanges();
2326 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2327 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2328 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2330 Returns a reference to the instantiated item at \a index in the group.
2332 All items returned by create are added to the persistedItems group. Items in this
2333 group remain instantiated when not referenced by any view.
2336 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2338 Q_D(QQuickVisualDataGroup);
2342 if (args->Length() == 0)
2345 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2347 int index = model->m_compositor.count(d->group);
2348 Compositor::Group group = d->group;
2351 v8::Local<v8::Value> v = (*args)[i];
2352 if (d->parseIndex(v, &index, &group))
2355 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2357 if (v->IsObject()) {
2358 int groups = 1 << d->group;
2359 if (++i < args->Length())
2360 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2362 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2363 ? model->m_compositor.findInsertPosition(group, index)
2364 : model->m_compositor.end();
2366 index = before.index[d->group];
2369 if (!model->insert(before, v->ToObject(), groups)) {
2374 if (index < 0 || index >= model->m_compositor.count(group)) {
2375 qmlInfo(this) << tr("create: index out of range");
2379 QObject *object = model->object(group, index, false);
2381 QVector<Compositor::Insert> inserts;
2382 Compositor::iterator it = model->m_compositor.find(group, index);
2383 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2384 model->itemsInserted(inserts);
2385 model->m_cache.at(it.cacheIndex)->releaseObject();
2388 args->returnValue(args->engine()->newQObject(object));
2389 model->emitChanges();
2392 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2394 Q_D(QQuickVisualDataGroup);
2398 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2400 if (args->Length() < 2)
2405 Compositor::Group fromGroup = d->group;
2406 Compositor::Group toGroup = d->group;
2408 v8::Local<v8::Value> v = (*args)[0];
2409 if (d->parseIndex(v, &from, &fromGroup)) {
2410 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2411 qmlInfo(this) << tr("resolve: from index out of range");
2415 qmlInfo(this) << tr("resolve: from index invalid");
2420 if (d->parseIndex(v, &to, &toGroup)) {
2421 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2422 qmlInfo(this) << tr("resolve: to index out of range");
2426 qmlInfo(this) << tr("resolve: to index invalid");
2430 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2431 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2433 if (!fromIt->isUnresolved()) {
2434 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2438 qmlInfo(this) << tr("resolve: to is not a model item");
2442 const int unresolvedFlags = fromIt->flags;
2443 const int resolvedFlags = toIt->flags;
2444 const int resolvedIndex = toIt.modelIndex();
2445 void * const resolvedList = toIt->list;
2447 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2448 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2450 if (toIt.cacheIndex > fromIt.cacheIndex)
2451 toIt.decrementIndexes(1, unresolvedFlags);
2452 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2456 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2457 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2458 model->itemsInserted(
2459 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2460 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2461 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2463 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2464 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2466 if (resolvedFlags & Compositor::CacheFlag)
2467 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2469 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2471 if (!cacheItem->isReferenced()) {
2472 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2473 model->m_cache.removeAt(toIt.cacheIndex);
2474 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2476 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2478 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2479 if (cacheItem->attached)
2480 cacheItem->attached->emitUnresolvedChanged();
2483 model->emitChanges();
2487 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2489 Removes \a count items starting at \a index from the group.
2492 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2494 Q_D(QQuickVisualDataGroup);
2497 Compositor::Group group = d->group;
2501 if (args->Length() == 0)
2505 v8::Local<v8::Value> v = (*args)[i];
2506 if (!d->parseIndex(v, &index, &group)) {
2507 qmlInfo(this) << tr("remove: invalid index");
2511 if (++i < args->Length()) {
2514 count = v->Int32Value();
2517 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2518 if (index < 0 || index >= model->m_compositor.count(group)) {
2519 qmlInfo(this) << tr("remove: index out of range");
2520 } else if (count != 0) {
2521 Compositor::iterator it = model->m_compositor.find(group, index);
2522 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2523 qmlInfo(this) << tr("remove: invalid count");
2525 model->removeGroups(it, count, d->group, 1 << d->group);
2530 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2531 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2533 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2536 if (args->Length() < 2)
2540 v8::Local<v8::Value> v = (*args)[i];
2541 if (!parseIndex(v, index, group))
2546 *count = v->Int32Value();
2548 if (++i == args->Length())
2553 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2559 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2561 Adds \a count items starting at \a index to \a groups.
2564 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2566 Q_D(QQuickVisualDataGroup);
2567 Compositor::Group group = d->group;
2572 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2575 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2576 if (index < 0 || index >= model->m_compositor.count(group)) {
2577 qmlInfo(this) << tr("addGroups: index out of range");
2578 } else if (count != 0) {
2579 Compositor::iterator it = model->m_compositor.find(group, index);
2580 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2581 qmlInfo(this) << tr("addGroups: invalid count");
2583 model->addGroups(it, count, d->group, groups);
2589 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2591 Removes \a count items starting at \a index from \a groups.
2594 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2596 Q_D(QQuickVisualDataGroup);
2597 Compositor::Group group = d->group;
2602 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2605 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2606 if (index < 0 || index >= model->m_compositor.count(group)) {
2607 qmlInfo(this) << tr("removeGroups: index out of range");
2608 } else if (count != 0) {
2609 Compositor::iterator it = model->m_compositor.find(group, index);
2610 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2611 qmlInfo(this) << tr("removeGroups: invalid count");
2613 model->removeGroups(it, count, d->group, groups);
2619 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2621 Sets the \a groups \a count items starting at \a index belong to.
2624 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2626 Q_D(QQuickVisualDataGroup);
2627 Compositor::Group group = d->group;
2632 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2635 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2636 if (index < 0 || index >= model->m_compositor.count(group)) {
2637 qmlInfo(this) << tr("setGroups: index out of range");
2638 } else if (count != 0) {
2639 Compositor::iterator it = model->m_compositor.find(group, index);
2640 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2641 qmlInfo(this) << tr("setGroups: invalid count");
2643 model->setGroups(it, count, d->group, groups);
2649 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2651 Sets the \a groups \a count items starting at \a index belong to.
2655 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2657 Moves \a count at \a from in a group \a to a new position.
2660 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2662 Q_D(QQuickVisualDataGroup);
2664 if (args->Length() < 2)
2667 Compositor::Group fromGroup = d->group;
2668 Compositor::Group toGroup = d->group;
2673 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2674 qmlInfo(this) << tr("move: invalid from index");
2678 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2679 qmlInfo(this) << tr("move: invalid to index");
2683 if (args->Length() > 2) {
2684 v8::Local<v8::Value> v = (*args)[2];
2686 count = v->Int32Value();
2689 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2692 qmlInfo(this) << tr("move: invalid count");
2693 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2694 qmlInfo(this) << tr("move: from index out of range");
2695 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2696 qmlInfo(this) << tr("move: to index out of range");
2697 } else if (count > 0) {
2698 QVector<Compositor::Remove> removes;
2699 QVector<Compositor::Insert> inserts;
2701 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2702 model->itemsMoved(removes, inserts);
2703 model->emitChanges();
2709 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2711 This handler is called when items have been removed from or inserted into the group.
2713 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2714 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2716 Each index is adjusted for previous changes with all removed items preceding any inserted
2720 //============================================================================
2722 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2723 : QQuickVisualModel(*new QObjectPrivate, parent)
2726 , m_compositorGroup(Compositor::Cache)
2727 , m_inheritGroup(true)
2729 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2730 if (d->m_cacheMetaType) {
2731 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2732 m_compositorGroup = Compositor::Default;
2734 d->m_pendingParts.insert(this);
2738 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2742 QString QQuickVisualPartsModel::filterGroup() const
2745 return m_model->filterGroup();
2746 return m_filterGroup;
2749 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2751 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2752 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2756 if (m_filterGroup != group || m_inheritGroup) {
2757 m_filterGroup = group;
2758 m_inheritGroup = false;
2759 updateFilterGroup();
2761 emit filterGroupChanged();
2765 void QQuickVisualPartsModel::resetFilterGroup()
2767 if (!m_inheritGroup) {
2768 m_inheritGroup = true;
2769 updateFilterGroup();
2770 emit filterGroupChanged();
2774 void QQuickVisualPartsModel::updateFilterGroup()
2776 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2777 if (!model->m_cacheMetaType)
2780 if (m_inheritGroup) {
2781 if (m_filterGroup == model->m_filterGroup)
2783 m_filterGroup = model->m_filterGroup;
2786 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2787 m_compositorGroup = Compositor::Default;
2788 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2789 for (int i = 1; i < model->m_groupCount; ++i) {
2790 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2791 m_compositorGroup = Compositor::Group(i);
2796 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2797 if (m_compositorGroup != previousGroup) {
2798 QVector<QQuickChangeSet::Remove> removes;
2799 QVector<QQuickChangeSet::Insert> inserts;
2800 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2802 QQuickChangeSet changeSet;
2803 changeSet.apply(removes, inserts);
2804 if (!changeSet.isEmpty())
2805 emit modelUpdated(changeSet, false);
2807 if (changeSet.difference() != 0)
2808 emit countChanged();
2812 void QQuickVisualPartsModel::updateFilterGroup(
2813 Compositor::Group group, const QQuickChangeSet &changeSet)
2815 if (!m_inheritGroup)
2818 m_compositorGroup = group;
2819 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2821 if (!changeSet.isEmpty())
2822 emit modelUpdated(changeSet, false);
2824 if (changeSet.difference() != 0)
2825 emit countChanged();
2827 emit filterGroupChanged();
2830 int QQuickVisualPartsModel::count() const
2832 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2833 return model->m_delegate
2834 ? model->m_compositor.count(m_compositorGroup)
2838 bool QQuickVisualPartsModel::isValid() const
2840 return m_model->isValid();
2843 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2845 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2847 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2848 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2852 QObject *object = model->object(m_compositorGroup, index, asynchronous);
2854 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
2855 QObject *part = package->part(m_part);
2858 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(part)) {
2859 m_packaged.insertMulti(item, package);
2864 model->release(object);
2865 if (!model->m_delegateValidated) {
2867 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2868 model->m_delegateValidated = true;
2874 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2876 QQuickVisualModel::ReleaseFlags flags = 0;
2878 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2879 if (it != m_packaged.end()) {
2880 QQuickPackage *package = *it;
2881 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2882 flags = model->release(package);
2883 m_packaged.erase(it);
2884 if (!m_packaged.contains(item))
2885 flags &= ~Referenced;
2886 if (flags & Destroyed)
2887 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2892 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2894 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2897 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2899 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2900 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2901 m_watchedRoles = roles;
2904 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2906 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2907 if (it != m_packaged.end()) {
2908 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2909 return cacheItem->groupIndex(m_compositorGroup);
2914 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2916 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2917 emit createdItem(index, item);
2920 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2922 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2923 emit initItem(index, item);
2926 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2928 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part))) {
2929 Q_ASSERT(!m_packaged.contains(item));
2930 emit destroyingItem(item);
2931 item->setParentItem(0);
2935 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2937 emit modelUpdated(changeSet, reset);
2938 if (changeSet.difference() != 0)
2939 emit countChanged();
2942 //============================================================================
2944 v8::Handle<v8::Value> get_change_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
2946 return info.This()->GetInternalField(0);
2949 v8::Handle<v8::Value> get_change_count(v8::Local<v8::String>, const v8::AccessorInfo &info)
2951 return info.This()->GetInternalField(1);
2954 v8::Handle<v8::Value> get_change_moveId(v8::Local<v8::String>, const v8::AccessorInfo &info)
2956 return info.This()->GetInternalField(2);
2959 class QQuickVisualDataGroupChangeArray : public QV8ObjectResource
2961 V8_RESOURCE_TYPE(ChangeSetArrayType)
2963 QQuickVisualDataGroupChangeArray(QV8Engine *engine)
2964 : QV8ObjectResource(engine)
2968 virtual quint32 count() const = 0;
2969 virtual const QQuickChangeSet::Change &at(int index) const = 0;
2971 static v8::Handle<v8::Value> get_change(quint32 index, const v8::AccessorInfo &info)
2973 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2975 V8THROW_ERROR("Not a valid change array");
2977 if (index >= array->count())
2978 return v8::Undefined();
2980 const QQuickChangeSet::Change &change = array->at(index);
2982 v8::Local<v8::Object> object = engineData(array->engine)->constructorChange->NewInstance();
2983 object->SetInternalField(0, v8::Int32::New(change.index));
2984 object->SetInternalField(1, v8::Int32::New(change.count));
2985 if (change.isMove())
2986 object->SetInternalField(2, v8::Int32::New(change.moveId));
2991 static v8::Handle<v8::Value> get_length(v8::Local<v8::String>, const v8::AccessorInfo &info)
2993 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2995 V8THROW_ERROR("Not a valid change array");
2997 return v8::Integer::New(array->count());
3000 static v8::Local<v8::Function> constructor()
3002 v8::Local<v8::FunctionTemplate> changeArray = v8::FunctionTemplate::New();
3003 changeArray->InstanceTemplate()->SetHasExternalResource(true);
3004 changeArray->InstanceTemplate()->SetIndexedPropertyHandler(get_change);
3005 changeArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), get_length);
3006 return changeArray->GetFunction();
3010 class QQuickVisualDataGroupRemoveArray : public QQuickVisualDataGroupChangeArray
3013 QQuickVisualDataGroupRemoveArray(QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3014 : QQuickVisualDataGroupChangeArray(engine)
3019 quint32 count() const { return changes.count(); }
3020 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3023 QVector<QQuickChangeSet::Remove> changes;
3026 class QQuickVisualDataGroupInsertArray : public QQuickVisualDataGroupChangeArray
3029 QQuickVisualDataGroupInsertArray(QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3030 : QQuickVisualDataGroupChangeArray(engine)
3035 quint32 count() const { return changes.count(); }
3036 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3039 QVector<QQuickChangeSet::Insert> changes;
3042 QQuickVisualDataModelEngineData::QQuickVisualDataModelEngineData(QV8Engine *)
3044 strings = qPersistentNew(v8::Array::New(StringCount));
3045 strings->Set(Model, v8::String::New("model"));
3046 strings->Set(Groups, v8::String::New("groups"));
3047 strings->Set(IsUnresolved, v8::String::New("isUnresolved"));
3048 strings->Set(ItemsIndex, v8::String::New("itemsIndex"));
3049 strings->Set(PersistedItemsIndex, v8::String::New("persistedItemsIndex"));
3050 strings->Set(InItems, v8::String::New("inItems"));
3051 strings->Set(InPersistedItems, v8::String::New("inPersistedItems"));
3053 v8::Local<v8::FunctionTemplate> change = v8::FunctionTemplate::New();
3054 change->InstanceTemplate()->SetAccessor(v8::String::New("index"), get_change_index);
3055 change->InstanceTemplate()->SetAccessor(v8::String::New("count"), get_change_count);
3056 change->InstanceTemplate()->SetAccessor(v8::String::New("moveId"), get_change_moveId);
3057 change->InstanceTemplate()->SetInternalFieldCount(3);
3058 constructorChange = qPersistentNew(change->GetFunction());
3059 constructorChangeArray = qPersistentNew(QQuickVisualDataGroupChangeArray::constructor());
3062 QQuickVisualDataModelEngineData::~QQuickVisualDataModelEngineData()
3064 qPersistentDispose(strings);
3065 qPersistentDispose(constructorChange);
3066 qPersistentDispose(constructorChangeArray);
3069 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3070 QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3072 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3073 array->SetExternalResource(new QQuickVisualDataGroupRemoveArray(engine, changes));
3077 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3078 QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3080 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3081 array->SetExternalResource(new QQuickVisualDataGroupInsertArray(engine, changes));