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 //---------------------------------------------------------------------------
77 QHash<QObject*, QQuickVisualDataModelAttached*> QQuickVisualDataModelAttached::attachedProperties;
80 \qmlclass VisualDataModel QQuickVisualDataModel
81 \inqmlmodule QtQuick 2
82 \ingroup qml-working-with-data
83 \brief The VisualDataModel encapsulates a model and delegate
85 A VisualDataModel encapsulates a model and the delegate that will
86 be instantiated for items in the model.
88 It is usually not necessary to create VisualDataModel elements.
89 However, it can be useful for manipulating and accessing the \l modelIndex
90 when a QAbstractItemModel subclass is used as the
91 model. Also, VisualDataModel is used together with \l Package to
92 provide delegates to multiple views.
94 The example below illustrates using a VisualDataModel with a ListView.
96 \snippet doc/src/snippets/qml/visualdatamodel.qml 0
99 QQuickVisualDataModelPrivate::QQuickVisualDataModelPrivate(QQmlContext *ctxt)
105 , m_compositorGroup(Compositor::Cache)
107 , m_delegateValidated(false)
109 , m_transaction(false)
110 , m_incubatorCleanupScheduled(false)
111 , m_filterGroup(QStringLiteral("items"))
114 , m_persistedItems(0)
115 , m_groupCount(Compositor::MinimumGroupCount)
119 QQuickVisualDataModelPrivate::~QQuickVisualDataModelPrivate()
121 qDeleteAll(m_finishedIncubating);
124 void QQuickVisualDataModelPrivate::connectModel(QQuickVisualAdaptorModel *model)
126 Q_Q(QQuickVisualDataModel);
128 QObject::connect(model, SIGNAL(itemsInserted(int,int)), q, SLOT(_q_itemsInserted(int,int)));
129 QObject::connect(model, SIGNAL(itemsRemoved(int,int)), q, SLOT(_q_itemsRemoved(int,int)));
130 QObject::connect(model, SIGNAL(itemsMoved(int,int,int)), q, SLOT(_q_itemsMoved(int,int,int)));
131 QObject::connect(model, SIGNAL(itemsChanged(int,int)), q, SLOT(_q_itemsChanged(int,int)));
132 QObject::connect(model, SIGNAL(modelReset(int,int)), q, SLOT(_q_modelReset(int,int)));
135 void QQuickVisualDataModelPrivate::init()
137 Q_Q(QQuickVisualDataModel);
138 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
140 m_adaptorModel = new QQuickVisualAdaptorModel;
141 QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged()));
143 m_items = new QQuickVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
144 m_items->setDefaultInclude(true);
145 m_persistedItems = new QQuickVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
146 QQuickVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
149 QQuickVisualDataModel::QQuickVisualDataModel()
150 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(0)))
152 Q_D(QQuickVisualDataModel);
156 QQuickVisualDataModel::QQuickVisualDataModel(QQmlContext *ctxt, QObject *parent)
157 : QQuickVisualModel(*(new QQuickVisualDataModelPrivate(ctxt)), parent)
159 Q_D(QQuickVisualDataModel);
163 QQuickVisualDataModel::~QQuickVisualDataModel()
165 Q_D(QQuickVisualDataModel);
167 foreach (QQuickVisualDataModelItem *cacheItem, d->m_cache) {
168 // If the object holds the last reference to the cache item deleting it will also
169 // delete the cache item, temporarily increase the reference count to avoid this.
170 cacheItem->scriptRef += 1;
171 delete cacheItem->object;
172 cacheItem->scriptRef -= 1;
173 cacheItem->objectRef = 0;
174 cacheItem->object = 0;
175 if (!cacheItem->isReferenced())
179 delete d->m_adaptorModel;
180 if (d->m_cacheMetaType)
181 d->m_cacheMetaType->release();
185 void QQuickVisualDataModel::classBegin()
189 void QQuickVisualDataModel::componentComplete()
191 Q_D(QQuickVisualDataModel);
192 d->m_complete = true;
194 int defaultGroups = 0;
195 QStringList groupNames;
196 groupNames.append(QStringLiteral("items"));
197 groupNames.append(QStringLiteral("persistedItems"));
198 if (QQuickVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
199 defaultGroups |= Compositor::DefaultFlag;
200 if (QQuickVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
201 defaultGroups |= Compositor::PersistedFlag;
202 for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
203 QString name = d->m_groups[i]->name();
204 if (name.isEmpty()) {
205 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
208 } else if (name.at(0).isUpper()) {
209 qmlInfo(d->m_groups[i]) << QQuickVisualDataGroup::tr("Group names must start with a lower case letter");
210 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
214 groupNames.append(name);
216 QQuickVisualDataGroupPrivate *group = QQuickVisualDataGroupPrivate::get(d->m_groups[i]);
217 group->setModel(this, Compositor::Group(i));
218 if (group->defaultInclude)
219 defaultGroups |= (1 << i);
223 d->m_context = qmlContext(this);
225 d->m_cacheMetaType = new QQuickVisualDataModelItemMetaType(
226 QQmlEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
228 d->m_compositor.setGroupCount(d->m_groupCount);
229 d->m_compositor.setDefaultGroups(defaultGroups);
230 d->updateFilterGroup();
232 while (!d->m_pendingParts.isEmpty())
233 static_cast<QQuickVisualPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
235 d->connectModel(d->m_adaptorModel);
236 QVector<Compositor::Insert> inserts;
237 d->m_compositor.append(
240 qMax(0, d->m_adaptorModel->count()),
241 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
243 d->itemsInserted(inserts);
246 if (d->m_adaptorModel->canFetchMore())
247 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
251 \qmlproperty model QtQuick2::VisualDataModel::model
252 This property holds the model providing data for the VisualDataModel.
254 The model provides a set of data that is used to create the items
255 for a view. For large or dynamic datasets the model is usually
256 provided by a C++ model object. The C++ model object must be a \l
257 {QAbstractItemModel} subclass or a simple list.
259 Models can also be created directly in QML, using a \l{ListModel} or
262 \sa {qmlmodels}{Data Models}
264 QVariant QQuickVisualDataModel::model() const
266 Q_D(const QQuickVisualDataModel);
267 return d->m_adaptorModel->model();
270 void QQuickVisualDataModel::setModel(const QVariant &model)
272 Q_D(QQuickVisualDataModel);
273 d->m_adaptorModel->setModel(model, d->m_context ? d->m_context->engine() : qmlEngine(this));
274 if (d->m_complete && d->m_adaptorModel->canFetchMore())
275 QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
279 \qmlproperty Component QtQuick2::VisualDataModel::delegate
281 The delegate provides a template defining each item instantiated by a view.
282 The index is exposed as an accessible \c index property. Properties of the
283 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
285 QQmlComponent *QQuickVisualDataModel::delegate() const
287 Q_D(const QQuickVisualDataModel);
288 return d->m_delegate;
291 void QQuickVisualDataModel::setDelegate(QQmlComponent *delegate)
293 Q_D(QQuickVisualDataModel);
294 if (d->m_transaction) {
295 qmlInfo(this) << tr("The delegate of a VisualDataModel cannot be changed within onUpdated.");
298 bool wasValid = d->m_delegate != 0;
299 d->m_delegate = delegate;
300 d->m_delegateValidated = false;
301 if (wasValid && d->m_complete) {
302 for (int i = 1; i < d->m_groupCount; ++i) {
303 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.remove(
304 0, d->m_compositor.count(Compositor::Group(i)));
307 if (d->m_complete && d->m_delegate) {
308 for (int i = 1; i < d->m_groupCount; ++i) {
309 QQuickVisualDataGroupPrivate::get(d->m_groups[i])->changeSet.insert(
310 0, d->m_compositor.count(Compositor::Group(i)));
317 \qmlproperty QModelIndex QtQuick2::VisualDataModel::rootIndex
319 QAbstractItemModel provides a hierarchical tree of data, whereas
320 QML only operates on list data. \c rootIndex allows the children of
321 any node in a QAbstractItemModel to be provided by this model.
323 This property only affects models of type QAbstractItemModel that
324 are hierarchical (e.g, a tree model).
326 For example, here is a simple interactive file system browser.
327 When a directory name is clicked, the view's \c rootIndex is set to the
328 QModelIndex node of the clicked directory, thus updating the view to show
329 the new directory's contents.
332 \snippet doc/src/snippets/qml/visualdatamodel_rootindex/main.cpp 0
335 \snippet doc/src/snippets/qml/visualdatamodel_rootindex/view.qml 0
337 If the \l model is a QAbstractItemModel subclass, the delegate can also
338 reference a \c hasModelChildren property (optionally qualified by a
339 \e model. prefix) that indicates whether the delegate's model item has
343 \sa modelIndex(), parentModelIndex()
345 QVariant QQuickVisualDataModel::rootIndex() const
347 Q_D(const QQuickVisualDataModel);
348 return d->m_adaptorModel->rootIndex();
351 void QQuickVisualDataModel::setRootIndex(const QVariant &root)
353 Q_D(QQuickVisualDataModel);
354 d->m_adaptorModel->setRootIndex(root);
358 \qmlmethod QModelIndex QtQuick2::VisualDataModel::modelIndex(int index)
360 QAbstractItemModel provides a hierarchical tree of data, whereas
361 QML only operates on list data. This function assists in using
364 Returns a QModelIndex for the specified index.
365 This value can be assigned to rootIndex.
369 QVariant QQuickVisualDataModel::modelIndex(int idx) const
371 Q_D(const QQuickVisualDataModel);
372 return d->m_adaptorModel->modelIndex(idx);
376 \qmlmethod QModelIndex QtQuick2::VisualDataModel::parentModelIndex()
378 QAbstractItemModel provides a hierarchical tree of data, whereas
379 QML only operates on list data. This function assists in using
382 Returns a QModelIndex for the parent of the current rootIndex.
383 This value can be assigned to rootIndex.
387 QVariant QQuickVisualDataModel::parentModelIndex() const
389 Q_D(const QQuickVisualDataModel);
390 return d->m_adaptorModel->parentModelIndex();
394 \qmlproperty int QtQuick2::VisualDataModel::count
397 int QQuickVisualDataModel::count() const
399 Q_D(const QQuickVisualDataModel);
402 return d->m_compositor.count(d->m_compositorGroup);
405 void QQuickVisualDataModelPrivate::destroy(QObject *object)
407 QObjectPrivate *p = QObjectPrivate::get(object);
408 Q_ASSERT(p->declarativeData);
409 QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
410 if (data->ownContext && data->context)
411 data->context->clearContext();
412 object->deleteLater();
415 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObject *object)
417 QQuickVisualDataModel::ReleaseFlags stat = 0;
421 if (QQuickVisualDataModelAttached *attached = QQuickVisualDataModelAttached::properties(object)) {
422 QQuickVisualDataModelItem *cacheItem = attached->m_cacheItem;
423 if (cacheItem->releaseObject()) {
425 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
426 emitDestroyingItem(item);
427 cacheItem->object = 0;
428 if (cacheItem->incubationTask) {
429 releaseIncubator(cacheItem->incubationTask);
430 cacheItem->incubationTask = 0;
432 stat |= QQuickVisualModel::Destroyed;
434 stat |= QQuickVisualDataModel::Referenced;
441 Returns ReleaseStatus flags.
444 QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *item)
446 Q_D(QQuickVisualDataModel);
447 QQuickVisualModel::ReleaseFlags stat = d->release(item);
448 if (stat & Destroyed)
449 item->setParentItem(0);
453 void QQuickVisualDataModelPrivate::group_append(
454 QQmlListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
456 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
459 if (d->m_groupCount == Compositor::MaximumGroupCount) {
460 qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
463 d->m_groups[d->m_groupCount] = group;
464 d->m_groupCount += 1;
467 int QQuickVisualDataModelPrivate::group_count(
468 QQmlListProperty<QQuickVisualDataGroup> *property)
470 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
471 return d->m_groupCount - 1;
474 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
475 QQmlListProperty<QQuickVisualDataGroup> *property, int index)
477 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
478 return index >= 0 && index < d->m_groupCount - 1
479 ? d->m_groups[index + 1]
484 \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
486 This property holds a visual data model's group definitions.
488 Groups define a sub-set of the items in a visual data model and can be used to filter
491 For every group defined in a VisualDataModel two attached properties are added to each
492 delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
493 item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
494 index of the item in that group.
496 The following example illustrates using groups to select items in a model.
498 \snippet doc/src/snippets/qml/visualdatagroup.qml 0
501 QQmlListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
503 Q_D(QQuickVisualDataModel);
504 return QQmlListProperty<QQuickVisualDataGroup>(
507 QQuickVisualDataModelPrivate::group_append,
508 QQuickVisualDataModelPrivate::group_count,
509 QQuickVisualDataModelPrivate::group_at);
513 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
515 This property holds visual data model's default group to which all new items are added.
518 QQuickVisualDataGroup *QQuickVisualDataModel::items()
520 Q_D(QQuickVisualDataModel);
525 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
527 This property holds visual data model's persisted items group.
529 Items in this group are not destroyed when released by a view, instead they are persisted
530 until removed from the group.
532 An item can be removed from the persistedItems group by setting the
533 VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
534 at that time it will be destroyed. Adding an item to this group will not create a new
537 Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
541 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
543 Q_D(QQuickVisualDataModel);
544 return d->m_persistedItems;
548 \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
550 This property holds the name of the group used to filter the visual data model.
552 Only items which belong to this group are visible to a view.
554 By default this is the \l items group.
557 QString QQuickVisualDataModel::filterGroup() const
559 Q_D(const QQuickVisualDataModel);
560 return d->m_filterGroup;
563 void QQuickVisualDataModel::setFilterGroup(const QString &group)
565 Q_D(QQuickVisualDataModel);
567 if (d->m_transaction) {
568 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
572 if (d->m_filterGroup != group) {
573 d->m_filterGroup = group;
574 d->updateFilterGroup();
575 emit filterGroupChanged();
579 void QQuickVisualDataModel::resetFilterGroup()
581 setFilterGroup(QStringLiteral("items"));
584 void QQuickVisualDataModelPrivate::updateFilterGroup()
586 Q_Q(QQuickVisualDataModel);
587 if (!m_cacheMetaType)
590 QQuickListCompositor::Group previousGroup = m_compositorGroup;
591 m_compositorGroup = Compositor::Default;
592 for (int i = 1; i < m_groupCount; ++i) {
593 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
594 m_compositorGroup = Compositor::Group(i);
599 QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
600 if (m_compositorGroup != previousGroup) {
601 QVector<QQuickChangeSet::Remove> removes;
602 QVector<QQuickChangeSet::Insert> inserts;
603 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
605 QQuickChangeSet changeSet;
606 changeSet.apply(removes, inserts);
607 emit q->modelUpdated(changeSet, false);
609 if (changeSet.difference() != 0)
610 emit q->countChanged();
613 foreach (QQuickVisualPartsModel *model, m_parts->models)
614 model->updateFilterGroup(m_compositorGroup, changeSet);
620 \qmlproperty object QtQuick2::VisualDataModel::parts
622 The \a parts property selects a VisualDataModel which creates
623 delegates from the part named. This is used in conjunction with
624 the \l Package element.
626 For example, the code below selects a model which creates
627 delegates named \e list from a \l Package:
633 Item { Package.name: "list" }
639 width: 200; height:200
640 model: visualModel.parts.list
647 QObject *QQuickVisualDataModel::parts()
649 Q_D(QQuickVisualDataModel);
651 d->m_parts = new QQuickVisualDataModelParts(this);
655 void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
657 for (int i = 1; i < m_groupCount; ++i)
658 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
661 void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
663 for (int i = 1; i < m_groupCount; ++i)
664 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
667 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
669 for (int i = 1; i < m_groupCount; ++i)
670 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
673 void QVDMIncubationTask::statusChanged(Status status)
675 vdm->incubatorStatusChanged(this, status);
678 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
680 Q_Q(QQuickVisualDataModel);
681 if (!incubationTask->isError())
682 incubationTask->clear();
683 m_finishedIncubating.append(incubationTask);
684 if (!m_incubatorCleanupScheduled) {
685 m_incubatorCleanupScheduled = true;
686 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
690 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
692 Q_Q(QQuickVisualDataModel);
693 if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
696 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
697 cacheItem->incubationTask = 0;
699 if (status == QQmlIncubator::Ready) {
700 incubationTask->incubating = 0;
701 releaseIncubator(incubationTask);
702 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
703 emitCreatedPackage(cacheItem, package);
704 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
705 emitCreatedItem(cacheItem, item);
706 } else if (status == QQmlIncubator::Error) {
707 delete incubationTask->incubatingContext;
708 incubationTask->incubatingContext = 0;
709 if (!cacheItem->isReferenced()) {
710 int cidx = m_cache.indexOf(cacheItem);
711 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
712 m_cache.removeAt(cidx);
714 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
716 releaseIncubator(incubationTask);
717 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
721 void QVDMIncubationTask::setInitialState(QObject *o)
723 vdm->setInitialState(this, o);
726 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
728 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
729 cacheItem->object = o;
730 QQml_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
731 incubationTask->incubatingContext = 0;
733 cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
734 cacheItem->attached->setCacheItem(cacheItem);
735 new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
736 cacheItem->attached->emitChanges();
738 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
739 emitInitPackage(cacheItem, package);
740 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
741 emitInitItem(cacheItem, item);
744 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
746 Q_Q(QQuickVisualDataModel);
747 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
748 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
752 Compositor::iterator it = m_compositor.find(group, index);
754 QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
757 cacheItem = m_adaptorModel->createItem(m_cacheMetaType, it.modelIndex());
758 for (int i = 1; i < m_groupCount; ++i)
759 cacheItem->index[i] = it.index[i];
761 cacheItem->groups = it->flags;
763 m_cache.insert(it.cacheIndex, cacheItem);
764 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
765 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
768 if (cacheItem->incubationTask) {
770 // previously requested async - now needed immediately
771 cacheItem->incubationTask->forceCompletion();
773 } else if (!cacheItem->object) {
774 QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
775 cacheItem->incubationTask = incubator;
777 QQmlContext *creationContext = m_delegate->creationContext();
778 QQmlContext *rootContext = new QQuickVisualDataModelContext(
779 cacheItem, creationContext ? creationContext : m_context.data());
780 QQmlContext *ctxt = rootContext;
781 if (m_adaptorModel->flags() & QQuickVisualAdaptorModel::ProxiedObject) {
782 if (QQuickVisualAdaptorModelProxyInterface *proxy = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
783 ctxt->setContextObject(proxy->proxiedObject());
784 ctxt = new QQuickVisualDataModelContext(cacheItem, ctxt, ctxt);
788 ctxt->setContextObject(cacheItem);
790 incubator->incubating = cacheItem;
791 incubator->incubatingContext = rootContext;
792 m_delegate->create(*incubator, ctxt, m_context);
795 if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
796 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
797 if (cacheItem->object && reference)
798 cacheItem->referenceObject();
799 return cacheItem->object;
803 If asynchronous is true or the component is being loaded asynchronously due
804 to an ancestor being loaded asynchronously, item() may return 0. In this
805 case itemCreated() will be emitted when the item is available. The item
806 at this stage does not have any references, so item() must be called again
807 to ensure a reference is held. Any call to item() which returns a valid item
808 must be matched by a call to release() in order to destroy the item.
810 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
812 Q_D(QQuickVisualDataModel);
813 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
814 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
818 QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
822 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
826 if (!d->m_delegateValidated) {
828 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
829 d->m_delegateValidated = true;
834 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
836 Compositor::iterator it = m_compositor.find(group, index);
837 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
838 return model->stringValue(it.modelIndex(), name);
843 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
845 Q_D(QQuickVisualDataModel);
846 return d->stringValue(d->m_compositorGroup, index, name);
849 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
851 Q_D(const QQuickVisualDataModel);
852 if (QQuickVisualDataModelAttached *attached = QQuickVisualDataModelAttached::properties(item))
853 return attached->m_cacheItem->index[d->m_compositorGroup];
857 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
859 Q_D(QQuickVisualDataModel);
860 d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles);
861 d->watchedRoles = roles;
864 void QQuickVisualDataModelPrivate::addGroups(
865 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
867 QVector<Compositor::Insert> inserts;
868 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
869 itemsInserted(inserts);
873 void QQuickVisualDataModelPrivate::removeGroups(
874 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
876 QVector<Compositor::Remove> removes;
877 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
878 itemsRemoved(removes);
882 void QQuickVisualDataModelPrivate::setGroups(
883 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
885 QVector<Compositor::Remove> removes;
886 QVector<Compositor::Insert> inserts;
888 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
889 itemsInserted(inserts);
890 const int removeFlags = ~groupFlags & Compositor::GroupMask;
892 from = m_compositor.find(from.group, from.index[from.group]);
893 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
894 itemsRemoved(removes);
898 bool QQuickVisualDataModel::event(QEvent *e)
900 Q_D(QQuickVisualDataModel);
901 if (e->type() == QEvent::UpdateRequest) {
902 d->m_adaptorModel->fetchMore();
903 } else if (e->type() == QEvent::User) {
904 d->m_incubatorCleanupScheduled = false;
905 qDeleteAll(d->m_finishedIncubating);
906 d->m_finishedIncubating.clear();
908 return QQuickVisualModel::event(e);
911 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
916 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
918 foreach (const Compositor::Change &change, changes) {
919 for (int i = 1; i < m_groupCount; ++i) {
920 if (change.inGroup(i)) {
921 translatedChanges[i].append(
922 QQuickChangeSet::Change(change.index[i], change.count));
927 for (int i = 1; i < m_groupCount; ++i)
928 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
931 void QQuickVisualDataModel::_q_itemsChanged(int index, int count)
933 Q_D(QQuickVisualDataModel);
936 QVector<Compositor::Change> changes;
937 d->m_compositor.listItemsChanged(d->m_adaptorModel, index, count, &changes);
938 d->itemsChanged(changes);
942 void QQuickVisualDataModelPrivate::itemsInserted(
943 const QVector<Compositor::Insert> &inserts,
944 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
945 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
949 int inserted[Compositor::MaximumGroupCount];
950 for (int i = 1; i < m_groupCount; ++i)
953 foreach (const Compositor::Insert &insert, inserts) {
954 for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
955 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
956 for (int i = 1; i < m_groupCount; ++i)
957 cacheItem->index[i] += inserted[i];
959 for (int i = 1; i < m_groupCount; ++i) {
960 if (insert.inGroup(i)) {
961 (*translatedInserts)[i].append(
962 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
963 inserted[i] += insert.count;
967 if (!insert.inCache())
970 if (movedItems && insert.isMove()) {
971 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
972 Q_ASSERT(items.count() == insert.count);
973 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
975 if (insert.inGroup()) {
976 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
977 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
978 cacheItem->groups |= insert.flags & Compositor::GroupMask;
979 for (int i = 1; i < m_groupCount; ++i) {
980 cacheItem->index[i] = cacheItem->groups & (1 << i)
981 ? insert.index[i] + offset
986 cacheIndex = insert.cacheIndex + insert.count;
989 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
990 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
991 for (int i = 1; i < m_groupCount; ++i)
992 cacheItem->index[i] += inserted[i];
996 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
998 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
999 itemsInserted(inserts, &translatedInserts);
1000 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1004 for (int i = 1; i < m_groupCount; ++i)
1005 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1008 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1011 Q_D(QQuickVisualDataModel);
1014 QVector<Compositor::Insert> inserts;
1015 d->m_compositor.listItemsInserted(d->m_adaptorModel, index, count, &inserts);
1016 d->itemsInserted(inserts);
1020 void QQuickVisualDataModelPrivate::itemsRemoved(
1021 const QVector<Compositor::Remove> &removes,
1022 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1023 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1026 int removedCache = 0;
1028 int removed[Compositor::MaximumGroupCount];
1029 for (int i = 1; i < m_groupCount; ++i)
1032 foreach (const Compositor::Remove &remove, removes) {
1033 for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
1034 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1035 for (int i = 1; i < m_groupCount; ++i)
1036 cacheItem->index[i] -= removed[i];
1038 for (int i = 1; i < m_groupCount; ++i) {
1039 if (remove.inGroup(i)) {
1040 (*translatedRemoves)[i].append(
1041 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1042 removed[i] += remove.count;
1046 if (!remove.inCache())
1049 if (movedItems && remove.isMove()) {
1050 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1051 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1052 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1053 m_cache.erase(begin, end);
1055 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1056 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1057 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1058 destroy(cacheItem->object);
1059 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
1060 emitDestroyingPackage(package);
1061 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
1062 emitDestroyingItem(item);
1063 cacheItem->object = 0;
1065 if (!cacheItem->isReferenced()) {
1066 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1067 m_cache.removeAt(cacheIndex);
1071 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1072 } else if (remove.groups() == cacheItem->groups) {
1073 cacheItem->groups = 0;
1074 for (int i = 1; i < m_groupCount; ++i)
1075 cacheItem->index[i] = -1;
1077 for (int i = 1; i < m_groupCount; ++i) {
1078 if (remove.inGroup(i))
1079 cacheItem->index[i] = remove.index[i];
1081 cacheItem->groups &= ~remove.flags;
1087 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1088 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1089 for (int i = 1; i < m_groupCount; ++i)
1090 cacheItem->index[i] -= removed[i];
1094 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1096 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1097 itemsRemoved(removes, &translatedRemoves);
1098 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1102 for (int i = 1; i < m_groupCount; ++i)
1103 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1106 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1108 Q_D(QQuickVisualDataModel);
1112 QVector<Compositor::Remove> removes;
1113 d->m_compositor.listItemsRemoved(d->m_adaptorModel, index, count, &removes);
1114 d->itemsRemoved(removes);
1119 void QQuickVisualDataModelPrivate::itemsMoved(
1120 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1122 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1124 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1125 itemsRemoved(removes, &translatedRemoves, &movedItems);
1127 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1128 itemsInserted(inserts, &translatedInserts, &movedItems);
1129 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1130 Q_ASSERT(movedItems.isEmpty());
1134 for (int i = 1; i < m_groupCount; ++i) {
1135 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1136 translatedRemoves.at(i),
1137 translatedInserts.at(i));
1141 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1143 Q_D(QQuickVisualDataModel);
1147 QVector<Compositor::Remove> removes;
1148 QVector<Compositor::Insert> inserts;
1149 d->m_compositor.listItemsMoved(d->m_adaptorModel, from, to, count, &removes, &inserts);
1150 d->itemsMoved(removes, inserts);
1154 template <typename T> v8::Local<v8::Array>
1155 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1157 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1158 v8::Local<v8::String> indexKey = v8::String::New("index");
1159 v8::Local<v8::String> countKey = v8::String::New("count");
1160 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1162 for (int i = 0; i < changes.count(); ++i) {
1163 v8::Local<v8::Object> object = v8::Object::New();
1164 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1165 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1166 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1167 indexes->Set(i, object);
1172 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1174 Q_Q(QQuickVisualDataModel);
1175 emit q->modelUpdated(changeSet, reset);
1176 if (changeSet.difference() != 0)
1177 emit q->countChanged();
1180 void QQuickVisualDataModelPrivate::emitChanges()
1182 if (m_transaction || !m_complete)
1185 m_transaction = true;
1186 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1187 for (int i = 1; i < m_groupCount; ++i)
1188 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1189 m_transaction = false;
1191 const bool reset = m_reset;
1193 for (int i = 1; i < m_groupCount; ++i)
1194 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1196 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1197 if (cacheItem->object && cacheItem->attached)
1198 cacheItem->attached->emitChanges();
1202 void QQuickVisualDataModel::_q_modelReset(int oldCount, int newCount)
1204 Q_D(QQuickVisualDataModel);
1208 QVector<Compositor::Remove> removes;
1209 QVector<Compositor::Insert> inserts;
1211 d->m_compositor.listItemsRemoved(d->m_adaptorModel, 0, oldCount, &removes);
1213 d->m_compositor.listItemsInserted(d->m_adaptorModel, 0, newCount, &inserts);
1214 d->itemsMoved(removes, inserts);
1219 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1221 return QQuickVisualDataModelAttached::properties(obj);
1224 bool QQuickVisualDataModelPrivate::insert(
1225 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1227 QQuickVisualDataModelItem *cacheItem = m_adaptorModel->createItem(m_cacheMetaType, -1);
1231 for (int i = 1; i < m_groupCount; ++i)
1232 cacheItem->index[i] = before.index[i];
1234 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1235 for (uint i = 0; i < propertyNames->Length(); ++i) {
1236 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1237 cacheItem->setValue(
1238 m_cacheMetaType->v8Engine->toString(propertyName),
1239 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1242 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1244 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1245 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1247 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1248 m_cache.insert(before.cacheIndex, cacheItem);
1253 //============================================================================
1255 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1256 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1258 , groupCount(groupNames.count() + 1)
1259 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1260 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
1263 , groupNames(groupNames)
1265 QMetaObjectBuilder builder;
1266 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1267 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1268 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1270 v8::HandleScope handleScope;
1271 v8::Context::Scope contextScope(engine->context());
1272 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
1273 ft->InstanceTemplate()->SetHasExternalResource(true);
1274 ft->PrototypeTemplate()->SetAccessor(v8::String::New("model"), get_model);
1275 ft->PrototypeTemplate()->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
1276 ft->PrototypeTemplate()->SetAccessor(v8::String::New("isUnresolved"), get_member, 0, v8::Int32::New(30));
1279 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1280 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1281 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1282 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1283 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1284 propertyName.toUtf8(), "bool", notifierId);
1285 propertyBuilder.setWritable(true);
1287 ft->PrototypeTemplate()->SetAccessor(
1288 engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1290 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1291 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1292 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1293 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1294 propertyName.toUtf8(), "int", notifierId);
1295 propertyBuilder.setWritable(true);
1297 ft->PrototypeTemplate()->SetAccessor(
1298 engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1301 metaObject = builder.toMetaObject();
1303 constructor = qPersistentNew<v8::Function>(ft->GetFunction());
1306 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1309 qPersistentDispose(constructor);
1312 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1315 foreach (const QString &groupName, groups) {
1316 int index = groupNames.indexOf(groupName);
1318 groupFlags |= 2 << index;
1323 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1326 if (groups->IsString()) {
1327 const QString groupName = v8Engine->toString(groups);
1328 int index = groupNames.indexOf(groupName);
1330 groupFlags |= 2 << index;
1331 } else if (groups->IsArray()) {
1332 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1333 for (uint i = 0; i < array->Length(); ++i) {
1334 const QString groupName = v8Engine->toString(array->Get(i));
1335 int index = groupNames.indexOf(groupName);
1337 groupFlags |= 2 << index;
1343 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1345 static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1346 qPersistentDispose(object);
1349 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1351 static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1352 qPersistentDispose(object);
1355 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1356 v8::Local<v8::String>, const v8::AccessorInfo &info)
1358 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1360 V8THROW_ERROR("Not a valid VisualData object");
1361 if (!cacheItem->metaType->model)
1362 return v8::Undefined();
1364 if (cacheItem->modelHandle.IsEmpty()) {
1365 cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1366 cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1368 ++cacheItem->scriptRef;
1371 return cacheItem->modelHandle;
1374 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
1375 v8::Local<v8::String>, const v8::AccessorInfo &info)
1377 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1379 V8THROW_ERROR("Not a valid VisualData object");
1382 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1383 if (cacheItem->groups & (1 << i))
1384 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1387 return cacheItem->engine->fromVariant(groups);
1390 void QQuickVisualDataModelItemMetaType::set_groups(
1391 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1393 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1395 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1397 if (!cacheItem->metaType->model)
1399 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1401 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1402 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1403 if (cacheItem->groups & (1 << i)) {
1404 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1405 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1411 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1412 v8::Local<v8::String>, const v8::AccessorInfo &info)
1414 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1416 V8THROW_ERROR("Not a valid VisualData object");
1418 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1421 void QQuickVisualDataModelItemMetaType::set_member(
1422 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1424 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1426 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1428 if (!cacheItem->metaType->model)
1430 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1432 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1433 const bool member = value->BooleanValue();
1434 const int groupFlag = (1 << group);
1435 if (member == ((cacheItem->groups & groupFlag) != 0))
1438 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1439 if (cacheItem->groups & (1 << i)) {
1440 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1442 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1444 model->removeGroups(it, 1, Compositor::Group(i), groupFlag);
1450 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1451 v8::Local<v8::String>, const v8::AccessorInfo &info)
1453 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1455 V8THROW_ERROR("Not a valid VisualData object");
1457 return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
1461 //---------------------------------------------------------------------------
1463 QQuickVisualDataModelItem::QQuickVisualDataModelItem(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int modelIndex)
1464 : QV8ObjectResource(metaType->v8Engine)
1465 , metaType(metaType)
1474 index[0] = modelIndex;
1478 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1480 Q_ASSERT(scriptRef == 0);
1481 Q_ASSERT(objectRef == 0);
1483 Q_ASSERT(indexHandle.IsEmpty());
1484 Q_ASSERT(modelHandle.IsEmpty());
1486 if (incubationTask && metaType->model)
1487 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1489 metaType->release();
1493 void QQuickVisualDataModelItem::Dispose()
1499 if (metaType->model) {
1500 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1501 const int cacheIndex = model->m_cache.indexOf(this);
1502 if (cacheIndex != -1) {
1503 model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1504 model->m_cache.removeAt(cacheIndex);
1505 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
1511 //---------------------------------------------------------------------------
1513 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1514 QQuickVisualDataModelAttached *attached, QQuickVisualDataModelItemMetaType *metaType)
1515 : attached(attached)
1516 , metaType(metaType)
1519 *static_cast<QMetaObject *>(this) = *metaType->metaObject;
1520 QObjectPrivate::get(attached)->metaObject = this;
1523 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1525 metaType->release();
1528 int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
1530 if (call == QMetaObject::ReadProperty) {
1531 if (_id >= metaType->indexPropertyOffset) {
1532 Compositor::Group group = Compositor::Group(_id - metaType->indexPropertyOffset + 1);
1533 *static_cast<int *>(arguments[0]) = attached->m_cacheItem->index[group];
1535 } else if (_id >= metaType->memberPropertyOffset) {
1536 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1537 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1540 } else if (call == QMetaObject::WriteProperty) {
1541 if (_id >= metaType->memberPropertyOffset) {
1542 if (!metaType->model)
1544 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1545 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1546 const int groupFlag = 1 << group;
1547 const bool member = attached->m_cacheItem->groups & groupFlag;
1548 if (member && !*static_cast<bool *>(arguments[0])) {
1549 Compositor::iterator it = model->m_compositor.find(
1550 group, attached->m_cacheItem->index[group]);
1551 model->removeGroups(it, 1, group, groupFlag);
1552 } else if (!member && *static_cast<bool *>(arguments[0])) {
1553 for (int i = 1; i < metaType->groupCount; ++i) {
1554 if (attached->m_cacheItem->groups & (1 << i)) {
1555 Compositor::iterator it = model->m_compositor.find(
1556 Compositor::Group(i), attached->m_cacheItem->index[i]);
1557 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1565 return attached->qt_metacall(call, _id, arguments);
1568 void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelItem *item)
1571 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1572 m_previousIndex[i] = m_cacheItem->index[i];
1576 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1578 This attached property holds the visual data model this delegate instance belongs to.
1580 It is attached to each instance of the delegate.
1583 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1585 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1589 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1591 This attached property holds the name of VisualDataGroups the item belongs to.
1593 It is attached to each instance of the delegate.
1596 QStringList QQuickVisualDataModelAttached::groups() const
1602 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1603 if (m_cacheItem->groups & (1 << i))
1604 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1609 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1614 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1616 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1617 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1618 if (m_cacheItem->groups & (1 << i)) {
1619 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), m_cacheItem->index[i]);
1620 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1626 bool QQuickVisualDataModelAttached::isUnresolved() const
1631 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1635 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1637 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1639 Changing this property will add or remove the item from the items group.
1641 It is attached to each instance of the delegate.
1645 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1647 This attached property holds the index of the item in the default \l items VisualDataGroup.
1649 It is attached to each instance of the delegate.
1653 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1655 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1657 Changing this property will add or remove the item from the items group. Change with caution
1658 as removing an item from the persistedItems group will destroy the current instance if it is
1659 not referenced by a model.
1661 It is attached to each instance of the delegate.
1665 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
1667 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
1669 It is attached to each instance of the delegate.
1672 void QQuickVisualDataModelAttached::emitChanges()
1674 if (m_modelChanged) {
1675 m_modelChanged = false;
1676 emit modelChanged();
1679 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
1680 m_previousGroups = m_cacheItem->groups;
1682 int indexChanges = 0;
1683 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1684 if (m_previousIndex[i] != m_cacheItem->index[i]) {
1685 m_previousIndex[i] = m_cacheItem->index[i];
1686 indexChanges |= (1 << i);
1691 const QMetaObject *meta = metaObject();
1692 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1693 if (groupChanges & (1 << i))
1694 QMetaObject::activate(this, meta, notifierId, 0);
1696 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1697 if (indexChanges & (1 << i))
1698 QMetaObject::activate(this, meta, notifierId, 0);
1702 emit groupsChanged();
1705 //============================================================================
1707 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
1714 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
1716 Q_Q(QQuickVisualDataGroup);
1717 static int idx = signalIndex("changed(QQmlV8Handle,QQmlV8Handle)");
1718 if (isSignalConnected(idx) && !changeSet.isEmpty()) {
1719 v8::HandleScope handleScope;
1720 v8::Context::Scope contextScope(engine->context());
1721 v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes());
1722 v8::Local<v8::Array> inserted = QQuickVisualDataModelPrivate::buildChangeList(changeSet.inserts());
1724 QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
1726 if (changeSet.difference() != 0)
1727 emit q->countChanged();
1730 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
1732 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1733 it->emitModelUpdated(changeSet, reset);
1737 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
1739 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1740 it->createdPackage(index, package);
1743 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
1745 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1746 it->initPackage(index, package);
1749 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
1751 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1752 it->destroyingPackage(package);
1756 \qmlclass VisualDataGroup QQuickVisualDataGroup
1757 \inqmlmodule QtQuick 2
1758 \ingroup qml-working-with-data
1759 \brief The VisualDataGroup encapsulates a filtered set of visual data items.
1763 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
1764 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1768 QQuickVisualDataGroup::QQuickVisualDataGroup(
1769 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
1770 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1772 Q_D(QQuickVisualDataGroup);
1774 d->setModel(model, Compositor::Group(index));
1777 QQuickVisualDataGroup::~QQuickVisualDataGroup()
1782 \qmlproperty string QtQuick2::VisualDataGroup::name
1784 This property holds the name of the group.
1786 Each group in a model must have a unique name starting with a lower case letter.
1789 QString QQuickVisualDataGroup::name() const
1791 Q_D(const QQuickVisualDataGroup);
1795 void QQuickVisualDataGroup::setName(const QString &name)
1797 Q_D(QQuickVisualDataGroup);
1800 if (d->name != name) {
1807 \qmlproperty int QtQuick2::VisualDataGroup::count
1809 This property holds the number of items in the group.
1812 int QQuickVisualDataGroup::count() const
1814 Q_D(const QQuickVisualDataGroup);
1817 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
1821 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
1823 This property holds whether new items are assigned to this group by default.
1826 bool QQuickVisualDataGroup::defaultInclude() const
1828 Q_D(const QQuickVisualDataGroup);
1829 return d->defaultInclude;
1832 void QQuickVisualDataGroup::setDefaultInclude(bool include)
1834 Q_D(QQuickVisualDataGroup);
1835 if (d->defaultInclude != include) {
1836 d->defaultInclude = include;
1840 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
1842 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
1844 emit defaultIncludeChanged();
1849 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
1851 Returns a javascript object describing the item at \a index in the group.
1853 The returned object contains the same information that is available to a delegate from the
1854 VisualDataModel attached as well as the model for that item. It has the properties:
1857 \o \b model The model data of the item. This is the same as the model context property in
1859 \o \b groups A list the of names of groups the item is a member of. This property can be
1860 written to change the item's membership.
1861 \o \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
1862 Writing to this property will add or remove the item from the group.
1863 \o \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
1864 \o \b {in\i{GroupName}} Whether the item belongs to the dynamic group \i groupName. Writing to
1865 this property will add or remove the item from the group.
1866 \o \b {\i{groupName}Index} The index of the item within the dynamic group \i groupName.
1870 QQmlV8Handle QQuickVisualDataGroup::get(int index)
1872 Q_D(QQuickVisualDataGroup);
1874 return QQmlV8Handle::fromHandle(v8::Undefined());;
1876 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
1877 if (index < 0 || index >= model->m_compositor.count(d->group)) {
1878 qmlInfo(this) << tr("get: index out of range");
1879 return QQmlV8Handle::fromHandle(v8::Undefined());
1882 Compositor::iterator it = model->m_compositor.find(d->group, index);
1883 QQuickVisualDataModelItem *cacheItem = it->inCache()
1884 ? model->m_cache.at(it.cacheIndex)
1888 cacheItem = model->m_adaptorModel->createItem(model->m_cacheMetaType, it.modelIndex());
1889 for (int i = 1; i < model->m_groupCount; ++i)
1890 cacheItem->index[i] = it.index[i];
1891 cacheItem->groups = it->flags;
1893 model->m_cache.insert(it.cacheIndex, cacheItem);
1894 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
1897 if (cacheItem->indexHandle.IsEmpty()) {
1898 cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
1899 cacheItem->indexHandle->SetExternalResource(cacheItem);
1900 cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
1902 ++cacheItem->scriptRef;
1905 return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
1908 bool QQuickVisualDataGroupPrivate::parseIndex(
1909 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
1911 if (value->IsInt32()) {
1912 *index = value->Int32Value();
1914 } else if (value->IsObject()) {
1915 v8::Local<v8::Object> object = value->ToObject();
1916 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
1917 for (int i = 1; cacheItem && i < cacheItem->metaType->groupCount; ++i) {
1918 if (cacheItem->groups & (1 << i)) {
1919 *group = Compositor::Group(i);
1920 *index = cacheItem->index[i];
1928 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
1930 Q_D(QQuickVisualDataGroup);
1931 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
1933 int index = model->m_compositor.count(d->group);
1934 Compositor::Group group = d->group;
1936 if (args->Length() == 0)
1940 v8::Local<v8::Value> v = (*args)[i];
1941 if (d->parseIndex(v, &index, &group)) {
1942 if (index < 0 || index > model->m_compositor.count(group)) {
1943 qmlInfo(this) << tr("insert: index out of range");
1946 if (++i == args->Length())
1951 Compositor::insert_iterator before = index < model->m_compositor.count(group)
1952 ? model->m_compositor.findInsertPosition(group, index)
1953 : model->m_compositor.end();
1955 int groups = 1 << d->group;
1956 if (++i < args->Length())
1957 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
1961 } else if (v->IsObject()) {
1962 model->insert(before, v->ToObject(), groups);
1963 model->emitChanges();
1968 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
1969 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
1970 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
1972 Returns a reference to the instantiated item at \a index in the group.
1974 All items returned by create are added to the persistedItems group. Items in this
1975 group remain instantiated when not referenced by any view.
1978 void QQuickVisualDataGroup::create(QQmlV8Function *args)
1980 Q_D(QQuickVisualDataGroup);
1984 if (args->Length() == 0)
1987 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
1989 int index = model->m_compositor.count(d->group);
1990 Compositor::Group group = d->group;
1993 v8::Local<v8::Value> v = (*args)[i];
1994 if (d->parseIndex(v, &index, &group))
1997 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
1999 if (v->IsObject()) {
2000 int groups = 1 << d->group;
2001 if (++i < args->Length())
2002 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2004 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2005 ? model->m_compositor.findInsertPosition(group, index)
2006 : model->m_compositor.end();
2008 index = before.index[d->group];
2011 if (!model->insert(before, v->ToObject(), groups)) {
2016 if (index < 0 || index >= model->m_compositor.count(group)) {
2017 qmlInfo(this) << tr("create: index out of range");
2021 QObject *object = model->object(group, index, false, false);
2023 QVector<Compositor::Insert> inserts;
2024 Compositor::iterator it = model->m_compositor.find(group, index);
2025 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2026 model->itemsInserted(inserts);
2029 args->returnValue(args->engine()->newQObject(object));
2030 model->emitChanges();
2033 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2035 Q_D(QQuickVisualDataGroup);
2039 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2041 if (args->Length() < 2)
2046 Compositor::Group fromGroup = d->group;
2047 Compositor::Group toGroup = d->group;
2049 v8::Local<v8::Value> v = (*args)[0];
2050 if (d->parseIndex(v, &from, &fromGroup)) {
2051 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2052 qmlInfo(this) << tr("resolve: from index out of range");
2056 qmlInfo(this) << tr("resolve: from index invalid");
2061 if (d->parseIndex(v, &to, &toGroup)) {
2062 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2063 qmlInfo(this) << tr("resolve: to index out of range");
2067 qmlInfo(this) << tr("resolve: to index invalid");
2071 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2072 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2074 if (!fromIt->isUnresolved()) {
2075 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2079 qmlInfo(this) << tr("resolve: to is not a model item");
2083 const int unresolvedFlags = fromIt->flags;
2084 const int resolvedFlags = toIt->flags;
2085 const int resolvedIndex = toIt.modelIndex();
2086 void * const resolvedList = toIt->list;
2088 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2089 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2091 if (toIt.cacheIndex > fromIt.cacheIndex)
2092 toIt.decrementIndexes(1, unresolvedFlags);
2093 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2097 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2098 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2099 model->itemsInserted(
2100 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2101 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2102 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2104 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2105 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2107 if (resolvedFlags & Compositor::CacheFlag)
2108 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2110 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2112 if (!cacheItem->isReferenced()) {
2113 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2114 model->m_cache.removeAt(toIt.cacheIndex);
2115 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2117 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2119 cacheItem->resolveIndex(resolvedIndex);
2120 if (cacheItem->object)
2121 cacheItem->attached->emitUnresolvedChanged();
2124 model->emitChanges();
2128 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2130 Removes \a count items starting at \a index from the group.
2133 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2135 Q_D(QQuickVisualDataGroup);
2138 Compositor::Group group = d->group;
2142 if (args->Length() == 0)
2146 v8::Local<v8::Value> v = (*args)[i];
2147 if (!d->parseIndex(v, &index, &group)) {
2148 qmlInfo(this) << tr("remove: invalid index");
2152 if (++i < args->Length()) {
2155 count = v->Int32Value();
2158 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2159 if (index < 0 || index >= model->m_compositor.count(group)) {
2160 qmlInfo(this) << tr("remove: index out of range");
2161 } else if (count != 0) {
2162 Compositor::iterator it = model->m_compositor.find(group, index);
2163 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2164 qmlInfo(this) << tr("remove: invalid count");
2166 model->removeGroups(it, count, d->group, 1 << d->group);
2171 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2172 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2174 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2177 if (args->Length() < 2)
2181 v8::Local<v8::Value> v = (*args)[i];
2182 if (!parseIndex(v, index, group))
2187 *count = v->Int32Value();
2189 if (++i == args->Length())
2194 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2200 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2202 Adds \a count items starting at \a index to \a groups.
2205 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2207 Q_D(QQuickVisualDataGroup);
2208 Compositor::Group group = d->group;
2213 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2216 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2217 if (index < 0 || index >= model->m_compositor.count(group)) {
2218 qmlInfo(this) << tr("addGroups: index out of range");
2219 } else if (count != 0) {
2220 Compositor::iterator it = model->m_compositor.find(group, index);
2221 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2222 qmlInfo(this) << tr("addGroups: invalid count");
2224 model->addGroups(it, count, d->group, groups);
2230 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2232 Removes \a count items starting at \a index from \a groups.
2235 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2237 Q_D(QQuickVisualDataGroup);
2238 Compositor::Group group = d->group;
2243 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2246 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2247 if (index < 0 || index >= model->m_compositor.count(group)) {
2248 qmlInfo(this) << tr("removeGroups: index out of range");
2249 } else if (count != 0) {
2250 Compositor::iterator it = model->m_compositor.find(group, index);
2251 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2252 qmlInfo(this) << tr("removeGroups: invalid count");
2254 model->removeGroups(it, count, d->group, groups);
2260 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2262 Sets the \a groups \a count items starting at \a index belong to.
2265 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2267 Q_D(QQuickVisualDataGroup);
2268 Compositor::Group group = d->group;
2273 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2276 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2277 if (index < 0 || index >= model->m_compositor.count(group)) {
2278 qmlInfo(this) << tr("setGroups: index out of range");
2279 } else if (count != 0) {
2280 Compositor::iterator it = model->m_compositor.find(group, index);
2281 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2282 qmlInfo(this) << tr("setGroups: invalid count");
2284 model->setGroups(it, count, d->group, groups);
2290 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2292 Sets the \a groups \a count items starting at \a index belong to.
2296 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2298 Moves \a count at \a from in a group \a to a new position.
2301 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2303 Q_D(QQuickVisualDataGroup);
2305 if (args->Length() < 2)
2308 Compositor::Group fromGroup = d->group;
2309 Compositor::Group toGroup = d->group;
2314 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2315 qmlInfo(this) << tr("move: invalid from index");
2319 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2320 qmlInfo(this) << tr("move: invalid to index");
2324 if (args->Length() > 2) {
2325 v8::Local<v8::Value> v = (*args)[2];
2327 count = v->Int32Value();
2330 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2333 qmlInfo(this) << tr("move: invalid count");
2334 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2335 qmlInfo(this) << tr("move: from index out of range");
2336 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2337 qmlInfo(this) << tr("move: to index out of range");
2338 } else if (count > 0) {
2339 QVector<Compositor::Remove> removes;
2340 QVector<Compositor::Insert> inserts;
2342 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2343 model->itemsMoved(removes, inserts);
2344 model->emitChanges();
2350 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2352 This handler is called when items have been removed from or inserted into the group.
2354 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2355 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2357 Each index is adjusted for previous changes with all removed items preceding any inserted
2361 //============================================================================
2363 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2364 : QQuickVisualModel(*new QObjectPrivate, parent)
2367 , m_compositorGroup(Compositor::Cache)
2368 , m_inheritGroup(true)
2370 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2371 if (d->m_cacheMetaType) {
2372 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2373 m_compositorGroup = Compositor::Default;
2375 d->m_pendingParts.insert(this);
2379 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2383 QString QQuickVisualPartsModel::filterGroup() const
2386 return m_model->filterGroup();
2387 return m_filterGroup;
2390 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2392 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2393 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2397 if (m_filterGroup != group || m_inheritGroup) {
2398 m_filterGroup = group;
2399 m_inheritGroup = false;
2400 updateFilterGroup();
2402 emit filterGroupChanged();
2406 void QQuickVisualPartsModel::resetFilterGroup()
2408 if (!m_inheritGroup) {
2409 m_inheritGroup = true;
2410 updateFilterGroup();
2411 emit filterGroupChanged();
2415 void QQuickVisualPartsModel::updateFilterGroup()
2417 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2418 if (!model->m_cacheMetaType)
2421 if (m_inheritGroup) {
2422 if (m_filterGroup == model->m_filterGroup)
2424 m_filterGroup = model->m_filterGroup;
2427 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2428 m_compositorGroup = Compositor::Default;
2429 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2430 for (int i = 1; i < model->m_groupCount; ++i) {
2431 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2432 m_compositorGroup = Compositor::Group(i);
2437 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2438 if (m_compositorGroup != previousGroup) {
2439 QVector<QQuickChangeSet::Remove> removes;
2440 QVector<QQuickChangeSet::Insert> inserts;
2441 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2443 QQuickChangeSet changeSet;
2444 changeSet.apply(removes, inserts);
2445 if (!changeSet.isEmpty())
2446 emit modelUpdated(changeSet, false);
2448 if (changeSet.difference() != 0)
2449 emit countChanged();
2453 void QQuickVisualPartsModel::updateFilterGroup(
2454 Compositor::Group group, const QQuickChangeSet &changeSet)
2456 if (!m_inheritGroup)
2459 m_compositorGroup = group;
2460 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2462 if (!changeSet.isEmpty())
2463 emit modelUpdated(changeSet, false);
2465 if (changeSet.difference() != 0)
2466 emit countChanged();
2468 emit filterGroupChanged();
2471 int QQuickVisualPartsModel::count() const
2473 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2474 return model->m_delegate
2475 ? model->m_compositor.count(m_compositorGroup)
2479 bool QQuickVisualPartsModel::isValid() const
2481 return m_model->isValid();
2484 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2486 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2488 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2489 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2493 QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
2495 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(object)) {
2496 QObject *part = package->part(m_part);
2499 if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
2500 m_packaged.insertMulti(item, package);
2505 model->release(object);
2506 if (!model->m_delegateValidated) {
2508 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2509 model->m_delegateValidated = true;
2515 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2517 QQuickVisualModel::ReleaseFlags flags = 0;
2519 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2520 if (it != m_packaged.end()) {
2521 QQuickPackage *package = *it;
2522 QQml_setParent_noEvent(item, package);
2523 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2524 flags = model->release(package);
2525 m_packaged.erase(it);
2526 if (!m_packaged.contains(item))
2527 flags &= ~Referenced;
2528 if (flags & Destroyed)
2529 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2534 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2536 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2539 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2541 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2542 model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles);
2543 m_watchedRoles = roles;
2546 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2548 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2549 if (it != m_packaged.end()) {
2550 if (QQuickVisualDataModelAttached *attached = QQuickVisualDataModelAttached::properties(*it))
2551 return attached->m_cacheItem->index[m_compositorGroup];
2556 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2558 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2559 emit createdItem(index, item);
2562 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2564 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2565 emit initItem(index, item);
2568 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2570 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
2571 Q_ASSERT(!m_packaged.contains(item));
2572 emit destroyingItem(item);
2573 item->setParentItem(0);
2574 QQml_setParent_noEvent(item, package);
2578 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2580 emit modelUpdated(changeSet, reset);
2581 if (changeSet.difference() != 0)
2582 emit countChanged();