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>
55 void QQuickVisualDataModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
57 prop.setWritable(false);
60 QVariant QQuickVisualDataModelPartsMetaObject::initialValue(int id)
62 QQuickVisualDataModelParts *parts = static_cast<QQuickVisualDataModelParts *>(object());
63 QQuickVisualPartsModel *m = new QQuickVisualPartsModel(
64 parts->model, QString::fromUtf8(name(id)), parts);
65 parts->models.append(m);
66 return QVariant::fromValue(static_cast<QObject *>(m));
69 QQuickVisualDataModelParts::QQuickVisualDataModelParts(QQuickVisualDataModel *parent)
70 : QObject(parent), model(parent)
72 new QQuickVisualDataModelPartsMetaObject(this);
75 //---------------------------------------------------------------------------
78 \qmlclass VisualDataModel QQuickVisualDataModel
79 \inqmlmodule QtQuick 2
80 \ingroup qml-working-with-data
81 \brief The VisualDataModel encapsulates a model and delegate
83 A VisualDataModel encapsulates a model and the delegate that will
84 be instantiated for items in the model.
86 It is usually not necessary to create VisualDataModel elements.
87 However, it can be useful for manipulating and accessing the \l modelIndex
88 when a QAbstractItemModel subclass is used as the
89 model. Also, VisualDataModel is used together with \l Package to
90 provide delegates to multiple views.
92 The example below illustrates using a VisualDataModel with a ListView.
94 \snippet doc/snippets/qml/visualdatamodel.qml 0
97 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QQmlContext *ctxt)
102 , m_filterGroup(QStringLiteral("items"))
104 , m_groupCount(Compositor::MinimumGroupCount)
105 , m_compositorGroup(Compositor::Cache)
107 , m_delegateValidated(false)
109 , m_transaction(false)
110 , m_incubatorCleanupScheduled(false)
113 , m_persistedItems(0)
117 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
119 qDeleteAll(m_finishedIncubating);
122 void QQuickVisualDataModelPrivate::init()
124 Q_Q(QQuickVisualDataModel);
125 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
127 m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
128 m_items->setDefaultInclude(true);
129 m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
130 QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
133 QQuickVisualDataModel::QQuickVisualDataModel()
134 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
136 Q_D(QQuickVisualDataModel);
140 QQuickVisualDataModel::QQuickVisualDataModel(QQmlContext *ctxt, QObject *parent)
141 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
143 Q_D(QQuickVisualDataModel);
147 QQuickVisualDataModel::~QQuickVisualDataModel()
149 Q_D(QQuickVisualDataModel);
151 foreach (QQuickVisualDataModelItem *cacheItem, d->m_cache) {
152 if (QObject *object = cacheItem->object()) {
153 // Clear the guard before deleting the object so it doesn't decrement scriptRef and
154 // potentially delete the cacheItem itself.
155 cacheItem->setObject(0);
156 cacheItem->scriptRef -= 1;
160 cacheItem->objectRef = 0;
161 if (!cacheItem->isReferenced())
165 if (d->m_cacheMetaType)
166 d->m_cacheMetaType->release();
170 void QQuickVisualDataModel::classBegin()
172 Q_D(QQuickVisualDataModel);
174 d->m_context = qmlContext(this);
177 void QQuickVisualDataModel::componentComplete()
179 Q_D(QQuickVisualDataModel);
180 d->m_complete = true;
182 int defaultGroups = 0;
183 QStringList groupNames;
184 groupNames.append(QStringLiteral("items"));
185 groupNames.append(QStringLiteral("persistedItems"));
186 if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
187 defaultGroups |= Compositor::DefaultFlag;
188 if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
189 defaultGroups |= Compositor::PersistedFlag;
190 for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
191 QString name = d->m_groups[i]->name();
192 if (name.isEmpty()) {
193 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
196 } else if (name.at(0).isUpper()) {
197 qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
198 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
202 groupNames.append(name);
204 QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
205 group->setModel(this, Compositor::Group(i));
206 if (group->defaultInclude)
207 defaultGroups |= (1 << i);
211 d->m_cacheMetaType = new QQuickVisualDataModelItemMetaType(
212 QQmlEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
214 d->m_compositor.setGroupCount(d->m_groupCount);
215 d->m_compositor.setDefaultGroups(defaultGroups);
216 d->updateFilterGroup();
218 while (!d->m_pendingParts.isEmpty())
219 static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
221 QVector<Compositor::Insert> inserts;
222 d->m_count = d->m_adaptorModel.count();
223 d->m_compositor.append(
227 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
229 d->itemsInserted(inserts);
232 if (d->m_adaptorModel.canFetchMore())
233 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
237 \qmlproperty model QtQuick2::VisualDataModel::model
238 This property holds the model providing data for the VisualDataModel.
240 The model provides a set of data that is used to create the items
241 for a view. For large or dynamic datasets the model is usually
242 provided by a C++ model object. The C++ model object must be a \l
243 {QAbstractItemModel} subclass or a simple list.
245 Models can also be created directly in QML, using a \l{ListModel} or
248 \sa {qmlmodels}{Data Models}
250 QVariant QQuickVisualDataModel::model() const
252 Q_D(const QQuickVisualDataModel);
253 return d->m_adaptorModel.model();
256 void QQuickVisualDataModel::setModel(const QVariant &model)
258 Q_D(QQuickVisualDataModel);
261 _q_itemsRemoved(0, d->m_count);
263 d->m_adaptorModel.setModel(model, this, d->m_context->engine());
264 d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
265 for (int i = 0; d->m_parts && i < d->m_parts->models.count(); ++i) {
266 d->m_adaptorModel.replaceWatchedRoles(
267 QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
271 _q_itemsInserted(0, d->m_adaptorModel.count());
272 if (d->m_adaptorModel.canFetchMore())
273 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
278 \qmlproperty Component QtQuick2::VisualDataModel::delegate
280 The delegate provides a template defining each item instantiated by a view.
281 The index is exposed as an accessible \c index property. Properties of the
282 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
284 QQmlComponent *QQuickVisualDataModel::delegate() const
286 Q_D(const QQuickVisualDataModel);
287 return d->m_delegate;
290 void QQuickVisualDataModel::setDelegate(QQmlComponent *delegate)
292 Q_D(QQuickVisualDataModel);
293 if (d->m_transaction) {
294 qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
297 bool wasValid = d->m_delegate != 0;
298 d->m_delegate = delegate;
299 d->m_delegateValidated = false;
300 if (wasValid && d->m_complete) {
301 for (int i = 1; i < d->m_groupCount; ++i) {
302 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
303 0, d->m_compositor.count(Compositor::Group(i)));
306 if (d->m_complete && d->m_delegate) {
307 for (int i = 1; i < d->m_groupCount; ++i) {
308 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
309 0, d->m_compositor.count(Compositor::Group(i)));
316 \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
318 QAbstractItemModel provides a hierarchical tree of data, whereas
319 QML only operates on list data. \c rootIndex allows the children of
320 any node in a QAbstractItemModel to be provided by this model.
322 This property only affects models of type QAbstractItemModel that
323 are hierarchical (e.g, a tree model).
325 For example, here is a simple interactive file system browser.
326 When a directory name is clicked, the view's \c rootIndex is set to the
327 QModelIndex node of the clicked directory, thus updating the view to show
328 the new directory's contents.
331 \snippet doc/snippets/qml/visualdatamodel_rootindex/main.cpp 0
334 \snippet doc/snippets/qml/visualdatamodel_rootindex/view.qml 0
336 If the \l model is a QAbstractItemModel subclass, the delegate can also
337 reference a \c hasModelChildren property (optionally qualified by a
338 \e model. prefix) that indicates whether the delegate's model item has
342 \sa modelIndex(), parentModelIndex()
344 QVariant QQuickVisualDataModel::rootIndex() const
346 Q_D(const QQuickVisualDataModel);
347 return QVariant::fromValue(d->m_adaptorModel.rootIndex);
350 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
352 Q_D(QQuickVisualDataModel);
354 QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
355 if (d->m_adaptorModel.rootIndex != modelIndex) {
356 const int oldCount = d->m_count;
357 d->m_adaptorModel.rootIndex = modelIndex;
358 if (d->m_adaptorModel.canFetchMore())
359 d->m_adaptorModel.fetchMore();
361 const int newCount = d->m_adaptorModel.count();
363 _q_itemsRemoved(0, oldCount);
365 _q_itemsInserted(0, newCount);
367 emit rootIndexChanged();
372 \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
374 QAbstractItemModel provides a hierarchical tree of data, whereas
375 QML only operates on list data. This function assists in using
378 Returns a QModelIndex for the specified index.
379 This value can be assigned to rootIndex.
383 QVariant QQuickVisualDataModel::modelIndex(int idx) const
385 Q_D(const QQuickVisualDataModel);
386 return d->m_adaptorModel.modelIndex(idx);
390 \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
392 QAbstractItemModel provides a hierarchical tree of data, whereas
393 QML only operates on list data. This function assists in using
396 Returns a QModelIndex for the parent of the current rootIndex.
397 This value can be assigned to rootIndex.
401 QVariant QQuickVisualDataModel::parentModelIndex() const
403 Q_D(const QQuickVisualDataModel);
404 return d->m_adaptorModel.parentModelIndex();
408 \qmlproperty int QtQuick2::VisualDataModel::count
411 int QQuickVisualDataModel::count() const
413 Q_D(const QQuickVisualDataModel);
416 return d->m_compositor.count(d->m_compositorGroup);
419 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
421 QQuickVisualDataModel::ReleaseFlags stat = 0;
425 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(object)) {
426 if (cacheItem->releaseObject()) {
427 cacheItem->destroyObject();
428 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
429 emitDestroyingItem(item);
430 if (cacheItem->incubationTask) {
431 releaseIncubator(cacheItem->incubationTask);
432 cacheItem->incubationTask = 0;
434 cacheItem->Dispose();
435 stat |= QQuickVisualModel::Destroyed;
437 stat |= QQuickVisualDataModel::Referenced;
444 Returns ReleaseStatus flags.
447 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
449 Q_D(QQuickVisualDataModel);
450 QQuickVisualModel::ReleaseFlags stat = d->release(item);
451 if (stat & Destroyed)
452 item->setParentItem(0);
456 // Cancel a requested async item
457 void QQuickVisualDataModel::cancel(int index)
459 Q_D(QQuickVisualDataModel);
460 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
461 qWarning() << "VisualDataModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
465 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
466 QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
468 if (cacheItem->incubationTask) {
469 delete cacheItem->incubationTask->incubatingContext;
470 cacheItem->incubationTask->incubatingContext = 0;
471 d->releaseIncubator(cacheItem->incubationTask);
472 cacheItem->incubationTask = 0;
474 if (cacheItem->object() && !cacheItem->isObjectReferenced()) {
475 QObject *object = cacheItem->object();
476 cacheItem->destroyObject();
477 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(object))
478 d->emitDestroyingPackage(package);
479 else if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
480 d->emitDestroyingItem(item);
481 cacheItem->scriptRef -= 1;
483 if (!cacheItem->isReferenced()) {
484 d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
485 d->m_cache.removeAt(it.cacheIndex);
487 Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
492 void QQuickVisualDataModelPrivate::group_append(
493 QQmlListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
495 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
498 if (d->m_groupCount == Compositor::MaximumGroupCount) {
499 qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
502 d->m_groups[d->m_groupCount] = group;
503 d->m_groupCount += 1;
506 int QQuickVisualDataModelPrivate::group_count(
507 QQmlListProperty<QQuickVisualDataGroup> *property)
509 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
510 return d->m_groupCount - 1;
513 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
514 QQmlListProperty<QQuickVisualDataGroup> *property, int index)
516 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
517 return index >= 0 && index < d->m_groupCount - 1
518 ? d->m_groups[index + 1]
523 \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
525 This property holds a visual data model's group definitions.
527 Groups define a sub-set of the items in a visual data model and can be used to filter
530 For every group defined in a VisualDataModel two attached properties are added to each
531 delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
532 item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
533 index of the item in that group.
535 The following example illustrates using groups to select items in a model.
537 \snippet doc/snippets/qml/visualdatagroup.qml 0
540 QQmlListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
542 Q_D(QQuickVisualDataModel);
543 return QQmlListProperty<QQuickVisualDataGroup>(
546 QQuickVisualDataModelPrivate::group_append,
547 QQuickVisualDataModelPrivate::group_count,
548 QQuickVisualDataModelPrivate::group_at);
552 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
554 This property holds visual data model's default group to which all new items are added.
557 QQuickVisualDataGroup *QQuickVisualDataModel::items()
559 Q_D(QQuickVisualDataModel);
564 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
566 This property holds visual data model's persisted items group.
568 Items in this group are not destroyed when released by a view, instead they are persisted
569 until removed from the group.
571 An item can be removed from the persistedItems group by setting the
572 VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
573 at that time it will be destroyed. Adding an item to this group will not create a new
576 Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
580 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
582 Q_D(QQuickVisualDataModel);
583 return d->m_persistedItems;
587 \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
589 This property holds the name of the group used to filter the visual data model.
591 Only items which belong to this group are visible to a view.
593 By default this is the \l items group.
596 QString QQuickVisualDataModel::filterGroup() const
598 Q_D(const QQuickVisualDataModel);
599 return d->m_filterGroup;
602 void QQuickVisualDataModel::setFilterGroup(const QString &group)
604 Q_D(QQuickVisualDataModel);
606 if (d->m_transaction) {
607 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
611 if (d->m_filterGroup != group) {
612 d->m_filterGroup = group;
613 d->updateFilterGroup();
614 emit filterGroupChanged();
618 void QQuickVisualDataModel::resetFilterGroup()
620 setFilterGroup(QStringLiteral("items"));
623 void QQuickVisualDataModelPrivate::updateFilterGroup()
625 Q_Q(QQuickVisualDataModel);
626 if (!m_cacheMetaType)
629 QQuickListCompositor::Group previousGroup = m_compositorGroup;
630 m_compositorGroup = Compositor::Default;
631 for (int i = 1; i < m_groupCount; ++i) {
632 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
633 m_compositorGroup = Compositor::Group(i);
638 QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
639 if (m_compositorGroup != previousGroup) {
640 QVector<QQuickChangeSet::Remove> removes;
641 QVector<QQuickChangeSet::Insert> inserts;
642 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
644 QQuickChangeSet changeSet;
645 changeSet.apply(removes, inserts);
646 emit q->modelUpdated(changeSet, false);
648 if (changeSet.difference() != 0)
649 emit q->countChanged();
652 foreach (QQuickVisualPartsModel *model, m_parts->models)
653 model->updateFilterGroup(m_compositorGroup, changeSet);
659 \qmlproperty object QtQuick2::VisualDataModel::parts
661 The \a parts property selects a VisualDataModel which creates
662 delegates from the part named. This is used in conjunction with
663 the \l Package element.
665 For example, the code below selects a model which creates
666 delegates named \e list from a \l Package:
672 Item { Package.name: "list" }
678 width: 200; height:200
679 model: visualModel.parts.list
686 QObject *QQuickVisualDataModel::parts()
688 Q_D(QQuickVisualDataModel);
690 d->m_parts = new QQuickVisualDataModelParts(this);
694 void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
696 for (int i = 1; i < m_groupCount; ++i)
697 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
700 void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
702 for (int i = 1; i < m_groupCount; ++i)
703 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
706 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
708 for (int i = 1; i < m_groupCount; ++i)
709 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
712 void QVDMIncubationTask::statusChanged(Status status)
714 vdm->incubatorStatusChanged(this, status);
717 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
719 Q_Q(QQuickVisualDataModel);
720 if (!incubationTask->isError())
721 incubationTask->clear();
722 m_finishedIncubating.append(incubationTask);
723 if (!m_incubatorCleanupScheduled) {
724 m_incubatorCleanupScheduled = true;
725 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
729 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
731 Q_Q(QQuickVisualDataModel);
732 if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
735 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
736 cacheItem->incubationTask = 0;
738 if (status == QQmlIncubator::Ready) {
739 incubationTask->incubating = 0;
740 releaseIncubator(incubationTask);
741 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object()))
742 emitCreatedPackage(cacheItem, package);
743 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object()))
744 emitCreatedItem(cacheItem, item);
745 } else if (status == QQmlIncubator::Error) {
746 delete incubationTask->incubatingContext;
747 incubationTask->incubatingContext = 0;
748 cacheItem->scriptRef -= 1;
749 if (!cacheItem->isReferenced()) {
750 int cidx = m_cache.indexOf(cacheItem);
752 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
753 m_cache.removeAt(cidx);
756 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
758 releaseIncubator(incubationTask);
759 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
763 void QVDMIncubationTask::setInitialState(QObject *o)
765 vdm->setInitialState(this, o);
768 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
770 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
771 cacheItem->setObject(o);
772 QQml_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object());
773 incubationTask->incubatingContext = 0;
776 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object()))
777 emitInitPackage(cacheItem, package);
778 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object()))
779 emitInitItem(cacheItem, item);
782 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
784 Q_Q(QQuickVisualDataModel);
785 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
786 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
790 Compositor::iterator it = m_compositor.find(group, index);
792 QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
795 cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), it.modelIndex());
799 for (int i = 1; i < m_groupCount; ++i)
800 cacheItem->index[i] = it.index[i];
802 cacheItem->groups = it->flags;
804 m_cache.insert(it.cacheIndex, cacheItem);
805 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
806 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
809 if (cacheItem->incubationTask) {
810 if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
811 // previously requested async - now needed immediately
812 cacheItem->incubationTask->forceCompletion();
814 } else if (!cacheItem->object()) {
815 cacheItem->scriptRef += 1;
817 QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
818 cacheItem->incubationTask = incubator;
820 QQmlContext *creationContext = m_delegate->creationContext();
821 QQmlContext *rootContext = new QQmlContext(creationContext ? creationContext : m_context);
822 QQmlContext *ctxt = rootContext;
823 ctxt->setContextObject(cacheItem);
824 if (m_adaptorModel.hasProxyObject()) {
825 if (QQuickVisualAdaptorModelProxyInterface *proxy = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
826 ctxt = new QQmlContext(ctxt, ctxt);
827 ctxt->setContextObject(proxy->proxiedObject());
831 incubator->incubating = cacheItem;
832 incubator->incubatingContext = rootContext;
833 m_delegate->create(*incubator, ctxt, m_context);
836 if (index == m_compositor.count(group) - 1 && m_adaptorModel.canFetchMore())
837 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
838 if (cacheItem->object() && reference)
839 cacheItem->referenceObject();
840 return cacheItem->object();
844 If asynchronous is true or the component is being loaded asynchronously due
845 to an ancestor being loaded asynchronously, item() may return 0. In this
846 case itemCreated() will be emitted when the item is available. The item
847 at this stage does not have any references, so item() must be called again
848 to ensure a reference is held. Any call to item() which returns a valid item
849 must be matched by a call to release() in order to destroy the item.
851 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
853 Q_D(QQuickVisualDataModel);
854 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
855 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
859 QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
863 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
867 if (!d->m_delegateValidated) {
869 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
870 d->m_delegateValidated = true;
875 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
877 Compositor::iterator it = m_compositor.find(group, index);
878 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
879 return model->stringValue(it.modelIndex(), name);
884 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
886 Q_D(QQuickVisualDataModel);
887 return d->stringValue(d->m_compositorGroup, index, name);
890 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
892 Q_D(const QQuickVisualDataModel);
893 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(item))
894 return cacheItem->index[d->m_compositorGroup];
898 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
900 Q_D(QQuickVisualDataModel);
901 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
902 d->m_watchedRoles = roles;
905 void QQuickVisualDataModelPrivate::addGroups(
906 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
908 QVector<Compositor::Insert> inserts;
909 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
910 itemsInserted(inserts);
914 void QQuickVisualDataModelPrivate::removeGroups(
915 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
917 QVector<Compositor::Remove> removes;
918 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
919 itemsRemoved(removes);
923 void QQuickVisualDataModelPrivate::setGroups(
924 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
926 QVector<Compositor::Remove> removes;
927 QVector<Compositor::Insert> inserts;
929 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
930 itemsInserted(inserts);
931 const int removeFlags = ~groupFlags & Compositor::GroupMask;
933 from = m_compositor.find(from.group, from.index[from.group]);
934 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
935 itemsRemoved(removes);
939 bool QQuickVisualDataModel::event(QEvent *e)
941 Q_D(QQuickVisualDataModel);
942 if (e->type() == QEvent::UpdateRequest) {
943 d->m_adaptorModel.fetchMore();
944 } else if (e->type() == QEvent::User) {
945 d->m_incubatorCleanupScheduled = false;
946 qDeleteAll(d->m_finishedIncubating);
947 d->m_finishedIncubating.clear();
949 return QQuickVisualModel::event(e);
952 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
957 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
959 foreach (const Compositor::Change &change, changes) {
960 for (int i = 1; i < m_groupCount; ++i) {
961 if (change.inGroup(i)) {
962 translatedChanges[i].append(QQuickChangeSet::Change(change.index[i], change.count));
967 for (int i = 1; i < m_groupCount; ++i)
968 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
971 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QList<int> &roles)
973 Q_D(QQuickVisualDataModel);
974 if (count <= 0 || !d->m_complete)
977 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
978 QVector<Compositor::Change> changes;
979 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
980 d->itemsChanged(changes);
985 void QQuickVisualDataModelPrivate::itemsInserted(
986 const QVector<Compositor::Insert> &inserts,
987 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
988 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
992 int inserted[Compositor::MaximumGroupCount];
993 for (int i = 1; i < m_groupCount; ++i)
996 foreach (const Compositor::Insert &insert, inserts) {
997 for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
998 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
999 for (int i = 1; i < m_groupCount; ++i)
1000 cacheItem->index[i] += inserted[i];
1002 for (int i = 1; i < m_groupCount; ++i) {
1003 if (insert.inGroup(i)) {
1004 (*translatedInserts)[i].append(
1005 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1006 inserted[i] += insert.count;
1010 if (!insert.inCache())
1013 if (movedItems && insert.isMove()) {
1014 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1015 Q_ASSERT(items.count() == insert.count);
1016 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1018 if (insert.inGroup()) {
1019 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1020 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1021 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1022 for (int i = 1; i < m_groupCount; ++i) {
1023 cacheItem->index[i] = cacheItem->groups & (1 << i)
1024 ? insert.index[i] + offset
1029 cacheIndex = insert.cacheIndex + insert.count;
1032 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1033 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1034 for (int i = 1; i < m_groupCount; ++i)
1035 cacheItem->index[i] += inserted[i];
1039 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1041 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1042 itemsInserted(inserts, &translatedInserts);
1043 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1047 for (int i = 1; i < m_groupCount; ++i)
1048 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1051 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1054 Q_D(QQuickVisualDataModel);
1055 if (count <= 0 || !d->m_complete)
1058 d->m_count += count;
1060 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1061 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1062 if (item->modelIndex() >= index)
1063 item->setModelIndex(item->modelIndex() + count);
1066 QVector<Compositor::Insert> inserts;
1067 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1068 d->itemsInserted(inserts);
1072 void QQuickVisualDataModelPrivate::itemsRemoved(
1073 const QVector<Compositor::Remove> &removes,
1074 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1075 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1078 int removedCache = 0;
1080 int removed[Compositor::MaximumGroupCount];
1081 for (int i = 1; i < m_groupCount; ++i)
1084 foreach (const Compositor::Remove &remove, removes) {
1085 for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
1086 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1087 for (int i = 1; i < m_groupCount; ++i)
1088 cacheItem->index[i] -= removed[i];
1090 for (int i = 1; i < m_groupCount; ++i) {
1091 if (remove.inGroup(i)) {
1092 (*translatedRemoves)[i].append(
1093 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1094 removed[i] += remove.count;
1098 if (!remove.inCache())
1101 if (movedItems && remove.isMove()) {
1102 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1103 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1104 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1105 m_cache.erase(begin, end);
1107 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1108 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1109 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object()) {
1110 QObject *object = cacheItem->object();
1111 cacheItem->destroyObject();
1112 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(object))
1113 emitDestroyingPackage(package);
1114 else if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
1115 emitDestroyingItem(item);
1116 cacheItem->setObject(0);
1117 cacheItem->scriptRef -= 1;
1119 if (!cacheItem->isReferenced()) {
1120 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1121 m_cache.removeAt(cacheIndex);
1125 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1126 } else if (remove.groups() == cacheItem->groups) {
1127 cacheItem->groups = 0;
1128 for (int i = 1; i < m_groupCount; ++i)
1129 cacheItem->index[i] = -1;
1131 for (int i = 1; i < m_groupCount; ++i) {
1132 if (remove.inGroup(i))
1133 cacheItem->index[i] = remove.index[i];
1135 cacheItem->groups &= ~remove.flags;
1141 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1142 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1143 for (int i = 1; i < m_groupCount; ++i)
1144 cacheItem->index[i] -= removed[i];
1148 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1150 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1151 itemsRemoved(removes, &translatedRemoves);
1152 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1156 for (int i = 1; i < m_groupCount; ++i)
1157 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1160 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1162 Q_D(QQuickVisualDataModel);
1163 if (count <= 0|| !d->m_complete)
1166 d->m_count -= count;
1168 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1169 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1170 if (item->modelIndex() >= index + count)
1171 item->setModelIndex(item->modelIndex() - count);
1172 else if (item->modelIndex() >= index)
1173 item->setModelIndex(-1);
1176 QVector<Compositor::Remove> removes;
1177 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1178 d->itemsRemoved(removes);
1183 void QQuickVisualDataModelPrivate::itemsMoved(
1184 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1186 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1188 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1189 itemsRemoved(removes, &translatedRemoves, &movedItems);
1191 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1192 itemsInserted(inserts, &translatedInserts, &movedItems);
1193 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1194 Q_ASSERT(movedItems.isEmpty());
1198 for (int i = 1; i < m_groupCount; ++i) {
1199 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1200 translatedRemoves.at(i),
1201 translatedInserts.at(i));
1205 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1207 Q_D(QQuickVisualDataModel);
1208 if (count <= 0 || !d->m_complete)
1211 const int minimum = qMin(from, to);
1212 const int maximum = qMax(from, to) + count;
1213 const int difference = from > to ? count : -count;
1215 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1216 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1217 if (item->modelIndex() >= from && item->modelIndex() < from + count)
1218 item->setModelIndex(item->modelIndex() - from + to);
1219 else if (item->modelIndex() >= minimum && item->modelIndex() < maximum)
1220 item->setModelIndex(item->modelIndex() + difference);
1223 QVector<Compositor::Remove> removes;
1224 QVector<Compositor::Insert> inserts;
1225 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1226 d->itemsMoved(removes, inserts);
1230 template <typename T> v8::Local<v8::Array>
1231 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1233 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1234 v8::Local<v8::String> indexKey = v8::String::New("index");
1235 v8::Local<v8::String> countKey = v8::String::New("count");
1236 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1238 for (int i = 0; i < changes.count(); ++i) {
1239 v8::Local<v8::Object> object = v8::Object::New();
1240 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1241 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1242 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1243 indexes->Set(i, object);
1248 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1250 Q_Q(QQuickVisualDataModel);
1251 emit q->modelUpdated(changeSet, reset);
1252 if (changeSet.difference() != 0)
1253 emit q->countChanged();
1256 void QQuickVisualDataModelPrivate::emitChanges()
1258 if (m_transaction || !m_complete)
1261 m_transaction = true;
1262 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1263 for (int i = 1; i < m_groupCount; ++i)
1264 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1265 m_transaction = false;
1267 const bool reset = m_reset;
1269 for (int i = 1; i < m_groupCount; ++i)
1270 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1272 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1273 if (cacheItem->object() && cacheItem->attached)
1274 cacheItem->attached->emitChanges();
1278 void QQuickVisualDataModel::_q_modelReset()
1280 Q_D(QQuickVisualDataModel);
1284 int oldCount = d->m_count;
1285 d->m_adaptorModel.rootIndex = QModelIndex();
1287 if (d->m_complete) {
1288 d->m_count = d->m_adaptorModel.count();
1290 for (int i = 0, c = d->m_cache.count(); i < c; ++i) {
1291 QQuickVisualDataModelItem *item = d->m_cache.at(i);
1292 if (item->modelIndex() != -1)
1293 item->setModelIndex(-1);
1296 QVector<Compositor::Remove> removes;
1297 QVector<Compositor::Insert> inserts;
1299 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1301 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1302 d->itemsMoved(removes, inserts);
1305 if (d->m_adaptorModel.canFetchMore())
1306 d->m_adaptorModel.fetchMore();
1310 emit rootIndexChanged();
1313 void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1315 Q_D(QQuickVisualDataModel);
1316 if (parent == d->m_adaptorModel.rootIndex)
1317 _q_itemsInserted(begin, end - begin + 1);
1320 void QQuickVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1322 Q_D(QQuickVisualDataModel);
1323 if (parent == d->m_adaptorModel.rootIndex)
1324 _q_itemsRemoved(begin, end - begin + 1);
1327 void QQuickVisualDataModel::_q_rowsMoved(
1328 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1329 const QModelIndex &destinationParent, int destinationRow)
1331 Q_D(QQuickVisualDataModel);
1332 const int count = sourceEnd - sourceStart + 1;
1333 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1334 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1335 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1336 _q_itemsRemoved(sourceStart, count);
1337 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1338 _q_itemsInserted(destinationRow, count);
1342 void QQuickVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
1344 Q_D(QQuickVisualDataModel);
1345 if (begin.parent() == d->m_adaptorModel.rootIndex)
1346 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, QList<int>());
1349 void QQuickVisualDataModel::_q_layoutChanged()
1351 Q_D(QQuickVisualDataModel);
1352 _q_itemsChanged(0, d->m_count, QList<int>());
1355 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1357 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(obj)) {
1358 if (cacheItem->object() == obj) { // Don't create attached item for child objects.
1359 cacheItem->attached = new QQuickVisualDataModelAttached(cacheItem, obj);
1360 return cacheItem->attached;
1363 return new QQuickVisualDataModelAttached(obj);
1366 bool QQuickVisualDataModelPrivate::insert(
1367 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1369 QQuickVisualDataModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1);
1373 for (int i = 1; i < m_groupCount; ++i)
1374 cacheItem->index[i] = before.index[i];
1376 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1377 for (uint i = 0; i < propertyNames->Length(); ++i) {
1378 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1379 cacheItem->setValue(
1380 m_cacheMetaType->v8Engine->toString(propertyName),
1381 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1384 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1386 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1387 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1389 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1390 m_cache.insert(before.cacheIndex, cacheItem);
1395 //============================================================================
1397 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1398 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1400 , groupCount(groupNames.count() + 1)
1401 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1402 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
1405 , groupNames(groupNames)
1407 initializeMetaObject();
1410 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1413 qPersistentDispose(constructor);
1416 void QQuickVisualDataModelItemMetaType::initializeMetaObject()
1418 QMetaObjectBuilder builder;
1419 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1420 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1421 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1424 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1425 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1426 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1427 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1428 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1429 propertyName.toUtf8(), "bool", notifierId);
1430 propertyBuilder.setWritable(true);
1432 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1433 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1434 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1435 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1436 propertyName.toUtf8(), "int", notifierId);
1437 propertyBuilder.setWritable(true);
1440 metaObject = builder.toMetaObject();
1443 void QQuickVisualDataModelItemMetaType::initializeConstructor()
1445 v8::HandleScope handleScope;
1446 v8::Context::Scope contextScope(v8Engine->context());
1448 constructor = qPersistentNew(v8::ObjectTemplate::New());
1450 constructor->SetHasExternalResource(true);
1451 constructor->SetAccessor(v8::String::New("model"), get_model);
1452 constructor->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
1453 constructor->SetAccessor(v8::String::New("isUnresolved"), get_member, 0, v8::Int32::New(30));
1456 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1457 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1458 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1459 constructor->SetAccessor(
1460 v8Engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1462 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1463 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1464 constructor->SetAccessor(
1465 v8Engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1469 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1472 foreach (const QString &groupName, groups) {
1473 int index = groupNames.indexOf(groupName);
1475 groupFlags |= 2 << index;
1480 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1483 if (groups->IsString()) {
1484 const QString groupName = v8Engine->toString(groups);
1485 int index = groupNames.indexOf(groupName);
1487 groupFlags |= 2 << index;
1488 } else if (groups->IsArray()) {
1489 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1490 for (uint i = 0; i < array->Length(); ++i) {
1491 const QString groupName = v8Engine->toString(array->Get(i));
1492 int index = groupNames.indexOf(groupName);
1494 groupFlags |= 2 << index;
1500 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1502 static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1503 qPersistentDispose(object);
1506 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1508 static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1509 qPersistentDispose(object);
1512 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1513 v8::Local<v8::String>, const v8::AccessorInfo &info)
1515 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1517 V8THROW_ERROR("Not a valid VisualData object");
1518 if (!cacheItem->metaType->model)
1519 return v8::Undefined();
1521 if (cacheItem->modelHandle.IsEmpty()) {
1522 cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1523 cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1525 ++cacheItem->scriptRef;
1528 return cacheItem->modelHandle;
1531 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1532 v8::Local<v8::String>, const v8::AccessorInfo &info)
1534 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1536 V8THROW_ERROR("Not a valid VisualData object");
1539 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1540 if (cacheItem->groups & (1 << i))
1541 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1544 return cacheItem->engine->fromVariant(groups);
1547 void QQuickVisualDataModelItemMetaType::set_groups(
1548 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1550 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1552 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1554 if (!cacheItem->metaType->model)
1556 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1558 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1559 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1560 if (cacheItem->groups & (1 << i)) {
1561 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1562 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1568 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1569 v8::Local<v8::String>, const v8::AccessorInfo &info)
1571 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1573 V8THROW_ERROR("Not a valid VisualData object");
1575 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1578 void QQuickVisualDataModelItemMetaType::set_member(
1579 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1581 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1583 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1585 if (!cacheItem->metaType->model)
1587 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1589 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1590 const bool member = value->BooleanValue();
1591 const int groupFlag = (1 << group);
1592 if (member == ((cacheItem->groups & groupFlag) != 0))
1595 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1596 if (cacheItem->groups & (1 << i)) {
1597 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1599 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1601 model->removeGroups(it, 1, Compositor::Group(i), groupFlag);
1607 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1608 v8::Local<v8::String>, const v8::AccessorInfo &info)
1610 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1612 V8THROW_ERROR("Not a valid VisualData object");
1614 return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
1618 //---------------------------------------------------------------------------
1620 QHash<QObject*, QQuickVisualDataModelItem *> QQuickVisualDataModelItem::contextData;
1622 QQuickVisualDataModelItem::QQuickVisualDataModelItem(
1623 QQuickVisualDataModelItemMetaType *metaType, int modelIndex)
1624 : QV8ObjectResource(metaType->v8Engine)
1625 , metaType(metaType)
1632 index[0] = modelIndex;
1636 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1638 Q_ASSERT(scriptRef == 0);
1639 Q_ASSERT(objectRef == 0);
1640 Q_ASSERT(!object());
1641 Q_ASSERT(indexHandle.IsEmpty());
1642 Q_ASSERT(modelHandle.IsEmpty());
1644 if (incubationTask && metaType->model)
1645 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1647 metaType->release();
1651 void QQuickVisualDataModelItem::Dispose()
1657 if (metaType->model) {
1658 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1659 const int cacheIndex = model->m_cache.indexOf(this);
1660 if (cacheIndex != -1) {
1661 model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1662 model->m_cache.removeAt(cacheIndex);
1663 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
1669 void QQuickVisualDataModelItem::setObject(QObject *g)
1671 if (QObject *previous = object())
1672 contextData.remove(previous);
1674 contextData.insert(g, this);
1676 QQmlGuard<QObject>::setObject(g);
1679 void QQuickVisualDataModelItem::destroyObject()
1681 QObject * const obj = object();
1686 QObjectPrivate *p = QObjectPrivate::get(obj);
1687 Q_ASSERT(p->declarativeData);
1688 QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
1689 if (data->ownContext && data->context)
1690 data->context->clearContext();
1694 attached->m_cacheItem = 0;
1699 void QQuickVisualDataModelItem::objectDestroyed(QObject *object)
1701 contextData.remove(object);
1707 //---------------------------------------------------------------------------
1709 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1710 QQuickVisualDataModelAttached *attached, QQuickVisualDataModelItemMetaType *metaType)
1711 : attached(attached)
1712 , metaType(metaType)
1714 if (!metaType->metaObject)
1715 metaType->initializeMetaObject();
1718 *static_cast<QMetaObject *>(this) = *metaType->metaObject;
1719 QObjectPrivate::get(attached)->metaObject = this;
1722 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1724 metaType->release();
1727 int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
1729 if (call == QMetaObject::ReadProperty) {
1730 if (_id >= metaType->indexPropertyOffset) {
1731 Compositor::Group group = Compositor::Group(_id - metaType->indexPropertyOffset + 1);
1732 *static_cast<int *>(arguments[0]) = attached->m_cacheItem->index[group];
1734 } else if (_id >= metaType->memberPropertyOffset) {
1735 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1736 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1739 } else if (call == QMetaObject::WriteProperty) {
1740 if (_id >= metaType->memberPropertyOffset) {
1741 if (!metaType->model)
1743 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1744 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1745 const int groupFlag = 1 << group;
1746 const bool member = attached->m_cacheItem->groups & groupFlag;
1747 if (member && !*static_cast<bool *>(arguments[0])) {
1748 Compositor::iterator it = model->m_compositor.find(
1749 group, attached->m_cacheItem->index[group]);
1750 model->removeGroups(it, 1, group, groupFlag);
1751 } else if (!member && *static_cast<bool *>(arguments[0])) {
1752 for (int i = 1; i < metaType->groupCount; ++i) {
1753 if (attached->m_cacheItem->groups & (1 << i)) {
1754 Compositor::iterator it = model->m_compositor.find(
1755 Compositor::Group(i), attached->m_cacheItem->index[i]);
1756 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1764 return attached->qt_metacall(call, _id, arguments);
1767 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(QObject *parent)
1769 , m_previousGroups(0)
1770 , m_modelChanged(false)
1772 QQml_setParent_noEvent(this, parent);
1775 QQuickVisualDataModelAttached::QQuickVisualDataModelAttached(
1776 QQuickVisualDataModelItem *cacheItem, QObject *parent)
1777 : m_cacheItem(cacheItem)
1778 , m_previousGroups(cacheItem->groups)
1779 , m_modelChanged(false)
1781 QQml_setParent_noEvent(this, parent);
1782 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1783 m_previousIndex[i] = m_cacheItem->index[i];
1785 new QQuickVisualDataModelAttachedMetaObject(this, cacheItem->metaType);
1789 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1791 This attached property holds the visual data model this delegate instance belongs to.
1793 It is attached to each instance of the delegate.
1796 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1798 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1802 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1804 This attached property holds the name of VisualDataGroups the item belongs to.
1806 It is attached to each instance of the delegate.
1809 QStringList QQuickVisualDataModelAttached::groups() const
1815 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1816 if (m_cacheItem->groups & (1 << i))
1817 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1822 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1827 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1829 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1830 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1831 if (m_cacheItem->groups & (1 << i)) {
1832 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), m_cacheItem->index[i]);
1833 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1839 bool QQuickVisualDataModelAttached::isUnresolved() const
1844 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1848 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1850 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1852 Changing this property will add or remove the item from the items group.
1854 It is attached to each instance of the delegate.
1858 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1860 This attached property holds the index of the item in the default \l items VisualDataGroup.
1862 It is attached to each instance of the delegate.
1866 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1868 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1870 Changing this property will add or remove the item from the items group. Change with caution
1871 as removing an item from the persistedItems group will destroy the current instance if it is
1872 not referenced by a model.
1874 It is attached to each instance of the delegate.
1878 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
1880 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
1882 It is attached to each instance of the delegate.
1885 void QQuickVisualDataModelAttached::emitChanges()
1887 if (m_modelChanged) {
1888 m_modelChanged = false;
1889 emit modelChanged();
1892 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
1893 m_previousGroups = m_cacheItem->groups;
1895 int indexChanges = 0;
1896 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1897 if (m_previousIndex[i] != m_cacheItem->index[i]) {
1898 m_previousIndex[i] = m_cacheItem->index[i];
1899 indexChanges |= (1 << i);
1904 const QMetaObject *meta = metaObject();
1905 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1906 if (groupChanges & (1 << i))
1907 QMetaObject::activate(this, meta, notifierId, 0);
1909 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1910 if (indexChanges & (1 << i))
1911 QMetaObject::activate(this, meta, notifierId, 0);
1915 emit groupsChanged();
1918 //============================================================================
1920 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
1927 static bool isChangedConnected(QObject *obj)
1929 IS_SIGNAL_CONNECTED(obj, "changed(QQmlV8Handle,QQmlV8Handle)");
1932 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
1934 Q_Q(QQuickVisualDataGroup);
1935 if (isChangedConnected(q) && !changeSet.isEmpty()) {
1936 v8::HandleScope handleScope;
1937 v8::Context::Scope contextScope(engine->context());
1938 v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes());
1939 v8::Local<v8::Array> inserted = QQuickVisualDataModelPrivate::buildChangeList(changeSet.inserts());
1941 QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
1943 if (changeSet.difference() != 0)
1944 emit q->countChanged();
1947 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
1949 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1950 it->emitModelUpdated(changeSet, reset);
1954 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
1956 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1957 it->createdPackage(index, package);
1960 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
1962 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1963 it->initPackage(index, package);
1966 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
1968 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1969 it->destroyingPackage(package);
1973 \qmlclass VisualDataGroup QQuickVisualDataGroup
1974 \inqmlmodule QtQuick 2
1975 \ingroup qml-working-with-data
1976 \brief The VisualDataGroup encapsulates a filtered set of visual data items.
1980 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
1981 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1985 QQuickVisualDataGroup::QQuickVisualDataGroup(
1986 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
1987 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1989 Q_D(QQuickVisualDataGroup);
1991 d->setModel(model, Compositor::Group(index));
1994 QQuickVisualDataGroup::~QQuickVisualDataGroup()
1999 \qmlproperty string QtQuick2::VisualDataGroup::name
2001 This property holds the name of the group.
2003 Each group in a model must have a unique name starting with a lower case letter.
2006 QString QQuickVisualDataGroup::name() const
2008 Q_D(const QQuickVisualDataGroup);
2012 void QQuickVisualDataGroup::setName(const QString &name)
2014 Q_D(QQuickVisualDataGroup);
2017 if (d->name != name) {
2024 \qmlproperty int QtQuick2::VisualDataGroup::count
2026 This property holds the number of items in the group.
2029 int QQuickVisualDataGroup::count() const
2031 Q_D(const QQuickVisualDataGroup);
2034 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
2038 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
2040 This property holds whether new items are assigned to this group by default.
2043 bool QQuickVisualDataGroup::defaultInclude() const
2045 Q_D(const QQuickVisualDataGroup);
2046 return d->defaultInclude;
2049 void QQuickVisualDataGroup::setDefaultInclude(bool include)
2051 Q_D(QQuickVisualDataGroup);
2052 if (d->defaultInclude != include) {
2053 d->defaultInclude = include;
2057 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2059 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2061 emit defaultIncludeChanged();
2066 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
2068 Returns a javascript object describing the item at \a index in the group.
2070 The returned object contains the same information that is available to a delegate from the
2071 VisualDataModel attached as well as the model for that item. It has the properties:
2074 \li \b model The model data of the item. This is the same as the model context property in
2076 \li \b groups A list the of names of groups the item is a member of. This property can be
2077 written to change the item's membership.
2078 \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
2079 Writing to this property will add or remove the item from the group.
2080 \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
2081 \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName. Writing to
2082 this property will add or remove the item from the group.
2083 \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
2087 QQmlV8Handle QQuickVisualDataGroup::get(int index)
2089 Q_D(QQuickVisualDataGroup);
2091 return QQmlV8Handle::fromHandle(v8::Undefined());;
2093 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2094 if (index < 0 || index >= model->m_compositor.count(d->group)) {
2095 qmlInfo(this) << tr("get: index out of range");
2096 return QQmlV8Handle::fromHandle(v8::Undefined());
2099 Compositor::iterator it = model->m_compositor.find(d->group, index);
2100 QQuickVisualDataModelItem *cacheItem = it->inCache()
2101 ? model->m_cache.at(it.cacheIndex)
2105 cacheItem = model->m_adaptorModel.createItem(
2106 model->m_cacheMetaType, model->m_context->engine(), it.modelIndex());
2108 return QQmlV8Handle::fromHandle(v8::Undefined());
2109 for (int i = 1; i < model->m_groupCount; ++i)
2110 cacheItem->index[i] = it.index[i];
2111 cacheItem->groups = it->flags;
2113 model->m_cache.insert(it.cacheIndex, cacheItem);
2114 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
2117 if (cacheItem->indexHandle.IsEmpty()) {
2118 if (model->m_cacheMetaType->constructor.IsEmpty())
2119 model->m_cacheMetaType->initializeConstructor();
2120 cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
2121 cacheItem->indexHandle->SetExternalResource(cacheItem);
2122 cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
2124 ++cacheItem->scriptRef;
2127 return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
2130 bool QQuickVisualDataGroupPrivate::parseIndex(
2131 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
2133 if (value->IsInt32()) {
2134 *index = value->Int32Value();
2136 } else if (value->IsObject()) {
2137 v8::Local<v8::Object> object = value->ToObject();
2138 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
2139 for (int i = 1; cacheItem && i < cacheItem->metaType->groupCount; ++i) {
2140 if (cacheItem->groups & (1 << i)) {
2141 *group = Compositor::Group(i);
2142 *index = cacheItem->index[i];
2150 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
2152 Q_D(QQuickVisualDataGroup);
2153 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2155 int index = model->m_compositor.count(d->group);
2156 Compositor::Group group = d->group;
2158 if (args->Length() == 0)
2162 v8::Local<v8::Value> v = (*args)[i];
2163 if (d->parseIndex(v, &index, &group)) {
2164 if (index < 0 || index > model->m_compositor.count(group)) {
2165 qmlInfo(this) << tr("insert: index out of range");
2168 if (++i == args->Length())
2173 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2174 ? model->m_compositor.findInsertPosition(group, index)
2175 : model->m_compositor.end();
2177 int groups = 1 << d->group;
2178 if (++i < args->Length())
2179 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2183 } else if (v->IsObject()) {
2184 model->insert(before, v->ToObject(), groups);
2185 model->emitChanges();
2190 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2191 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2192 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2194 Returns a reference to the instantiated item at \a index in the group.
2196 All items returned by create are added to the persistedItems group. Items in this
2197 group remain instantiated when not referenced by any view.
2200 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2202 Q_D(QQuickVisualDataGroup);
2206 if (args->Length() == 0)
2209 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2211 int index = model->m_compositor.count(d->group);
2212 Compositor::Group group = d->group;
2215 v8::Local<v8::Value> v = (*args)[i];
2216 if (d->parseIndex(v, &index, &group))
2219 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2221 if (v->IsObject()) {
2222 int groups = 1 << d->group;
2223 if (++i < args->Length())
2224 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2226 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2227 ? model->m_compositor.findInsertPosition(group, index)
2228 : model->m_compositor.end();
2230 index = before.index[d->group];
2233 if (!model->insert(before, v->ToObject(), groups)) {
2238 if (index < 0 || index >= model->m_compositor.count(group)) {
2239 qmlInfo(this) << tr("create: index out of range");
2243 QObject *object = model->object(group, index, false, false);
2245 QVector<Compositor::Insert> inserts;
2246 Compositor::iterator it = model->m_compositor.find(group, index);
2247 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2248 model->itemsInserted(inserts);
2251 args->returnValue(args->engine()->newQObject(object));
2252 model->emitChanges();
2255 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2257 Q_D(QQuickVisualDataGroup);
2261 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2263 if (args->Length() < 2)
2268 Compositor::Group fromGroup = d->group;
2269 Compositor::Group toGroup = d->group;
2271 v8::Local<v8::Value> v = (*args)[0];
2272 if (d->parseIndex(v, &from, &fromGroup)) {
2273 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2274 qmlInfo(this) << tr("resolve: from index out of range");
2278 qmlInfo(this) << tr("resolve: from index invalid");
2283 if (d->parseIndex(v, &to, &toGroup)) {
2284 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2285 qmlInfo(this) << tr("resolve: to index out of range");
2289 qmlInfo(this) << tr("resolve: to index invalid");
2293 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2294 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2296 if (!fromIt->isUnresolved()) {
2297 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2301 qmlInfo(this) << tr("resolve: to is not a model item");
2305 const int unresolvedFlags = fromIt->flags;
2306 const int resolvedFlags = toIt->flags;
2307 const int resolvedIndex = toIt.modelIndex();
2308 void * const resolvedList = toIt->list;
2310 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2311 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2313 if (toIt.cacheIndex > fromIt.cacheIndex)
2314 toIt.decrementIndexes(1, unresolvedFlags);
2315 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2319 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2320 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2321 model->itemsInserted(
2322 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2323 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2324 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2326 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2327 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2329 if (resolvedFlags & Compositor::CacheFlag)
2330 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2332 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2334 if (!cacheItem->isReferenced()) {
2335 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2336 model->m_cache.removeAt(toIt.cacheIndex);
2337 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2339 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2341 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
2342 if (cacheItem->attached)
2343 cacheItem->attached->emitUnresolvedChanged();
2346 model->emitChanges();
2350 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2352 Removes \a count items starting at \a index from the group.
2355 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2357 Q_D(QQuickVisualDataGroup);
2360 Compositor::Group group = d->group;
2364 if (args->Length() == 0)
2368 v8::Local<v8::Value> v = (*args)[i];
2369 if (!d->parseIndex(v, &index, &group)) {
2370 qmlInfo(this) << tr("remove: invalid index");
2374 if (++i < args->Length()) {
2377 count = v->Int32Value();
2380 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2381 if (index < 0 || index >= model->m_compositor.count(group)) {
2382 qmlInfo(this) << tr("remove: index out of range");
2383 } else if (count != 0) {
2384 Compositor::iterator it = model->m_compositor.find(group, index);
2385 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2386 qmlInfo(this) << tr("remove: invalid count");
2388 model->removeGroups(it, count, d->group, 1 << d->group);
2393 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2394 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2396 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2399 if (args->Length() < 2)
2403 v8::Local<v8::Value> v = (*args)[i];
2404 if (!parseIndex(v, index, group))
2409 *count = v->Int32Value();
2411 if (++i == args->Length())
2416 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2422 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2424 Adds \a count items starting at \a index to \a groups.
2427 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2429 Q_D(QQuickVisualDataGroup);
2430 Compositor::Group group = d->group;
2435 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2438 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2439 if (index < 0 || index >= model->m_compositor.count(group)) {
2440 qmlInfo(this) << tr("addGroups: index out of range");
2441 } else if (count != 0) {
2442 Compositor::iterator it = model->m_compositor.find(group, index);
2443 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2444 qmlInfo(this) << tr("addGroups: invalid count");
2446 model->addGroups(it, count, d->group, groups);
2452 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2454 Removes \a count items starting at \a index from \a groups.
2457 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2459 Q_D(QQuickVisualDataGroup);
2460 Compositor::Group group = d->group;
2465 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2468 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2469 if (index < 0 || index >= model->m_compositor.count(group)) {
2470 qmlInfo(this) << tr("removeGroups: index out of range");
2471 } else if (count != 0) {
2472 Compositor::iterator it = model->m_compositor.find(group, index);
2473 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2474 qmlInfo(this) << tr("removeGroups: invalid count");
2476 model->removeGroups(it, count, d->group, groups);
2482 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2484 Sets the \a groups \a count items starting at \a index belong to.
2487 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2489 Q_D(QQuickVisualDataGroup);
2490 Compositor::Group group = d->group;
2495 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2498 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2499 if (index < 0 || index >= model->m_compositor.count(group)) {
2500 qmlInfo(this) << tr("setGroups: index out of range");
2501 } else if (count != 0) {
2502 Compositor::iterator it = model->m_compositor.find(group, index);
2503 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2504 qmlInfo(this) << tr("setGroups: invalid count");
2506 model->setGroups(it, count, d->group, groups);
2512 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2514 Sets the \a groups \a count items starting at \a index belong to.
2518 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2520 Moves \a count at \a from in a group \a to a new position.
2523 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2525 Q_D(QQuickVisualDataGroup);
2527 if (args->Length() < 2)
2530 Compositor::Group fromGroup = d->group;
2531 Compositor::Group toGroup = d->group;
2536 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2537 qmlInfo(this) << tr("move: invalid from index");
2541 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2542 qmlInfo(this) << tr("move: invalid to index");
2546 if (args->Length() > 2) {
2547 v8::Local<v8::Value> v = (*args)[2];
2549 count = v->Int32Value();
2552 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2555 qmlInfo(this) << tr("move: invalid count");
2556 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2557 qmlInfo(this) << tr("move: from index out of range");
2558 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2559 qmlInfo(this) << tr("move: to index out of range");
2560 } else if (count > 0) {
2561 QVector<Compositor::Remove> removes;
2562 QVector<Compositor::Insert> inserts;
2564 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2565 model->itemsMoved(removes, inserts);
2566 model->emitChanges();
2572 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2574 This handler is called when items have been removed from or inserted into the group.
2576 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2577 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2579 Each index is adjusted for previous changes with all removed items preceding any inserted
2583 //============================================================================
2585 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2586 : QQuickVisualModel(*new QObjectPrivate, parent)
2589 , m_compositorGroup(Compositor::Cache)
2590 , m_inheritGroup(true)
2592 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2593 if (d->m_cacheMetaType) {
2594 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2595 m_compositorGroup = Compositor::Default;
2597 d->m_pendingParts.insert(this);
2601 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2605 QString QQuickVisualPartsModel::filterGroup() const
2608 return m_model->filterGroup();
2609 return m_filterGroup;
2612 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2614 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2615 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2619 if (m_filterGroup != group || m_inheritGroup) {
2620 m_filterGroup = group;
2621 m_inheritGroup = false;
2622 updateFilterGroup();
2624 emit filterGroupChanged();
2628 void QQuickVisualPartsModel::resetFilterGroup()
2630 if (!m_inheritGroup) {
2631 m_inheritGroup = true;
2632 updateFilterGroup();
2633 emit filterGroupChanged();
2637 void QQuickVisualPartsModel::updateFilterGroup()
2639 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2640 if (!model->m_cacheMetaType)
2643 if (m_inheritGroup) {
2644 if (m_filterGroup == model->m_filterGroup)
2646 m_filterGroup = model->m_filterGroup;
2649 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2650 m_compositorGroup = Compositor::Default;
2651 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2652 for (int i = 1; i < model->m_groupCount; ++i) {
2653 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2654 m_compositorGroup = Compositor::Group(i);
2659 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2660 if (m_compositorGroup != previousGroup) {
2661 QVector<QQuickChangeSet::Remove> removes;
2662 QVector<QQuickChangeSet::Insert> inserts;
2663 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2665 QQuickChangeSet changeSet;
2666 changeSet.apply(removes, inserts);
2667 if (!changeSet.isEmpty())
2668 emit modelUpdated(changeSet, false);
2670 if (changeSet.difference() != 0)
2671 emit countChanged();
2675 void QQuickVisualPartsModel::updateFilterGroup(
2676 Compositor::Group group, const QQuickChangeSet &changeSet)
2678 if (!m_inheritGroup)
2681 m_compositorGroup = group;
2682 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2684 if (!changeSet.isEmpty())
2685 emit modelUpdated(changeSet, false);
2687 if (changeSet.difference() != 0)
2688 emit countChanged();
2690 emit filterGroupChanged();
2693 int QQuickVisualPartsModel::count() const
2695 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2696 return model->m_delegate
2697 ? model->m_compositor.count(m_compositorGroup)
2701 bool QQuickVisualPartsModel::isValid() const
2703 return m_model->isValid();
2706 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2708 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2710 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2711 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2715 QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
2717 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(object)) {
2718 QObject *part = package->part(m_part);
2721 if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
2722 m_packaged.insertMulti(item, package);
2727 model->release(object);
2728 if (!model->m_delegateValidated) {
2730 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2731 model->m_delegateValidated = true;
2737 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2739 QQuickVisualModel::ReleaseFlags flags = 0;
2741 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2742 if (it != m_packaged.end()) {
2743 QQuickPackage *package = *it;
2744 QQml_setParent_noEvent(item, package);
2745 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2746 flags = model->release(package);
2747 m_packaged.erase(it);
2748 if (!m_packaged.contains(item))
2749 flags &= ~Referenced;
2750 if (flags & Destroyed)
2751 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2756 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2758 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2761 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2763 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2764 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
2765 m_watchedRoles = roles;
2768 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2770 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2771 if (it != m_packaged.end()) {
2772 if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(*it))
2773 return cacheItem->index[m_compositorGroup];
2778 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2780 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2781 emit createdItem(index, item);
2784 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2786 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2787 emit initItem(index, item);
2790 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2792 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
2793 Q_ASSERT(!m_packaged.contains(item));
2794 emit destroyingItem(item);
2795 item->setParentItem(0);
2796 QQml_setParent_noEvent(item, package);
2800 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2802 emit modelUpdated(changeSet, reset);
2803 if (changeSet.difference() != 0)
2804 emit countChanged();