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 The VisualDataModel type encapsulates a model and the delegate that will
129 be instantiated for items in the model.
131 It is usually not necessary to create a VisualDataModel.
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
711 For example, the code below selects a model which creates
712 delegates named \e list from a \l Package:
718 Item { Package.name: "list" }
724 width: 200; height:200
725 model: visualModel.parts.list
732 QObject *QQuickVisualDataModel::parts()
734 Q_D(QQuickVisualDataModel);
736 d->m_parts = new QQuickVisualDataModelParts(this);
740 void QQuickVisualDataModelPrivate::emitCreatedPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
742 for (int i = 1; i < m_groupCount; ++i)
743 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
746 void QQuickVisualDataModelPrivate::emitInitPackage(QVDMIncubationTask *incubationTask, QQuickPackage *package)
748 for (int i = 1; i < m_groupCount; ++i)
749 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
752 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
754 for (int i = 1; i < m_groupCount; ++i)
755 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
758 void QVDMIncubationTask::statusChanged(Status status)
760 vdm->incubatorStatusChanged(this, status);
763 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
765 Q_Q(QQuickVisualDataModel);
766 if (!incubationTask->isError())
767 incubationTask->clear();
768 m_finishedIncubating.append(incubationTask);
769 if (!m_incubatorCleanupScheduled) {
770 m_incubatorCleanupScheduled = true;
771 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
775 void QQuickVisualDataModelPrivate::removeCacheItem(QQuickVisualDataModelItem *cacheItem)
777 int cidx = m_cache.indexOf(cacheItem);
779 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
780 m_cache.removeAt(cidx);
782 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
785 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
787 Q_Q(QQuickVisualDataModel);
788 if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
791 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
792 cacheItem->incubationTask = 0;
793 incubationTask->incubating = 0;
794 releaseIncubator(incubationTask);
796 if (status == QQmlIncubator::Ready) {
797 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
798 emitCreatedItem(incubationTask, item);
799 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
800 emitCreatedPackage(incubationTask, package);
801 } else if (status == QQmlIncubator::Error) {
802 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
805 if (!cacheItem->isObjectReferenced()) {
806 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
807 emitDestroyingItem(item);
808 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
809 emitDestroyingPackage(package);
810 delete cacheItem->object;
811 cacheItem->object = 0;
812 cacheItem->scriptRef -= 1;
813 cacheItem->contextData->destroy();
814 cacheItem->contextData = 0;
815 if (!cacheItem->isReferenced()) {
816 removeCacheItem(cacheItem);
822 void QVDMIncubationTask::setInitialState(QObject *o)
824 vdm->setInitialState(this, o);
827 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
829 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
830 cacheItem->object = o;
832 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(cacheItem->object))
833 emitInitItem(incubationTask, item);
834 else if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
835 emitInitPackage(incubationTask, package);
838 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous)
840 Q_Q(QQuickVisualDataModel);
841 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
842 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
846 Compositor::iterator it = m_compositor.find(group, index);
848 QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
851 cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), it.modelIndex());
855 cacheItem->groups = it->flags;
857 m_cache.insert(it.cacheIndex, cacheItem);
858 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
859 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
862 // Bump the reference counts temporarily so neither the content data or the delegate object
863 // are deleted if incubatorStatusChanged() is called synchronously.
864 cacheItem->scriptRef += 1;
865 cacheItem->referenceObject();
867 if (cacheItem->incubationTask) {
868 if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
869 // previously requested async - now needed immediately
870 cacheItem->incubationTask->forceCompletion();
872 } else if (!cacheItem->object) {
873 QQmlContext *creationContext = m_delegate->creationContext();
875 cacheItem->scriptRef += 1;
877 cacheItem->incubationTask = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
878 cacheItem->incubationTask->incubating = cacheItem;
879 cacheItem->incubationTask->clear();
881 for (int i = 1; i < m_groupCount; ++i)
882 cacheItem->incubationTask->index[i] = it.index[i];
884 QQmlContextData *ctxt = new QQmlContextData;
885 ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context));
886 ctxt->contextObject = cacheItem;
887 cacheItem->contextData = ctxt;
889 if (m_adaptorModel.hasProxyObject()) {
890 if (QQuickVisualAdaptorModelProxyInterface *proxy
891 = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
892 ctxt = new QQmlContextData;
893 ctxt->setParent(cacheItem->contextData, true);
894 ctxt->contextObject = proxy->proxiedObject();
898 cacheItem->incubateObject(
902 QQmlContextData::get(m_context));
905 if (index == m_compositor.count(group) - 1 && m_adaptorModel.canFetchMore())
906 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
908 // Remove the temporary reference count.
909 cacheItem->scriptRef -= 1;
910 if (cacheItem->object)
911 return cacheItem->object;
913 cacheItem->releaseObject();
914 if (!cacheItem->isReferenced()) {
915 removeCacheItem(cacheItem);
923 If asynchronous is true or the component is being loaded asynchronously due
924 to an ancestor being loaded asynchronously, item() may return 0. In this
925 case itemCreated() will be emitted when the item is available. The item
926 at this stage does not have any references, so item() must be called again
927 to ensure a reference is held. Any call to item() which returns a valid item
928 must be matched by a call to release() in order to destroy the item.
930 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
932 Q_D(QQuickVisualDataModel);
933 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
934 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
938 QObject *object = d->object(d->m_compositorGroup, index, asynchronous);
942 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
946 if (!d->m_delegateValidated) {
948 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
949 d->m_delegateValidated = true;
954 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
956 Compositor::iterator it = m_compositor.find(group, index);
957 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
959 int dot = name.indexOf(QLatin1Char('.'));
961 role = name.left(dot);
962 QVariant value = model->value(it.modelIndex(), role);
964 QObject *obj = qvariant_cast<QObject*>(value);
968 dot = name.indexOf(QLatin1Char('.'), from);
969 value = obj->property(name.mid(from, dot-from).toUtf8());
971 return value.toString();
976 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
978 Q_D(QQuickVisualDataModel);
979 return d->stringValue(d->m_compositorGroup, index, name);
982 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
984 Q_D(const QQuickVisualDataModel);
985 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
986 return cacheItem->groupIndex(d->m_compositorGroup);
990 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
992 Q_D(QQuickVisualDataModel);
993 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
994 d->m_watchedRoles = roles;
997 void QQuickVisualDataModelPrivate::addGroups(
998 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1000 QVector<Compositor::Insert> inserts;
1001 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1002 itemsInserted(inserts);
1006 void QQuickVisualDataModelPrivate::removeGroups(
1007 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1009 QVector<Compositor::Remove> removes;
1010 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
1011 itemsRemoved(removes);
1015 void QQuickVisualDataModelPrivate::setGroups(
1016 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1018 QVector<Compositor::Remove> removes;
1019 QVector<Compositor::Insert> inserts;
1021 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1022 itemsInserted(inserts);
1023 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1025 from = m_compositor.find(from.group, from.index[from.group]);
1026 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1027 itemsRemoved(removes);
1031 bool QQuickVisualDataModel::event(QEvent *e)
1033 Q_D(QQuickVisualDataModel);
1034 if (e->type() == QEvent::UpdateRequest) {
1035 d->m_adaptorModel.fetchMore();
1036 } else if (e->type() == QEvent::User) {
1037 d->m_incubatorCleanupScheduled = false;
1038 qDeleteAll(d->m_finishedIncubating);
1039 d->m_finishedIncubating.clear();
1041 return QQuickVisualModel::event(e);
1044 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1049 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1051 foreach (const Compositor::Change &change, changes) {
1052 for (int i = 1; i < m_groupCount; ++i) {
1053 if (change.inGroup(i)) {
1054 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
1059 for (int i = 1; i < m_groupCount; ++i)
1060 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
1063 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
1065 Q_D(QQuickVisualDataModel);
1066 if (count <= 0 || !d->m_complete)
1069 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1070 QVector<Compositor::Change> changes;
1071 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1072 d->itemsChanged(changes);
1077 static void incrementIndexes(QQuickVisualDataModelItem *cacheItem, int count, const int *deltas)
1079 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1080 for (int i = 1; i < count; ++i)
1081 incubationTask->index[i] += deltas[i];
1083 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1084 for (int i = 1; i < count; ++i)
1085 attached->m_currentIndex[i] += deltas[i];
1089 void QQuickVisualDataModelPrivate::itemsInserted(
1090 const QVector<Compositor::Insert> &inserts,
1091 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
1092 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1096 int inserted[Compositor::MaximumGroupCount];
1097 for (int i = 1; i < m_groupCount; ++i)
1100 foreach (const Compositor::Insert &insert, inserts) {
1101 for (; cacheIndex < insert.cacheIndex; ++cacheIndex)
1102 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1104 for (int i = 1; i < m_groupCount; ++i) {
1105 if (insert.inGroup(i)) {
1106 (*translatedInserts)[i].append(
1107 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1108 inserted[i] += insert.count;
1112 if (!insert.inCache())
1115 if (movedItems && insert.isMove()) {
1116 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1117 Q_ASSERT(items.count() == insert.count);
1118 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1120 if (insert.inGroup()) {
1121 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1122 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1123 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1125 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1126 for (int i = 1; i < m_groupCount; ++i)
1127 incubationTask->index[i] = cacheItem->groups & (1 << i)
1128 ? insert.index[i] + offset
1131 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1132 for (int i = 1; i < m_groupCount; ++i)
1133 attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1134 ? insert.index[i] + offset
1139 cacheIndex = insert.cacheIndex + insert.count;
1142 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1143 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1146 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1148 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1149 itemsInserted(inserts, &translatedInserts);
1150 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1154 for (int i = 1; i < m_groupCount; ++i)
1155 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1158 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1161 Q_D(QQuickVisualDataModel);
1162 if (count <= 0 || !d->m_complete)
1165 d->m_count += count;
1167 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1168 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1169 if (item->modelIndex() >= index)
1170 item->setModelIndex(item->modelIndex() + count);
1173 QVector<Compositor::Insert> inserts;
1174 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1175 d->itemsInserted(inserts);
1179 void QQuickVisualDataModelPrivate::itemsRemoved(
1180 const QVector<Compositor::Remove> &removes,
1181 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1182 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1185 int removedCache = 0;
1187 int removed[Compositor::MaximumGroupCount];
1188 for (int i = 1; i < m_groupCount; ++i)
1191 foreach (const Compositor::Remove &remove, removes) {
1192 for (; cacheIndex < remove.cacheIndex; ++cacheIndex)
1193 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1195 for (int i = 1; i < m_groupCount; ++i) {
1196 if (remove.inGroup(i)) {
1197 (*translatedRemoves)[i].append(
1198 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1199 removed[i] -= remove.count;
1203 if (!remove.inCache())
1206 if (movedItems && remove.isMove()) {
1207 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1208 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1209 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1210 m_cache.erase(begin, end);
1212 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1213 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1214 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1215 QObject *object = cacheItem->object;
1216 cacheItem->destroyObject();
1217 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1218 emitDestroyingPackage(package);
1219 else if (QQuickItem *item = qmlobject_cast<QQuickItem *>(object))
1220 emitDestroyingItem(item);
1221 cacheItem->scriptRef -= 1;
1223 if (!cacheItem->isReferenced()) {
1224 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1225 m_cache.removeAt(cacheIndex);
1229 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1230 } else if (remove.groups() == cacheItem->groups) {
1231 cacheItem->groups = 0;
1232 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1233 for (int i = 1; i < m_groupCount; ++i)
1234 incubationTask->index[i] = -1;
1236 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1237 for (int i = 1; i < m_groupCount; ++i)
1238 attached->m_currentIndex[i] = -1;
1241 if (QVDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1242 for (int i = 1; i < m_groupCount; ++i) {
1243 if (remove.inGroup(i))
1244 incubationTask->index[i] = remove.index[i];
1247 if (QQuickVisualDataModelAttached *attached = cacheItem->attached) {
1248 for (int i = 1; i < m_groupCount; ++i) {
1249 if (remove.inGroup(i))
1250 attached->m_currentIndex[i] = remove.index[i];
1253 cacheItem->groups &= ~remove.flags;
1259 for (; cacheIndex < m_cache.count(); ++cacheIndex)
1260 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1263 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1265 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1266 itemsRemoved(removes, &translatedRemoves);
1267 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1271 for (int i = 1; i < m_groupCount; ++i)
1272 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1275 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1277 Q_D(QQuickVisualDataModel);
1278 if (count <= 0|| !d->m_complete)
1281 d->m_count -= count;
1283 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1284 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1285 if (item->modelIndex() >= index + count)
1286 item->setModelIndex(item->modelIndex() - count);
1287 else if (item->modelIndex() >= index)
1288 item->setModelIndex(-1);
1291 QVector<Compositor::Remove> removes;
1292 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1293 d->itemsRemoved(removes);
1298 void QQuickVisualDataModelPrivate::itemsMoved(
1299 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1301 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1303 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1304 itemsRemoved(removes, &translatedRemoves, &movedItems);
1306 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1307 itemsInserted(inserts, &translatedInserts, &movedItems);
1308 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1309 Q_ASSERT(movedItems.isEmpty());
1313 for (int i = 1; i < m_groupCount; ++i) {
1314 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1315 translatedRemoves.at(i),
1316 translatedInserts.at(i));
1320 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1322 Q_D(QQuickVisualDataModel);
1323 if (count <= 0 || !d->m_complete)
1326 const int minimum = qMin(from, to);
1327 const int maximum = qMax(from, to) + count;
1328 const int difference = from > to ? count : -count;
1330 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1331 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1332 if (item->modelIndex() >= from && item->modelIndex() < from + count)
1333 item->setModelIndex(item->modelIndex() - from + to);
1334 else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1335 item->setModelIndex(item->modelIndex() + difference);
1338 QVector<Compositor::Remove> removes;
1339 QVector<Compositor::Insert> inserts;
1340 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1341 d->itemsMoved(removes, inserts);
1345 template <typename T> v8::Local<v8::Array>
1346 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1348 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1349 v8::Local<v8::String> indexKey = v8::String::New("index");
1350 v8::Local<v8::String> countKey = v8::String::New("count");
1351 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1353 for (int i = 0; i < changes.count(); ++i) {
1354 v8::Local<v8::Object> object = v8::Object::New();
1355 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1356 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1357 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1358 indexes->Set(i, object);
1363 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1365 Q_Q(QQuickVisualDataModel);
1366 emit q->modelUpdated(changeSet, reset);
1367 if (changeSet.difference() != 0)
1368 emit q->countChanged();
1371 void QQuickVisualDataModelPrivate::emitChanges()
1373 if (m_transaction || !m_complete)
1376 m_transaction = true;
1377 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1378 for (int i = 1; i < m_groupCount; ++i)
1379 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1380 m_transaction = false;
1382 const bool reset = m_reset;
1384 for (int i = 1; i < m_groupCount; ++i)
1385 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1387 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1388 if (cacheItem->attached)
1389 cacheItem->attached->emitChanges();
1393 void QQuickVisualDataModel::_q_modelReset()
1395 Q_D(QQuickVisualDataModel);
1399 int oldCount = d->m_count;
1400 d->m_adaptorModel.rootIndex = QModelIndex();
1402 if (d->m_complete) {
1403 d->m_count = d->m_adaptorModel.count();
1405 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1406 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1407 if (item->modelIndex() != -1)
1408 item->setModelIndex(-1);
1411 QVector<Compositor::Remove> removes;
1412 QVector<Compositor::Insert> inserts;
1414 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1416 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1417 d->itemsMoved(removes, inserts);
1420 if (d->m_adaptorModel.canFetchMore())
1421 d->m_adaptorModel.fetchMore();
1425 emit rootIndexChanged();
1428 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1430 Q_D(QQuickVisualDataModel);
1431 if (parent == d->m_adaptorModel.rootIndex)
1432 _q_itemsInserted(begin, end - begin + 1);
1435 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1437 Q_D(QQuickVisualDataModel);
1438 if (parent == d->m_adaptorModel.rootIndex)
1439 _q_itemsRemoved(begin, end - begin + 1);
1442 void QQuickVisualDataModel::_q_rowsMoved(
1443 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1444 const QModelIndex &destinationParent, int destinationRow)
1446 Q_D(QQuickVisualDataModel);
1447 const int count = sourceEnd - sourceStart + 1;
1448 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1449 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1450 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1451 _q_itemsRemoved(sourceStart, count);
1452 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1453 _q_itemsInserted(destinationRow, count);
1457 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
1459 Q_D(QQuickVisualDataModel);
1460 if (begin.parent() == d->m_adaptorModel.rootIndex)
1461 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
1464 void QQuickVisualDataModel::_q_layoutChanged()
1466 Q_D(QQuickVisualDataModel);
1467 _q_itemsChanged(0, d->m_count, QVector<int>());
1470 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1472 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1473 if (cacheItem->object == obj) { // Don't create attached item for child objects.
1474 cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1475 return cacheItem->attached;
1478 return new QQuickVisualDataModelAttached(obj);
1481 bool QQuickVisualDataModelPrivate::insert(
1482 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1484 QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1488 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1489 for (uint i = 0; i < propertyNames->Length(); ++i) {
1490 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1491 cacheItem->setValue(
1492 m_cacheMetaType->v8Engine->toString(propertyName),
1493 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1496 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1498 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1499 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1501 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1502 m_cache.insert(before.cacheIndex, cacheItem);
1507 //============================================================================
1509 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1510 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1512 , groupCount(groupNames.count() + 1)
1515 , groupNames(groupNames)
1519 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1522 metaObject->release();
1523 qPersistentDispose(constructor);
1526 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1528 QMetaObjectBuilder builder;
1529 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1530 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1531 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1534 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1535 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1536 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1537 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1538 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1539 propertyName.toUtf8(), "bool", notifierId);
1540 propertyBuilder.setWritable(true);
1542 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1543 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1544 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1545 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1546 propertyName.toUtf8(), "int", notifierId);
1547 propertyBuilder.setWritable(true);
1550 metaObject = new QQuickVisualDataModelAttachedMetaObject(this, builder.toMetaObject());
1553 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1555 v8::HandleScope handleScope;
1556 v8::Context::Scope contextScope(v8Engine->context());
1558 QQuickVisualDataModelEngineData *data = engineData(v8Engine);
1560 constructor = qPersistentNew(v8::ObjectTemplate::New());
1562 constructor->SetHasExternalResource(true);
1563 constructor->SetAccessor(data->model(), get_model);
1564 constructor->SetAccessor(data->groups(), get_groups, set_groups);
1565 constructor->SetAccessor(data->isUnresolved(), get_member, 0, v8::Int32::New(30));
1566 constructor->SetAccessor(data->inItems(), get_member, set_member, v8::Int32::New(1));
1567 constructor->SetAccessor(data->inPersistedItems(), get_member, set_member, v8::Int32::New(2));
1568 constructor->SetAccessor(data->itemsIndex(), get_index, 0, v8::Int32::New(1));
1569 constructor->SetAccessor(data->persistedItemsIndex(), get_index, 0, v8::Int32::New(2));
1571 for (int i = 2; i < groupNames.count(); ++i) {
1572 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1573 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1574 constructor->SetAccessor(
1575 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1577 for (int i = 2; i < groupNames.count(); ++i) {
1578 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1579 constructor->SetAccessor(
1580 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1584 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1587 foreach (const QString &groupName, groups) {
1588 int index = groupNames.indexOf(groupName);
1590 groupFlags |= 2 << index;
1595 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1598 if (groups->IsString()) {
1599 const QString groupName = v8Engine->toString(groups);
1600 int index = groupNames.indexOf(groupName);
1602 groupFlags |= 2 << index;
1603 } else if (groups->IsArray()) {
1604 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1605 for (uint i = 0; i < array->Length(); ++i) {
1606 const QString groupName = v8Engine->toString(array->Get(i));
1607 int index = groupNames.indexOf(groupName);
1609 groupFlags |= 2 << index;
1615 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1616 v8::Local<v8::String>, const v8::AccessorInfo &info)
1618 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1619 V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1620 if (!cacheItem->metaType->model)
1621 return v8::Undefined();
1623 return cacheItem->get();
1626 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1627 v8::Local<v8::String>, const v8::AccessorInfo &info)
1629 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1630 V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1633 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1634 if (cacheItem->groups & (1 << i))
1635 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1638 return cacheItem->engine->fromVariant(groups);
1641 void QQuickVisualDataModelItemMetaType::set_groups(
1642 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1644 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1645 V8ASSERT_TYPE_SETTER(cacheItem, "Not a valid VisualData object");
1647 if (!cacheItem->metaType->model)
1649 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1651 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1652 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1653 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1654 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1657 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1658 v8::Local<v8::String>, const v8::AccessorInfo &info)
1660 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1661 V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1663 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1666 void QQuickVisualDataModelItemMetaType::set_member(
1667 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1669 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1670 V8ASSERT_TYPE_SETTER(cacheItem, "Not a valid VisualData object");
1672 if (!cacheItem->metaType->model)
1674 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1676 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1677 const bool member = value->BooleanValue();
1678 const int groupFlag = (1 << group);
1679 if (member == ((cacheItem->groups & groupFlag) != 0))
1682 const int cacheIndex = model->m_cache.indexOf(cacheItem);
1683 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1685 model->addGroups(it, 1, Compositor::Cache, groupFlag);
1687 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
1690 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1691 v8::Local<v8::String>, const v8::AccessorInfo &info)
1693 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1694 V8ASSERT_TYPE(cacheItem, "Not a valid VisualData object");
1696 return v8::Integer::New(cacheItem->groupIndex(Compositor::Group(info.Data()->Int32Value())));
1700 //---------------------------------------------------------------------------
1702 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1703 QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1704 : QV8ObjectResource(metaType->v8Engine)
1705 , metaType(metaType)
1718 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1720 Q_ASSERT(scriptRef == 0);
1721 Q_ASSERT(objectRef == 0);
1724 if (incubationTask && metaType->model)
1725 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1727 metaType->release();
1731 void QQuickVisualDataModelItem::Dispose()
1737 if (metaType->model) {
1738 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1739 model->removeCacheItem(this);
1745 This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
1746 arguments instead of QQmlContext which means we don't have to construct the rather weighty
1747 wrapper class for every delegate item.
1749 void QQuickVisualDataModelItem::incubateObject(
1750 QQmlComponent *component,
1752 QQmlContextData *context,
1753 QQmlContextData *forContext)
1755 QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
1756 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
1757 QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
1759 incubatorPriv->compiledData = componentPriv->cc;
1760 incubatorPriv->compiledData->addref();
1761 incubatorPriv->vme.init(
1764 componentPriv->start,
1765 componentPriv->creationContext);
1767 enginePriv->incubate(*incubationTask, forContext);
1770 void QQuickVisualDataModelItem::destroyObject()
1773 Q_ASSERT(contextData);
1775 QObjectPrivate *p = QObjectPrivate::get(object);
1776 Q_ASSERT(p->declarativeData);
1777 QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1778 if (data->ownContext && data->context)
1779 data->context->clearContext();
1780 object->deleteLater();
1783 attached->m_cacheItem = 0;
1787 contextData->destroy();
1792 QQuickVisualDataModelItem *QQuickVisualDataModelItem::dataForObject(QObject *object)
1794 QObjectPrivate *p = QObjectPrivate::get(object);
1795 QQmlContextData *context = p->declarativeData
1796 ? static_cast<QQmlData *>(p->declarativeData)->context
1798 for (context = context ? context->parent : 0; context; context = context->parent) {
1799 if (QQuickVisualDataModelItem *cacheItem = qobject_cast<QQuickVisualDataModelItem *>(
1800 context->contextObject)) {
1807 int QQuickVisualDataModelItem::groupIndex(Compositor::Group group)
1809 if (QQuickVisualDataModelPrivate * const model = metaType->model
1810 ? QQuickVisualDataModelPrivate::get(metaType->model)
1812 return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
1817 //---------------------------------------------------------------------------
1819 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1820 QQuickVisualDataModelItemMetaType *metaType, QMetaObject *metaObject)
1821 : metaType(metaType)
1822 , metaObject(metaObject)
1823 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1824 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.count())
1826 // Don't reference count the meta-type here as that would create a circular reference.
1827 // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
1828 // destroying all delegates with attached objects.
1829 *static_cast<QMetaObject *>(this) = *metaObject;
1832 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1837 void QQuickVisualDataModelAttachedMetaObject::objectDestroyed(QObject *)
1842 int QQuickVisualDataModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::Call call, int _id, void **arguments)
1844 QQuickVisualDataModelAttached *attached = static_cast<QQuickVisualDataModelAttached *>(object);
1845 if (call == QMetaObject::ReadProperty) {
1846 if (_id >= indexPropertyOffset) {
1847 Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
1848 *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
1850 } else if (_id >= memberPropertyOffset) {
1851 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1852 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1855 } else if (call == QMetaObject::WriteProperty) {
1856 if (_id >= memberPropertyOffset) {
1857 if (!metaType->model)
1859 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1860 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
1861 const int groupFlag = 1 << group;
1862 const bool member = attached->m_cacheItem->groups & groupFlag;
1863 if (member && !*static_cast<bool *>(arguments[0])) {
1864 Compositor::iterator it = model->m_compositor.find(
1865 group, attached->m_currentIndex[group]);
1866 model->removeGroups(it, 1, group, groupFlag);
1867 } else if (!member && *static_cast<bool *>(arguments[0])) {
1868 for (int i = 1; i < metaType->groupCount; ++i) {
1869 if (attached->m_cacheItem->groups & (1 << i)) {
1870 Compositor::iterator it = model->m_compositor.find(
1871 Compositor::Group(i), attached->m_currentIndex[i]);
1872 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1880 return attached->qt_metacall(call, _id, arguments);
1883 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1885 , m_previousGroups(0)
1887 QQml_setParent_noEvent(this, parent);
1890 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1891 QQuickVisualDataModelItem *cacheItem, QObject *parent)
1892 : m_cacheItem(cacheItem)
1893 , m_previousGroups(cacheItem->groups)
1895 QQml_setParent_noEvent(this, parent);
1896 if (QVDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
1897 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1898 m_currentIndex[i] = m_previousIndex[i] = incubationTask->index[i];
1900 QQuickVisualDataModelPrivate * const model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1901 Compositor::iterator it = model->m_compositor.find(
1902 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
1903 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1904 m_currentIndex[i] = m_previousIndex[i] = it.index[i];
1907 if (!cacheItem->metaType->metaObject)
1908 cacheItem->metaType->initializeMetaObject();
1910 QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
1911 cacheItem->metaType->metaObject->addref();
1915 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1917 This attached property holds the visual data model this delegate instance belongs to.
1919 It is attached to each instance of the delegate.
1922 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1924 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1928 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1930 This attached property holds the name of VisualDataGroups the item belongs to.
1932 It is attached to each instance of the delegate.
1935 QStringList QQuickVisualDataModelAttached::groups() const
1941 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1942 if (m_cacheItem->groups & (1 << i))
1943 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1948 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1953 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1955 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1956 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
1957 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
1958 model->setGroups(it, 1, Compositor::Cache, groupFlags);
1961 bool QQuickVisualDataModelAttached::isUnresolved() const
1966 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1970 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1972 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1974 Changing this property will add or remove the item from the items group.
1976 It is attached to each instance of the delegate.
1980 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1982 This attached property holds the index of the item in the default \l items VisualDataGroup.
1984 It is attached to each instance of the delegate.
1988 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1990 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1992 Changing this property will add or remove the item from the items group. Change with caution
1993 as removing an item from the persistedItems group will destroy the current instance if it is
1994 not referenced by a model.
1996 It is attached to each instance of the delegate.
2000 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
2002 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
2004 It is attached to each instance of the delegate.
2007 void QQuickVisualDataModelAttached::emitChanges()
2009 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2010 m_previousGroups = m_cacheItem->groups;
2012 int indexChanges = 0;
2013 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2014 if (m_previousIndex[i] != m_currentIndex[i]) {
2015 m_previousIndex[i] = m_currentIndex[i];
2016 indexChanges |= (1 << i);
2021 const QMetaObject *meta = metaObject();
2022 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2023 if (groupChanges & (1 << i))
2024 QMetaObject::activate(this, meta, notifierId, 0);
2026 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
2027 if (indexChanges & (1 << i))
2028 QMetaObject::activate(this, meta, notifierId, 0);
2032 emit groupsChanged();
2035 //============================================================================
2037 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
2044 bool QQuickVisualDataGroupPrivate::isChangedConnected()
2046 Q_Q(QQuickVisualDataGroup);
2047 IS_SIGNAL_CONNECTED(q, QQuickVisualDataGroup, changed, (const QQmlV8Handle &,const QQmlV8Handle &));
2050 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
2052 Q_Q(QQuickVisualDataGroup);
2053 if (isChangedConnected() && !changeSet.isEmpty()) {
2054 v8::HandleScope handleScope;
2055 v8::Context::Scope contextScope(engine->context());
2056 v8::Local<v8::Object> removed = engineData(engine)->array(engine, changeSet.removes());
2057 v8::Local<v8::Object> inserted = engineData(engine)->array(engine, changeSet.inserts());
2058 emit q->changed(QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
2060 if (changeSet.difference() != 0)
2061 emit q->countChanged();
2064 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
2066 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2067 it->emitModelUpdated(changeSet, reset);
2071 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
2073 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2074 it->createdPackage(index, package);
2077 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
2079 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2080 it->initPackage(index, package);
2083 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
2085 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2086 it->destroyingPackage(package);
2090 \qmlclass VisualDataGroup QQuickVisualDataGroup
2091 \inqmlmodule QtQuick 2
2092 \ingroup qtquick-models
2093 \brief Encapsulates a filtered set of visual data items
2097 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
2098 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2102 QQuickVisualDataGroup::QQuickVisualDataGroup(
2103 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
2104 : QObject(*new QQuickVisualDataGroupPrivate, parent)
2106 Q_D(QQuickVisualDataGroup);
2108 d->setModel(model, Compositor::Group(index));
2111 QQuickVisualDataGroup::~QQuickVisualDataGroup()
2116 \qmlproperty string QtQuick2::VisualDataGroup::name
2118 This property holds the name of the group.
2120 Each group in a model must have a unique name starting with a lower case letter.
2123 QString QQuickVisualDataGroup::name() const
2125 Q_D(const QQuickVisualDataGroup);
2129 void QQuickVisualDataGroup::setName(const QString &name)
2131 Q_D(QQuickVisualDataGroup);
2134 if (d->name != name) {
2141 \qmlproperty int QtQuick2::VisualDataGroup::count
2143 This property holds the number of items in the group.
2146 int QQuickVisualDataGroup::count() const
2148 Q_D(const QQuickVisualDataGroup);
2151 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2155 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2157 This property holds whether new items are assigned to this group by default.
2160 bool QQuickVisualDataGroup::defaultInclude() const
2162 Q_D(const QQuickVisualDataGroup);
2163 return d->defaultInclude;
2166 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2168 Q_D(QQuickVisualDataGroup);
2169 if (d->defaultInclude != include) {
2170 d->defaultInclude = include;
2174 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2176 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2178 emit defaultIncludeChanged();
2183 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2185 Returns a javascript object describing the item at \a index in the group.
2187 The returned object contains the same information that is available to a delegate from the
2188 VisualDataModel attached as well as the model for that item. It has the properties:
2191 \li \b model The model data of the item. This is the same as the model context property in
2193 \li \b groups A list the of names of groups the item is a member of. This property can be
2194 written to change the item's membership.
2195 \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2196 Writing to this property will add or remove the item from the group.
2197 \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2198 \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName. Writing to
2199 this property will add or remove the item from the group.
2200 \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2204 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2206 Q_D(QQuickVisualDataGroup);
2208 return QQmlV8Handle::fromHandle(v8::Undefined());;
2210 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2211 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2212 qmlInfo(this) << tr("get: index out of range");
2213 return QQmlV8Handle::fromHandle(v8::Undefined());
2216 Compositor::iterator it = model->m_compositor.find(d->group, index);
2217 QQuickVisualDataModelItem *cacheItem = it->inCache()
2218 ? model->m_cache.at(it.cacheIndex)
2222 cacheItem = model->m_adaptorModel.createItem(
2223 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2225 return QQmlV8Handle::fromHandle(v8::Undefined());
2226 cacheItem->groups = it->flags;
2228 model->m_cache.insert(it.cacheIndex, cacheItem);
2229 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2232 if (model->m_cacheMetaType->constructor.IsEmpty())
2233 model->m_cacheMetaType->initializeConstructor();
2234 v8::Local<v8::Object> handle = model->m_cacheMetaType->constructor->NewInstance();
2235 handle->SetExternalResource(cacheItem);
2236 ++cacheItem->scriptRef;
2238 return QQmlV8Handle::fromHandle(handle);
2241 bool QQuickVisualDataGroupPrivate::parseIndex(
2242 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2244 if (value->IsInt32()) {
2245 *index = value->Int32Value();
2247 } else if (value->IsObject()) {
2248 v8::Local<v8::Object> object = value->ToObject();
2249 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2250 if (QQuickVisualDataModelPrivate *model = cacheItem && cacheItem->metaType->model
2251 ? QQuickVisualDataModelPrivate::get(cacheItem->metaType->model)
2253 *index = model->m_cache.indexOf(cacheItem);
2254 *group = Compositor::Cache;
2261 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2263 Q_D(QQuickVisualDataGroup);
2264 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2266 int index = model->m_compositor.count(d->group);
2267 Compositor::Group group = d->group;
2269 if (args->Length() == 0)
2273 v8::Local<v8::Value> v = (*args)[i];
2274 if (d->parseIndex(v, &index, &group)) {
2275 if (index < 0 || index > model->m_compositor.count(group)) {
2276 qmlInfo(this) << tr("insert: index out of range");
2279 if (++i == args->Length())
2284 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2285 ? model->m_compositor.findInsertPosition(group, index)
2286 : model->m_compositor.end();
2288 int groups = 1 << d->group;
2289 if (++i < args->Length())
2290 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2294 } else if (v->IsObject()) {
2295 model->insert(before, v->ToObject(), groups);
2296 model->emitChanges();
2301 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2302 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2303 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2305 Returns a reference to the instantiated item at \a index in the group.
2307 All items returned by create are added to the persistedItems group. Items in this
2308 group remain instantiated when not referenced by any view.
2311 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2313 Q_D(QQuickVisualDataGroup);
2317 if (args->Length() == 0)
2320 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2322 int index = model->m_compositor.count(d->group);
2323 Compositor::Group group = d->group;
2326 v8::Local<v8::Value> v = (*args)[i];
2327 if (d->parseIndex(v, &index, &group))
2330 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2332 if (v->IsObject()) {
2333 int groups = 1 << d->group;
2334 if (++i < args->Length())
2335 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2337 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2338 ? model->m_compositor.findInsertPosition(group, index)
2339 : model->m_compositor.end();
2341 index = before.index[d->group];
2344 if (!model->insert(before, v->ToObject(), groups)) {
2349 if (index < 0 || index >= model->m_compositor.count(group)) {
2350 qmlInfo(this) << tr("create: index out of range");
2354 QObject *object = model->object(group, index, false);
2356 QVector<Compositor::Insert> inserts;
2357 Compositor::iterator it = model->m_compositor.find(group, index);
2358 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2359 model->itemsInserted(inserts);
2360 model->m_cache.at(it.cacheIndex)->releaseObject();
2363 args->returnValue(args->engine()->newQObject(object));
2364 model->emitChanges();
2367 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2369 Q_D(QQuickVisualDataGroup);
2373 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2375 if (args->Length() < 2)
2380 Compositor::Group fromGroup = d->group;
2381 Compositor::Group toGroup = d->group;
2383 v8::Local<v8::Value> v = (*args)[0];
2384 if (d->parseIndex(v, &from, &fromGroup)) {
2385 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2386 qmlInfo(this) << tr("resolve: from index out of range");
2390 qmlInfo(this) << tr("resolve: from index invalid");
2395 if (d->parseIndex(v, &to, &toGroup)) {
2396 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2397 qmlInfo(this) << tr("resolve: to index out of range");
2401 qmlInfo(this) << tr("resolve: to index invalid");
2405 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2406 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2408 if (!fromIt->isUnresolved()) {
2409 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2413 qmlInfo(this) << tr("resolve: to is not a model item");
2417 const int unresolvedFlags = fromIt->flags;
2418 const int resolvedFlags = toIt->flags;
2419 const int resolvedIndex = toIt.modelIndex();
2420 void * const resolvedList = toIt->list;
2422 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2423 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2425 if (toIt.cacheIndex > fromIt.cacheIndex)
2426 toIt.decrementIndexes(1, unresolvedFlags);
2427 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2431 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2432 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2433 model->itemsInserted(
2434 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2435 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2436 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2438 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2439 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2441 if (resolvedFlags & Compositor::CacheFlag)
2442 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2444 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2446 if (!cacheItem->isReferenced()) {
2447 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2448 model->m_cache.removeAt(toIt.cacheIndex);
2449 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2451 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2453 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2454 if (cacheItem->attached)
2455 cacheItem->attached->emitUnresolvedChanged();
2458 model->emitChanges();
2462 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2464 Removes \a count items starting at \a index from the group.
2467 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2469 Q_D(QQuickVisualDataGroup);
2472 Compositor::Group group = d->group;
2476 if (args->Length() == 0)
2480 v8::Local<v8::Value> v = (*args)[i];
2481 if (!d->parseIndex(v, &index, &group)) {
2482 qmlInfo(this) << tr("remove: invalid index");
2486 if (++i < args->Length()) {
2489 count = v->Int32Value();
2492 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2493 if (index < 0 || index >= model->m_compositor.count(group)) {
2494 qmlInfo(this) << tr("remove: index out of range");
2495 } else if (count != 0) {
2496 Compositor::iterator it = model->m_compositor.find(group, index);
2497 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2498 qmlInfo(this) << tr("remove: invalid count");
2500 model->removeGroups(it, count, d->group, 1 << d->group);
2505 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2506 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2508 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2511 if (args->Length() < 2)
2515 v8::Local<v8::Value> v = (*args)[i];
2516 if (!parseIndex(v, index, group))
2521 *count = v->Int32Value();
2523 if (++i == args->Length())
2528 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2534 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2536 Adds \a count items starting at \a index to \a groups.
2539 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2541 Q_D(QQuickVisualDataGroup);
2542 Compositor::Group group = d->group;
2547 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2550 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2551 if (index < 0 || index >= model->m_compositor.count(group)) {
2552 qmlInfo(this) << tr("addGroups: index out of range");
2553 } else if (count != 0) {
2554 Compositor::iterator it = model->m_compositor.find(group, index);
2555 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2556 qmlInfo(this) << tr("addGroups: invalid count");
2558 model->addGroups(it, count, d->group, groups);
2564 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2566 Removes \a count items starting at \a index from \a groups.
2569 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2571 Q_D(QQuickVisualDataGroup);
2572 Compositor::Group group = d->group;
2577 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2580 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2581 if (index < 0 || index >= model->m_compositor.count(group)) {
2582 qmlInfo(this) << tr("removeGroups: index out of range");
2583 } else if (count != 0) {
2584 Compositor::iterator it = model->m_compositor.find(group, index);
2585 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2586 qmlInfo(this) << tr("removeGroups: invalid count");
2588 model->removeGroups(it, count, d->group, groups);
2594 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2596 Sets the \a groups \a count items starting at \a index belong to.
2599 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2601 Q_D(QQuickVisualDataGroup);
2602 Compositor::Group group = d->group;
2607 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2610 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2611 if (index < 0 || index >= model->m_compositor.count(group)) {
2612 qmlInfo(this) << tr("setGroups: index out of range");
2613 } else if (count != 0) {
2614 Compositor::iterator it = model->m_compositor.find(group, index);
2615 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2616 qmlInfo(this) << tr("setGroups: invalid count");
2618 model->setGroups(it, count, d->group, groups);
2624 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2626 Sets the \a groups \a count items starting at \a index belong to.
2630 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2632 Moves \a count at \a from in a group \a to a new position.
2635 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2637 Q_D(QQuickVisualDataGroup);
2639 if (args->Length() < 2)
2642 Compositor::Group fromGroup = d->group;
2643 Compositor::Group toGroup = d->group;
2648 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2649 qmlInfo(this) << tr("move: invalid from index");
2653 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2654 qmlInfo(this) << tr("move: invalid to index");
2658 if (args->Length() > 2) {
2659 v8::Local<v8::Value> v = (*args)[2];
2661 count = v->Int32Value();
2664 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2667 qmlInfo(this) << tr("move: invalid count");
2668 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2669 qmlInfo(this) << tr("move: from index out of range");
2670 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2671 qmlInfo(this) << tr("move: to index out of range");
2672 } else if (count > 0) {
2673 QVector<Compositor::Remove> removes;
2674 QVector<Compositor::Insert> inserts;
2676 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2677 model->itemsMoved(removes, inserts);
2678 model->emitChanges();
2684 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2686 This handler is called when items have been removed from or inserted into the group.
2688 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2689 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2691 Each index is adjusted for previous changes with all removed items preceding any inserted
2695 //============================================================================
2697 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2698 : QQuickVisualModel(*new QObjectPrivate, parent)
2701 , m_compositorGroup(Compositor::Cache)
2702 , m_inheritGroup(true)
2704 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2705 if (d->m_cacheMetaType) {
2706 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2707 m_compositorGroup = Compositor::Default;
2709 d->m_pendingParts.insert(this);
2713 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2717 QString QQuickVisualPartsModel::filterGroup() const
2720 return m_model->filterGroup();
2721 return m_filterGroup;
2724 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2726 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2727 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2731 if (m_filterGroup != group || m_inheritGroup) {
2732 m_filterGroup = group;
2733 m_inheritGroup = false;
2734 updateFilterGroup();
2736 emit filterGroupChanged();
2740 void QQuickVisualPartsModel::resetFilterGroup()
2742 if (!m_inheritGroup) {
2743 m_inheritGroup = true;
2744 updateFilterGroup();
2745 emit filterGroupChanged();
2749 void QQuickVisualPartsModel::updateFilterGroup()
2751 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2752 if (!model->m_cacheMetaType)
2755 if (m_inheritGroup) {
2756 if (m_filterGroup == model->m_filterGroup)
2758 m_filterGroup = model->m_filterGroup;
2761 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2762 m_compositorGroup = Compositor::Default;
2763 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2764 for (int i = 1; i < model->m_groupCount; ++i) {
2765 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2766 m_compositorGroup = Compositor::Group(i);
2771 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2772 if (m_compositorGroup != previousGroup) {
2773 QVector<QQuickChangeSet::Remove> removes;
2774 QVector<QQuickChangeSet::Insert> inserts;
2775 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2777 QQuickChangeSet changeSet;
2778 changeSet.apply(removes, inserts);
2779 if (!changeSet.isEmpty())
2780 emit modelUpdated(changeSet, false);
2782 if (changeSet.difference() != 0)
2783 emit countChanged();
2787 void QQuickVisualPartsModel::updateFilterGroup(
2788 Compositor::Group group, const QQuickChangeSet &changeSet)
2790 if (!m_inheritGroup)
2793 m_compositorGroup = group;
2794 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2796 if (!changeSet.isEmpty())
2797 emit modelUpdated(changeSet, false);
2799 if (changeSet.difference() != 0)
2800 emit countChanged();
2802 emit filterGroupChanged();
2805 int QQuickVisualPartsModel::count() const
2807 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2808 return model->m_delegate
2809 ? model->m_compositor.count(m_compositorGroup)
2813 bool QQuickVisualPartsModel::isValid() const
2815 return m_model->isValid();
2818 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2820 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2822 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2823 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2827 QObject *object = model->object(m_compositorGroup, index, asynchronous);
2829 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
2830 QObject *part = package->part(m_part);
2833 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(part)) {
2834 m_packaged.insertMulti(item, package);
2839 model->release(object);
2840 if (!model->m_delegateValidated) {
2842 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2843 model->m_delegateValidated = true;
2849 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2851 QQuickVisualModel::ReleaseFlags flags = 0;
2853 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2854 if (it != m_packaged.end()) {
2855 QQuickPackage *package = *it;
2856 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2857 flags = model->release(package);
2858 m_packaged.erase(it);
2859 if (!m_packaged.contains(item))
2860 flags &= ~Referenced;
2861 if (flags & Destroyed)
2862 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2867 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2869 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2872 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2874 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2875 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2876 m_watchedRoles = roles;
2879 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2881 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2882 if (it != m_packaged.end()) {
2883 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2884 return cacheItem->groupIndex(m_compositorGroup);
2889 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2891 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2892 emit createdItem(index, item);
2895 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2897 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part)))
2898 emit initItem(index, item);
2901 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2903 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(package->part(m_part))) {
2904 Q_ASSERT(!m_packaged.contains(item));
2905 emit destroyingItem(item);
2906 item->setParentItem(0);
2910 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2912 emit modelUpdated(changeSet, reset);
2913 if (changeSet.difference() != 0)
2914 emit countChanged();
2917 //============================================================================
2919 v8::Handle<v8::Value> get_change_index(v8::Local<v8::String>, const v8::AccessorInfo &info)
2921 return info.This()->GetInternalField(0);
2924 v8::Handle<v8::Value> get_change_count(v8::Local<v8::String>, const v8::AccessorInfo &info)
2926 return info.This()->GetInternalField(1);
2929 v8::Handle<v8::Value> get_change_moveId(v8::Local<v8::String>, const v8::AccessorInfo &info)
2931 return info.This()->GetInternalField(2);
2934 class QQuickVisualDataGroupChangeArray : public QV8ObjectResource
2936 V8_RESOURCE_TYPE(ChangeSetArrayType)
2938 QQuickVisualDataGroupChangeArray(QV8Engine *engine)
2939 : QV8ObjectResource(engine)
2943 virtual quint32 count() const = 0;
2944 virtual const QQuickChangeSet::Change &at(int index) const = 0;
2946 static v8::Handle<v8::Value> get_change(quint32 index, const v8::AccessorInfo &info)
2948 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2949 V8ASSERT_TYPE(array, "Not a valid change array");
2951 if (index >= array->count())
2952 return v8::Undefined();
2954 const QQuickChangeSet::Change &change = array->at(index);
2956 v8::Local<v8::Object> object = engineData(array->engine)->constructorChange->NewInstance();
2957 object->SetInternalField(0, v8::Int32::New(change.index));
2958 object->SetInternalField(1, v8::Int32::New(change.count));
2959 if (change.isMove())
2960 object->SetInternalField(2, v8::Int32::New(change.moveId));
2965 static v8::Handle<v8::Value> get_length(v8::Local<v8::String>, const v8::AccessorInfo &info)
2967 QQuickVisualDataGroupChangeArray *array = v8_resource_cast<QQuickVisualDataGroupChangeArray>(info.This());
2968 V8ASSERT_TYPE(array, "Not a valid change array");
2970 return v8::Integer::New(array->count());
2973 static v8::Local<v8::Function> constructor()
2975 v8::Local<v8::FunctionTemplate> changeArray = v8::FunctionTemplate::New();
2976 changeArray->InstanceTemplate()->SetHasExternalResource(true);
2977 changeArray->InstanceTemplate()->SetIndexedPropertyHandler(get_change);
2978 changeArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), get_length);
2979 return changeArray->GetFunction();
2983 class QQuickVisualDataGroupRemoveArray : public QQuickVisualDataGroupChangeArray
2986 QQuickVisualDataGroupRemoveArray(QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
2987 : QQuickVisualDataGroupChangeArray(engine)
2992 quint32 count() const { return changes.count(); }
2993 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
2996 QVector<QQuickChangeSet::Remove> changes;
2999 class QQuickVisualDataGroupInsertArray : public QQuickVisualDataGroupChangeArray
3002 QQuickVisualDataGroupInsertArray(QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3003 : QQuickVisualDataGroupChangeArray(engine)
3008 quint32 count() const { return changes.count(); }
3009 const QQuickChangeSet::Change &at(int index) const { return changes.at(index); }
3012 QVector<QQuickChangeSet::Insert> changes;
3015 QQuickVisualDataModelEngineData::QQuickVisualDataModelEngineData(QV8Engine *)
3017 strings = qPersistentNew(v8::Array::New(StringCount));
3018 strings->Set(Model, v8::String::New("model"));
3019 strings->Set(Groups, v8::String::New("groups"));
3020 strings->Set(IsUnresolved, v8::String::New("isUnresolved"));
3021 strings->Set(ItemsIndex, v8::String::New("itemsIndex"));
3022 strings->Set(PersistedItemsIndex, v8::String::New("persistedItemsIndex"));
3023 strings->Set(InItems, v8::String::New("inItems"));
3024 strings->Set(InPersistedItems, v8::String::New("inPersistedItems"));
3026 v8::Local<v8::FunctionTemplate> change = v8::FunctionTemplate::New();
3027 change->InstanceTemplate()->SetAccessor(v8::String::New("index"), get_change_index);
3028 change->InstanceTemplate()->SetAccessor(v8::String::New("count"), get_change_count);
3029 change->InstanceTemplate()->SetAccessor(v8::String::New("moveId"), get_change_moveId);
3030 change->InstanceTemplate()->SetInternalFieldCount(3);
3031 constructorChange = qPersistentNew(change->GetFunction());
3032 constructorChangeArray = qPersistentNew(QQuickVisualDataGroupChangeArray::constructor());
3035 QQuickVisualDataModelEngineData::~QQuickVisualDataModelEngineData()
3037 qPersistentDispose(strings);
3038 qPersistentDispose(constructorChange);
3039 qPersistentDispose(constructorChangeArray);
3042 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3043 QV8Engine *engine, const QVector<QQuickChangeSet::Remove> &changes)
3045 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3046 array->SetExternalResource(new QQuickVisualDataGroupRemoveArray(engine, changes));
3050 v8::Local<v8::Object> QQuickVisualDataModelEngineData::array(
3051 QV8Engine *engine, const QVector<QQuickChangeSet::Insert> &changes)
3053 v8::Local<v8::Object> array = constructorChangeArray->NewInstance();
3054 array->SetExternalResource(new QQuickVisualDataGroupInsertArray(engine, changes));