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 // Cancel a requested async item
454 void QQuickVisualDataModel::cancel(int index)
456 Q_D(QQuickVisualDataModel);
457 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
458 qWarning() << "VisualDataModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
462 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
463 QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0;
465 if (cacheItem->incubationTask) {
466 delete cacheItem->incubationTask->incubatingContext;
467 cacheItem->incubationTask->incubatingContext = 0;
468 d->releaseIncubator(cacheItem->incubationTask);
469 cacheItem->incubationTask = 0;
471 if (cacheItem->object && !cacheItem->isObjectReferenced()) {
472 d->destroy(cacheItem->object);
473 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
474 d->emitDestroyingPackage(package);
475 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
476 d->emitDestroyingItem(item);
477 cacheItem->object = 0;
479 if (!cacheItem->isReferenced()) {
480 d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag);
481 d->m_cache.removeAt(it.cacheIndex);
483 Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache));
488 void QQuickVisualDataModelPrivate::group_append(
489 QQmlListProperty<QQuickVisualDataGroup> *property, QQuickVisualDataGroup *group)
491 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
494 if (d->m_groupCount == Compositor::MaximumGroupCount) {
495 qmlInfo(d->q_func()) << QQuickVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
498 d->m_groups[d->m_groupCount] = group;
499 d->m_groupCount += 1;
502 int QQuickVisualDataModelPrivate::group_count(
503 QQmlListProperty<QQuickVisualDataGroup> *property)
505 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
506 return d->m_groupCount - 1;
509 QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at(
510 QQmlListProperty<QQuickVisualDataGroup> *property, int index)
512 QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data);
513 return index >= 0 && index < d->m_groupCount - 1
514 ? d->m_groups[index + 1]
519 \qmlproperty list<VisualDataGroup> QtQuick2::VisualDataModel::groups
521 This property holds a visual data model's group definitions.
523 Groups define a sub-set of the items in a visual data model and can be used to filter
526 For every group defined in a VisualDataModel two attached properties are added to each
527 delegate item. The first of the form VisualDataModel.in\e{GroupName} holds whether the
528 item belongs to the group and the second VisualDataModel.\e{groupName}Index holds the
529 index of the item in that group.
531 The following example illustrates using groups to select items in a model.
533 \snippet doc/src/snippets/qml/visualdatagroup.qml 0
536 QQmlListProperty<QQuickVisualDataGroup> QQuickVisualDataModel::groups()
538 Q_D(QQuickVisualDataModel);
539 return QQmlListProperty<QQuickVisualDataGroup>(
542 QQuickVisualDataModelPrivate::group_append,
543 QQuickVisualDataModelPrivate::group_count,
544 QQuickVisualDataModelPrivate::group_at);
548 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::items
550 This property holds visual data model's default group to which all new items are added.
553 QQuickVisualDataGroup *QQuickVisualDataModel::items()
555 Q_D(QQuickVisualDataModel);
560 \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
562 This property holds visual data model's persisted items group.
564 Items in this group are not destroyed when released by a view, instead they are persisted
565 until removed from the group.
567 An item can be removed from the persistedItems group by setting the
568 VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
569 at that time it will be destroyed. Adding an item to this group will not create a new
572 Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
576 QQuickVisualDataGroup *QQuickVisualDataModel::persistedItems()
578 Q_D(QQuickVisualDataModel);
579 return d->m_persistedItems;
583 \qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
585 This property holds the name of the group used to filter the visual data model.
587 Only items which belong to this group are visible to a view.
589 By default this is the \l items group.
592 QString QQuickVisualDataModel::filterGroup() const
594 Q_D(const QQuickVisualDataModel);
595 return d->m_filterGroup;
598 void QQuickVisualDataModel::setFilterGroup(const QString &group)
600 Q_D(QQuickVisualDataModel);
602 if (d->m_transaction) {
603 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
607 if (d->m_filterGroup != group) {
608 d->m_filterGroup = group;
609 d->updateFilterGroup();
610 emit filterGroupChanged();
614 void QQuickVisualDataModel::resetFilterGroup()
616 setFilterGroup(QStringLiteral("items"));
619 void QQuickVisualDataModelPrivate::updateFilterGroup()
621 Q_Q(QQuickVisualDataModel);
622 if (!m_cacheMetaType)
625 QQuickListCompositor::Group previousGroup = m_compositorGroup;
626 m_compositorGroup = Compositor::Default;
627 for (int i = 1; i < m_groupCount; ++i) {
628 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
629 m_compositorGroup = Compositor::Group(i);
634 QQuickVisualDataGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this);
635 if (m_compositorGroup != previousGroup) {
636 QVector<QQuickChangeSet::Remove> removes;
637 QVector<QQuickChangeSet::Insert> inserts;
638 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
640 QQuickChangeSet changeSet;
641 changeSet.apply(removes, inserts);
642 emit q->modelUpdated(changeSet, false);
644 if (changeSet.difference() != 0)
645 emit q->countChanged();
648 foreach (QQuickVisualPartsModel *model, m_parts->models)
649 model->updateFilterGroup(m_compositorGroup, changeSet);
655 \qmlproperty object QtQuick2::VisualDataModel::parts
657 The \a parts property selects a VisualDataModel which creates
658 delegates from the part named. This is used in conjunction with
659 the \l Package element.
661 For example, the code below selects a model which creates
662 delegates named \e list from a \l Package:
668 Item { Package.name: "list" }
674 width: 200; height:200
675 model: visualModel.parts.list
682 QObject *QQuickVisualDataModel::parts()
684 Q_D(QQuickVisualDataModel);
686 d->m_parts = new QQuickVisualDataModelParts(this);
690 void QQuickVisualDataModelPrivate::emitCreatedPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
692 for (int i = 1; i < m_groupCount; ++i)
693 QQuickVisualDataGroupPrivate::get(m_groups[i])->createdPackage(cacheItem->index[i], package);
696 void QQuickVisualDataModelPrivate::emitInitPackage(QQuickVisualDataModelItem *cacheItem, QQuickPackage *package)
698 for (int i = 1; i < m_groupCount; ++i)
699 QQuickVisualDataGroupPrivate::get(m_groups[i])->initPackage(cacheItem->index[i], package);
702 void QQuickVisualDataModelPrivate::emitDestroyingPackage(QQuickPackage *package)
704 for (int i = 1; i < m_groupCount; ++i)
705 QQuickVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
708 void QVDMIncubationTask::statusChanged(Status status)
710 vdm->incubatorStatusChanged(this, status);
713 void QQuickVisualDataModelPrivate::releaseIncubator(QVDMIncubationTask *incubationTask)
715 Q_Q(QQuickVisualDataModel);
716 if (!incubationTask->isError())
717 incubationTask->clear();
718 m_finishedIncubating.append(incubationTask);
719 if (!m_incubatorCleanupScheduled) {
720 m_incubatorCleanupScheduled = true;
721 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
725 void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *incubationTask, QQmlIncubator::Status status)
727 Q_Q(QQuickVisualDataModel);
728 if (status != QQmlIncubator::Ready && status != QQmlIncubator::Error)
731 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
732 cacheItem->incubationTask = 0;
734 if (status == QQmlIncubator::Ready) {
735 incubationTask->incubating = 0;
736 releaseIncubator(incubationTask);
737 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
738 emitCreatedPackage(cacheItem, package);
739 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
740 emitCreatedItem(cacheItem, item);
741 } else if (status == QQmlIncubator::Error) {
742 delete incubationTask->incubatingContext;
743 incubationTask->incubatingContext = 0;
744 if (!cacheItem->isReferenced()) {
745 int cidx = m_cache.indexOf(cacheItem);
747 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
748 m_cache.removeAt(cidx);
751 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
753 releaseIncubator(incubationTask);
754 qmlInfo(q, m_delegate->errors()) << "Error creating delegate";
758 void QVDMIncubationTask::setInitialState(QObject *o)
760 vdm->setInitialState(this, o);
763 void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubationTask, QObject *o)
765 QQuickVisualDataModelItem *cacheItem = incubationTask->incubating;
766 cacheItem->object = o;
767 QQml_setParent_noEvent(incubationTask->incubatingContext, cacheItem->object);
768 incubationTask->incubatingContext = 0;
770 cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object);
771 cacheItem->attached->setCacheItem(cacheItem);
772 new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
773 cacheItem->attached->emitChanges();
775 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
776 emitInitPackage(cacheItem, package);
777 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
778 emitInitItem(cacheItem, item);
781 QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index, bool asynchronous, bool reference)
783 Q_Q(QQuickVisualDataModel);
784 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
785 qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
789 Compositor::iterator it = m_compositor.find(group, index);
791 QQuickVisualDataModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
794 cacheItem = m_adaptorModel->createItem(m_cacheMetaType, it.modelIndex());
795 for (int i = 1; i < m_groupCount; ++i)
796 cacheItem->index[i] = it.index[i];
798 cacheItem->groups = it->flags;
800 m_cache.insert(it.cacheIndex, cacheItem);
801 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
802 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
805 if (cacheItem->incubationTask) {
806 if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
807 // previously requested async - now needed immediately
808 cacheItem->incubationTask->forceCompletion();
810 } else if (!cacheItem->object) {
811 QVDMIncubationTask *incubator = new QVDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested);
812 cacheItem->incubationTask = incubator;
814 QQmlContext *creationContext = m_delegate->creationContext();
815 QQmlContext *rootContext = new QQuickVisualDataModelContext(
816 cacheItem, creationContext ? creationContext : m_context.data());
817 QQmlContext *ctxt = rootContext;
818 if (m_adaptorModel->flags() & QQuickVisualAdaptorModel::ProxiedObject) {
819 if (QQuickVisualAdaptorModelProxyInterface *proxy = qobject_cast<QQuickVisualAdaptorModelProxyInterface *>(cacheItem)) {
820 ctxt->setContextObject(proxy->proxiedObject());
821 ctxt = new QQuickVisualDataModelContext(cacheItem, ctxt, ctxt);
825 ctxt->setContextObject(cacheItem);
827 incubator->incubating = cacheItem;
828 incubator->incubatingContext = rootContext;
829 m_delegate->create(*incubator, ctxt, m_context);
832 if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
833 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
834 if (cacheItem->object && reference)
835 cacheItem->referenceObject();
836 return cacheItem->object;
840 If asynchronous is true or the component is being loaded asynchronously due
841 to an ancestor being loaded asynchronously, item() may return 0. In this
842 case itemCreated() will be emitted when the item is available. The item
843 at this stage does not have any references, so item() must be called again
844 to ensure a reference is held. Any call to item() which returns a valid item
845 must be matched by a call to release() in order to destroy the item.
847 QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous)
849 Q_D(QQuickVisualDataModel);
850 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
851 qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
855 QObject *object = d->object(d->m_compositorGroup, index, asynchronous, true);
859 if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
863 if (!d->m_delegateValidated) {
865 qmlInfo(d->m_delegate) << QQuickVisualDataModel::tr("Delegate component must be Item type.");
866 d->m_delegateValidated = true;
871 QString QQuickVisualDataModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
873 Compositor::iterator it = m_compositor.find(group, index);
874 if (QQuickVisualAdaptorModel *model = it.list<QQuickVisualAdaptorModel>()) {
875 return model->stringValue(it.modelIndex(), name);
880 QString QQuickVisualDataModel::stringValue(int index, const QString &name)
882 Q_D(QQuickVisualDataModel);
883 return d->stringValue(d->m_compositorGroup, index, name);
886 int QQuickVisualDataModel::indexOf(QQuickItem *item, QObject *) const
888 Q_D(const QQuickVisualDataModel);
889 if (QQuickVisualDataModelAttached *attached = QQuickVisualDataModelAttached::properties(item))
890 return attached->m_cacheItem->index[d->m_compositorGroup];
894 void QQuickVisualDataModel::setWatchedRoles(QList<QByteArray> roles)
896 Q_D(QQuickVisualDataModel);
897 d->m_adaptorModel->replaceWatchedRoles(d->watchedRoles, roles);
898 d->watchedRoles = roles;
901 void QQuickVisualDataModelPrivate::addGroups(
902 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
904 QVector<Compositor::Insert> inserts;
905 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
906 itemsInserted(inserts);
910 void QQuickVisualDataModelPrivate::removeGroups(
911 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
913 QVector<Compositor::Remove> removes;
914 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
915 itemsRemoved(removes);
919 void QQuickVisualDataModelPrivate::setGroups(
920 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
922 QVector<Compositor::Remove> removes;
923 QVector<Compositor::Insert> inserts;
925 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
926 itemsInserted(inserts);
927 const int removeFlags = ~groupFlags & Compositor::GroupMask;
929 from = m_compositor.find(from.group, from.index[from.group]);
930 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
931 itemsRemoved(removes);
935 bool QQuickVisualDataModel::event(QEvent *e)
937 Q_D(QQuickVisualDataModel);
938 if (e->type() == QEvent::UpdateRequest) {
939 d->m_adaptorModel->fetchMore();
940 } else if (e->type() == QEvent::User) {
941 d->m_incubatorCleanupScheduled = false;
942 qDeleteAll(d->m_finishedIncubating);
943 d->m_finishedIncubating.clear();
945 return QQuickVisualModel::event(e);
948 void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
953 QVarLengthArray<QVector<QQuickChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
955 foreach (const Compositor::Change &change, changes) {
956 for (int i = 1; i < m_groupCount; ++i) {
957 if (change.inGroup(i)) {
958 translatedChanges[i].append(
959 QQuickChangeSet::Change(change.index[i], change.count));
964 for (int i = 1; i < m_groupCount; ++i)
965 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
968 void QQuickVisualDataModel::_q_itemsChanged(int index, int count)
970 Q_D(QQuickVisualDataModel);
973 QVector<Compositor::Change> changes;
974 d->m_compositor.listItemsChanged(d->m_adaptorModel, index, count, &changes);
975 d->itemsChanged(changes);
979 void QQuickVisualDataModelPrivate::itemsInserted(
980 const QVector<Compositor::Insert> &inserts,
981 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts,
982 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
986 int inserted[Compositor::MaximumGroupCount];
987 for (int i = 1; i < m_groupCount; ++i)
990 foreach (const Compositor::Insert &insert, inserts) {
991 for (; cacheIndex < insert.cacheIndex; ++cacheIndex) {
992 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
993 for (int i = 1; i < m_groupCount; ++i)
994 cacheItem->index[i] += inserted[i];
996 for (int i = 1; i < m_groupCount; ++i) {
997 if (insert.inGroup(i)) {
998 (*translatedInserts)[i].append(
999 QQuickChangeSet::Insert(insert.index[i], insert.count, insert.moveId));
1000 inserted[i] += insert.count;
1004 if (!insert.inCache())
1007 if (movedItems && insert.isMove()) {
1008 QList<QQuickVisualDataModelItem *> items = movedItems->take(insert.moveId);
1009 Q_ASSERT(items.count() == insert.count);
1010 m_cache = m_cache.mid(0, insert.cacheIndex) + items + m_cache.mid(insert.cacheIndex);
1012 if (insert.inGroup()) {
1013 for (int offset = 0; cacheIndex < insert.cacheIndex + insert.count; ++cacheIndex, ++offset) {
1014 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1015 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1016 for (int i = 1; i < m_groupCount; ++i) {
1017 cacheItem->index[i] = cacheItem->groups & (1 << i)
1018 ? insert.index[i] + offset
1023 cacheIndex = insert.cacheIndex + insert.count;
1026 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1027 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1028 for (int i = 1; i < m_groupCount; ++i)
1029 cacheItem->index[i] += inserted[i];
1033 void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1035 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1036 itemsInserted(inserts, &translatedInserts);
1037 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1041 for (int i = 1; i < m_groupCount; ++i)
1042 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
1045 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
1048 Q_D(QQuickVisualDataModel);
1051 QVector<Compositor::Insert> inserts;
1052 d->m_compositor.listItemsInserted(d->m_adaptorModel, index, count, &inserts);
1053 d->itemsInserted(inserts);
1057 void QQuickVisualDataModelPrivate::itemsRemoved(
1058 const QVector<Compositor::Remove> &removes,
1059 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves,
1060 QHash<int, QList<QQuickVisualDataModelItem *> > *movedItems)
1063 int removedCache = 0;
1065 int removed[Compositor::MaximumGroupCount];
1066 for (int i = 1; i < m_groupCount; ++i)
1069 foreach (const Compositor::Remove &remove, removes) {
1070 for (; cacheIndex < remove.cacheIndex; ++cacheIndex) {
1071 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1072 for (int i = 1; i < m_groupCount; ++i)
1073 cacheItem->index[i] -= removed[i];
1075 for (int i = 1; i < m_groupCount; ++i) {
1076 if (remove.inGroup(i)) {
1077 (*translatedRemoves)[i].append(
1078 QQuickChangeSet::Remove(remove.index[i], remove.count, remove.moveId));
1079 removed[i] += remove.count;
1083 if (!remove.inCache())
1086 if (movedItems && remove.isMove()) {
1087 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex, remove.count));
1088 QList<QQuickVisualDataModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex;
1089 QList<QQuickVisualDataModelItem *>::iterator end = begin + remove.count;
1090 m_cache.erase(begin, end);
1092 for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
1093 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1094 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1095 destroy(cacheItem->object);
1096 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(cacheItem->object))
1097 emitDestroyingPackage(package);
1098 else if (QQuickItem *item = qobject_cast<QQuickItem *>(cacheItem->object))
1099 emitDestroyingItem(item);
1100 cacheItem->object = 0;
1102 if (!cacheItem->isReferenced()) {
1103 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1104 m_cache.removeAt(cacheIndex);
1108 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1109 } else if (remove.groups() == cacheItem->groups) {
1110 cacheItem->groups = 0;
1111 for (int i = 1; i < m_groupCount; ++i)
1112 cacheItem->index[i] = -1;
1114 for (int i = 1; i < m_groupCount; ++i) {
1115 if (remove.inGroup(i))
1116 cacheItem->index[i] = remove.index[i];
1118 cacheItem->groups &= ~remove.flags;
1124 for (; cacheIndex < m_cache.count(); ++cacheIndex) {
1125 QQuickVisualDataModelItem *cacheItem = m_cache.at(cacheIndex);
1126 for (int i = 1; i < m_groupCount; ++i)
1127 cacheItem->index[i] -= removed[i];
1131 void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1133 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1134 itemsRemoved(removes, &translatedRemoves);
1135 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1139 for (int i = 1; i < m_groupCount; ++i)
1140 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
1143 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
1145 Q_D(QQuickVisualDataModel);
1149 QVector<Compositor::Remove> removes;
1150 d->m_compositor.listItemsRemoved(d->m_adaptorModel, index, count, &removes);
1151 d->itemsRemoved(removes);
1156 void QQuickVisualDataModelPrivate::itemsMoved(
1157 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1159 QHash<int, QList<QQuickVisualDataModelItem *> > movedItems;
1161 QVarLengthArray<QVector<QQuickChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1162 itemsRemoved(removes, &translatedRemoves, &movedItems);
1164 QVarLengthArray<QVector<QQuickChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1165 itemsInserted(inserts, &translatedInserts, &movedItems);
1166 Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
1167 Q_ASSERT(movedItems.isEmpty());
1171 for (int i = 1; i < m_groupCount; ++i) {
1172 QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
1173 translatedRemoves.at(i),
1174 translatedInserts.at(i));
1178 void QQuickVisualDataModel::_q_itemsMoved(int from, int to, int count)
1180 Q_D(QQuickVisualDataModel);
1184 QVector<Compositor::Remove> removes;
1185 QVector<Compositor::Insert> inserts;
1186 d->m_compositor.listItemsMoved(d->m_adaptorModel, from, to, count, &removes, &inserts);
1187 d->itemsMoved(removes, inserts);
1191 template <typename T> v8::Local<v8::Array>
1192 QQuickVisualDataModelPrivate::buildChangeList(const QVector<T> &changes)
1194 v8::Local<v8::Array> indexes = v8::Array::New(changes.count());
1195 v8::Local<v8::String> indexKey = v8::String::New("index");
1196 v8::Local<v8::String> countKey = v8::String::New("count");
1197 v8::Local<v8::String> moveIdKey = v8::String::New("moveId");
1199 for (int i = 0; i < changes.count(); ++i) {
1200 v8::Local<v8::Object> object = v8::Object::New();
1201 object->Set(indexKey, v8::Integer::New(changes.at(i).index));
1202 object->Set(countKey, v8::Integer::New(changes.at(i).count));
1203 object->Set(moveIdKey, changes.at(i).moveId != -1 ? v8::Integer::New(changes.at(i).count) : v8::Undefined());
1204 indexes->Set(i, object);
1209 void QQuickVisualDataModelPrivate::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
1211 Q_Q(QQuickVisualDataModel);
1212 emit q->modelUpdated(changeSet, reset);
1213 if (changeSet.difference() != 0)
1214 emit q->countChanged();
1217 void QQuickVisualDataModelPrivate::emitChanges()
1219 if (m_transaction || !m_complete)
1222 m_transaction = true;
1223 QV8Engine *engine = QQmlEnginePrivate::getV8Engine(m_context->engine());
1224 for (int i = 1; i < m_groupCount; ++i)
1225 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitChanges(engine);
1226 m_transaction = false;
1228 const bool reset = m_reset;
1230 for (int i = 1; i < m_groupCount; ++i)
1231 QQuickVisualDataGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
1233 foreach (QQuickVisualDataModelItem *cacheItem, m_cache) {
1234 if (cacheItem->object && cacheItem->attached)
1235 cacheItem->attached->emitChanges();
1239 void QQuickVisualDataModel::_q_modelReset(int oldCount, int newCount)
1241 Q_D(QQuickVisualDataModel);
1245 QVector<Compositor::Remove> removes;
1246 QVector<Compositor::Insert> inserts;
1248 d->m_compositor.listItemsRemoved(d->m_adaptorModel, 0, oldCount, &removes);
1250 d->m_compositor.listItemsInserted(d->m_adaptorModel, 0, newCount, &inserts);
1251 d->itemsMoved(removes, inserts);
1256 QQuickVisualDataModelAttached *QQuickVisualDataModel::qmlAttachedProperties(QObject *obj)
1258 return QQuickVisualDataModelAttached::properties(obj);
1261 bool QQuickVisualDataModelPrivate::insert(
1262 Compositor::insert_iterator &before, const v8::Local<v8::Object> &object, int groups)
1264 QQuickVisualDataModelItem *cacheItem = m_adaptorModel->createItem(m_cacheMetaType, -1);
1268 for (int i = 1; i < m_groupCount; ++i)
1269 cacheItem->index[i] = before.index[i];
1271 v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
1272 for (uint i = 0; i < propertyNames->Length(); ++i) {
1273 v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString();
1274 cacheItem->setValue(
1275 m_cacheMetaType->v8Engine->toString(propertyName),
1276 m_cacheMetaType->v8Engine->toVariant(object->Get(propertyName), QVariant::Invalid));
1279 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
1281 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
1282 itemsInserted(QVector<Compositor::Insert>() << Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag));
1284 before = m_compositor.insert(before, 0, 0, 1, cacheItem->groups);
1285 m_cache.insert(before.cacheIndex, cacheItem);
1290 //============================================================================
1292 QQuickVisualDataModelItemMetaType::QQuickVisualDataModelItemMetaType(
1293 QV8Engine *engine, QQuickVisualDataModel *model, const QStringList &groupNames)
1295 , groupCount(groupNames.count() + 1)
1296 , memberPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount())
1297 , indexPropertyOffset(QQuickVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
1300 , groupNames(groupNames)
1302 QMetaObjectBuilder builder;
1303 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1304 builder.setClassName(QQuickVisualDataModelAttached::staticMetaObject.className());
1305 builder.setSuperClass(&QQuickVisualDataModelAttached::staticMetaObject);
1307 v8::HandleScope handleScope;
1308 v8::Context::Scope contextScope(engine->context());
1310 constructor = qPersistentNew(v8::ObjectTemplate::New());
1312 constructor->SetHasExternalResource(true);
1313 constructor->SetAccessor(v8::String::New("model"), get_model);
1314 constructor->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
1315 constructor->SetAccessor(v8::String::New("isUnresolved"), get_member, 0, v8::Int32::New(30));
1318 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1319 QString propertyName = QStringLiteral("in") + groupNames.at(i);
1320 propertyName.replace(2, 1, propertyName.at(2).toUpper());
1321 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1322 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1323 propertyName.toUtf8(), "bool", notifierId);
1324 propertyBuilder.setWritable(true);
1326 constructor->SetAccessor(
1327 engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
1329 for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
1330 const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
1331 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
1332 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
1333 propertyName.toUtf8(), "int", notifierId);
1334 propertyBuilder.setWritable(true);
1336 constructor->SetAccessor(
1337 engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
1340 metaObject = builder.toMetaObject();
1343 QQuickVisualDataModelItemMetaType::~QQuickVisualDataModelItemMetaType()
1346 qPersistentDispose(constructor);
1349 int QQuickVisualDataModelItemMetaType::parseGroups(const QStringList &groups) const
1352 foreach (const QString &groupName, groups) {
1353 int index = groupNames.indexOf(groupName);
1355 groupFlags |= 2 << index;
1360 int QQuickVisualDataModelItemMetaType::parseGroups(const v8::Local<v8::Value> &groups) const
1363 if (groups->IsString()) {
1364 const QString groupName = v8Engine->toString(groups);
1365 int index = groupNames.indexOf(groupName);
1367 groupFlags |= 2 << index;
1368 } else if (groups->IsArray()) {
1369 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(groups);
1370 for (uint i = 0; i < array->Length(); ++i) {
1371 const QString groupName = v8Engine->toString(array->Get(i));
1372 int index = groupNames.indexOf(groupName);
1374 groupFlags |= 2 << index;
1380 void QQuickVisualDataModelItemMetaType::release_index(v8::Persistent<v8::Value> object, void *data)
1382 static_cast<QQuickVisualDataModelItem *>(data)->indexHandle.Clear();
1383 qPersistentDispose(object);
1386 void QQuickVisualDataModelItemMetaType::release_model(v8::Persistent<v8::Value> object, void *data)
1388 static_cast<QQuickVisualDataModelItem *>(data)->modelHandle.Clear();
1389 qPersistentDispose(object);
1392 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_model(
1393 v8::Local<v8::String>, const v8::AccessorInfo &info)
1395 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1397 V8THROW_ERROR("Not a valid VisualData object");
1398 if (!cacheItem->metaType->model)
1399 return v8::Undefined();
1401 if (cacheItem->modelHandle.IsEmpty()) {
1402 cacheItem->modelHandle = qPersistentNew(cacheItem->get());
1403 cacheItem->modelHandle.MakeWeak(cacheItem, &release_model);
1405 ++cacheItem->scriptRef;
1408 return cacheItem->modelHandle;
1411 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_groups(
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");
1419 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1420 if (cacheItem->groups & (1 << i))
1421 groups.append(cacheItem->metaType->groupNames.at(i - 1));
1424 return cacheItem->engine->fromVariant(groups);
1427 void QQuickVisualDataModelItemMetaType::set_groups(
1428 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1430 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1432 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1434 if (!cacheItem->metaType->model)
1436 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1438 const int groupFlags = model->m_cacheMetaType->parseGroups(value);
1439 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1440 if (cacheItem->groups & (1 << i)) {
1441 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1442 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1448 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_member(
1449 v8::Local<v8::String>, const v8::AccessorInfo &info)
1451 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1453 V8THROW_ERROR("Not a valid VisualData object");
1455 return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
1458 void QQuickVisualDataModelItemMetaType::set_member(
1459 v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1461 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1463 V8THROW_ERROR_SETTER("Not a valid VisualData object");
1465 if (!cacheItem->metaType->model)
1467 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(cacheItem->metaType->model);
1469 Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
1470 const bool member = value->BooleanValue();
1471 const int groupFlag = (1 << group);
1472 if (member == ((cacheItem->groups & groupFlag) != 0))
1475 for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
1476 if (cacheItem->groups & (1 << i)) {
1477 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), cacheItem->index[i]);
1479 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1481 model->removeGroups(it, 1, Compositor::Group(i), groupFlag);
1487 v8::Handle<v8::Value> QQuickVisualDataModelItemMetaType::get_index(
1488 v8::Local<v8::String>, const v8::AccessorInfo &info)
1490 QQuickVisualDataModelItem *cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(info.This());
1492 V8THROW_ERROR("Not a valid VisualData object");
1494 return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
1498 //---------------------------------------------------------------------------
1500 QQuickVisualDataModelItem::QQuickVisualDataModelItem(QQuickVisualDataModelItemMetaType *metaType, QQuickVisualAdaptorModel *model, int modelIndex)
1501 : QV8ObjectResource(metaType->v8Engine)
1502 , metaType(metaType)
1511 index[0] = modelIndex;
1515 QQuickVisualDataModelItem::~QQuickVisualDataModelItem()
1517 Q_ASSERT(scriptRef == 0);
1518 Q_ASSERT(objectRef == 0);
1520 Q_ASSERT(indexHandle.IsEmpty());
1521 Q_ASSERT(modelHandle.IsEmpty());
1523 if (incubationTask && metaType->model)
1524 QQuickVisualDataModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
1526 metaType->release();
1530 void QQuickVisualDataModelItem::Dispose()
1536 if (metaType->model) {
1537 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1538 const int cacheIndex = model->m_cache.indexOf(this);
1539 if (cacheIndex != -1) {
1540 model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1541 model->m_cache.removeAt(cacheIndex);
1542 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
1548 //---------------------------------------------------------------------------
1550 QQuickVisualDataModelAttachedMetaObject::QQuickVisualDataModelAttachedMetaObject(
1551 QQuickVisualDataModelAttached *attached, QQuickVisualDataModelItemMetaType *metaType)
1552 : attached(attached)
1553 , metaType(metaType)
1556 *static_cast<QMetaObject *>(this) = *metaType->metaObject;
1557 QObjectPrivate::get(attached)->metaObject = this;
1560 QQuickVisualDataModelAttachedMetaObject::~QQuickVisualDataModelAttachedMetaObject()
1562 metaType->release();
1565 int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, int _id, void **arguments)
1567 if (call == QMetaObject::ReadProperty) {
1568 if (_id >= metaType->indexPropertyOffset) {
1569 Compositor::Group group = Compositor::Group(_id - metaType->indexPropertyOffset + 1);
1570 *static_cast<int *>(arguments[0]) = attached->m_cacheItem->index[group];
1572 } else if (_id >= metaType->memberPropertyOffset) {
1573 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1574 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
1577 } else if (call == QMetaObject::WriteProperty) {
1578 if (_id >= metaType->memberPropertyOffset) {
1579 if (!metaType->model)
1581 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(metaType->model);
1582 Compositor::Group group = Compositor::Group(_id - metaType->memberPropertyOffset + 1);
1583 const int groupFlag = 1 << group;
1584 const bool member = attached->m_cacheItem->groups & groupFlag;
1585 if (member && !*static_cast<bool *>(arguments[0])) {
1586 Compositor::iterator it = model->m_compositor.find(
1587 group, attached->m_cacheItem->index[group]);
1588 model->removeGroups(it, 1, group, groupFlag);
1589 } else if (!member && *static_cast<bool *>(arguments[0])) {
1590 for (int i = 1; i < metaType->groupCount; ++i) {
1591 if (attached->m_cacheItem->groups & (1 << i)) {
1592 Compositor::iterator it = model->m_compositor.find(
1593 Compositor::Group(i), attached->m_cacheItem->index[i]);
1594 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
1602 return attached->qt_metacall(call, _id, arguments);
1605 void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelItem *item)
1608 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
1609 m_previousIndex[i] = m_cacheItem->index[i];
1613 \qmlattachedproperty int QtQuick2::VisualDataModel::model
1615 This attached property holds the visual data model this delegate instance belongs to.
1617 It is attached to each instance of the delegate.
1620 QQuickVisualDataModel *QQuickVisualDataModelAttached::model() const
1622 return m_cacheItem ? m_cacheItem->metaType->model : 0;
1626 \qmlattachedproperty stringlist QtQuick2::VisualDataModel::groups
1628 This attached property holds the name of VisualDataGroups the item belongs to.
1630 It is attached to each instance of the delegate.
1633 QStringList QQuickVisualDataModelAttached::groups() const
1639 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1640 if (m_cacheItem->groups & (1 << i))
1641 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
1646 void QQuickVisualDataModelAttached::setGroups(const QStringList &groups)
1651 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_cacheItem->metaType->model);
1653 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
1654 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1655 if (m_cacheItem->groups & (1 << i)) {
1656 Compositor::iterator it = model->m_compositor.find(Compositor::Group(i), m_cacheItem->index[i]);
1657 model->setGroups(it, 1, Compositor::Group(i), groupFlags);
1663 bool QQuickVisualDataModelAttached::isUnresolved() const
1668 return m_cacheItem->groups & Compositor::UnresolvedFlag;
1672 \qmlattachedproperty int QtQuick2::VisualDataModel::inItems
1674 This attached property holds whether the item belongs to the default \l items VisualDataGroup.
1676 Changing this property will add or remove the item from the items group.
1678 It is attached to each instance of the delegate.
1682 \qmlattachedproperty int QtQuick2::VisualDataModel::itemsIndex
1684 This attached property holds the index of the item in the default \l items VisualDataGroup.
1686 It is attached to each instance of the delegate.
1690 \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
1692 This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
1694 Changing this property will add or remove the item from the items group. Change with caution
1695 as removing an item from the persistedItems group will destroy the current instance if it is
1696 not referenced by a model.
1698 It is attached to each instance of the delegate.
1702 \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
1704 This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
1706 It is attached to each instance of the delegate.
1709 void QQuickVisualDataModelAttached::emitChanges()
1711 if (m_modelChanged) {
1712 m_modelChanged = false;
1713 emit modelChanged();
1716 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
1717 m_previousGroups = m_cacheItem->groups;
1719 int indexChanges = 0;
1720 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
1721 if (m_previousIndex[i] != m_cacheItem->index[i]) {
1722 m_previousIndex[i] = m_cacheItem->index[i];
1723 indexChanges |= (1 << i);
1728 const QMetaObject *meta = metaObject();
1729 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1730 if (groupChanges & (1 << i))
1731 QMetaObject::activate(this, meta, notifierId, 0);
1733 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
1734 if (indexChanges & (1 << i))
1735 QMetaObject::activate(this, meta, notifierId, 0);
1739 emit groupsChanged();
1742 //============================================================================
1744 void QQuickVisualDataGroupPrivate::setModel(QQuickVisualDataModel *m, Compositor::Group g)
1751 void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine)
1753 Q_Q(QQuickVisualDataGroup);
1754 static int idx = signalIndex("changed(QQmlV8Handle,QQmlV8Handle)");
1755 if (isSignalConnected(idx) && !changeSet.isEmpty()) {
1756 v8::HandleScope handleScope;
1757 v8::Context::Scope contextScope(engine->context());
1758 v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes());
1759 v8::Local<v8::Array> inserted = QQuickVisualDataModelPrivate::buildChangeList(changeSet.inserts());
1761 QQmlV8Handle::fromHandle(removed), QQmlV8Handle::fromHandle(inserted));
1763 if (changeSet.difference() != 0)
1764 emit q->countChanged();
1767 void QQuickVisualDataGroupPrivate::emitModelUpdated(bool reset)
1769 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1770 it->emitModelUpdated(changeSet, reset);
1774 void QQuickVisualDataGroupPrivate::createdPackage(int index, QQuickPackage *package)
1776 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1777 it->createdPackage(index, package);
1780 void QQuickVisualDataGroupPrivate::initPackage(int index, QQuickPackage *package)
1782 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1783 it->initPackage(index, package);
1786 void QQuickVisualDataGroupPrivate::destroyingPackage(QQuickPackage *package)
1788 for (QQuickVisualDataGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
1789 it->destroyingPackage(package);
1793 \qmlclass VisualDataGroup QQuickVisualDataGroup
1794 \inqmlmodule QtQuick 2
1795 \ingroup qml-working-with-data
1796 \brief The VisualDataGroup encapsulates a filtered set of visual data items.
1800 QQuickVisualDataGroup::QQuickVisualDataGroup(QObject *parent)
1801 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1805 QQuickVisualDataGroup::QQuickVisualDataGroup(
1806 const QString &name, QQuickVisualDataModel *model, int index, QObject *parent)
1807 : QObject(*new QQuickVisualDataGroupPrivate, parent)
1809 Q_D(QQuickVisualDataGroup);
1811 d->setModel(model, Compositor::Group(index));
1814 QQuickVisualDataGroup::~QQuickVisualDataGroup()
1819 \qmlproperty string QtQuick2::VisualDataGroup::name
1821 This property holds the name of the group.
1823 Each group in a model must have a unique name starting with a lower case letter.
1826 QString QQuickVisualDataGroup::name() const
1828 Q_D(const QQuickVisualDataGroup);
1832 void QQuickVisualDataGroup::setName(const QString &name)
1834 Q_D(QQuickVisualDataGroup);
1837 if (d->name != name) {
1844 \qmlproperty int QtQuick2::VisualDataGroup::count
1846 This property holds the number of items in the group.
1849 int QQuickVisualDataGroup::count() const
1851 Q_D(const QQuickVisualDataGroup);
1854 return QQuickVisualDataModelPrivate::get(d->model)->m_compositor.count(d->group);
1858 \qmlproperty bool QtQuick2::VisualDataGroup::includeByDefault
1860 This property holds whether new items are assigned to this group by default.
1863 bool QQuickVisualDataGroup::defaultInclude() const
1865 Q_D(const QQuickVisualDataGroup);
1866 return d->defaultInclude;
1869 void QQuickVisualDataGroup::setDefaultInclude(bool include)
1871 Q_D(QQuickVisualDataGroup);
1872 if (d->defaultInclude != include) {
1873 d->defaultInclude = include;
1877 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
1879 QQuickVisualDataModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
1881 emit defaultIncludeChanged();
1886 \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
1888 Returns a javascript object describing the item at \a index in the group.
1890 The returned object contains the same information that is available to a delegate from the
1891 VisualDataModel attached as well as the model for that item. It has the properties:
1894 \li \b model The model data of the item. This is the same as the model context property in
1896 \li \b groups A list the of names of groups the item is a member of. This property can be
1897 written to change the item's membership.
1898 \li \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
1899 Writing to this property will add or remove the item from the group.
1900 \li \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
1901 \li \b {in\e{GroupName}} Whether the item belongs to the dynamic group \e groupName. Writing to
1902 this property will add or remove the item from the group.
1903 \li \b {\e{groupName}Index} The index of the item within the dynamic group \e groupName.
1907 QQmlV8Handle QQuickVisualDataGroup::get(int index)
1909 Q_D(QQuickVisualDataGroup);
1911 return QQmlV8Handle::fromHandle(v8::Undefined());;
1913 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
1914 if (index < 0 || index >= model->m_compositor.count(d->group)) {
1915 qmlInfo(this) << tr("get: index out of range");
1916 return QQmlV8Handle::fromHandle(v8::Undefined());
1919 Compositor::iterator it = model->m_compositor.find(d->group, index);
1920 QQuickVisualDataModelItem *cacheItem = it->inCache()
1921 ? model->m_cache.at(it.cacheIndex)
1925 cacheItem = model->m_adaptorModel->createItem(model->m_cacheMetaType, it.modelIndex());
1926 for (int i = 1; i < model->m_groupCount; ++i)
1927 cacheItem->index[i] = it.index[i];
1928 cacheItem->groups = it->flags;
1930 model->m_cache.insert(it.cacheIndex, cacheItem);
1931 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
1934 if (cacheItem->indexHandle.IsEmpty()) {
1935 cacheItem->indexHandle = qPersistentNew(model->m_cacheMetaType->constructor->NewInstance());
1936 cacheItem->indexHandle->SetExternalResource(cacheItem);
1937 cacheItem->indexHandle.MakeWeak(cacheItem, QQuickVisualDataModelItemMetaType::release_index);
1939 ++cacheItem->scriptRef;
1942 return QQmlV8Handle::fromHandle(cacheItem->indexHandle);
1945 bool QQuickVisualDataGroupPrivate::parseIndex(
1946 const v8::Local<v8::Value> &value, int *index, Compositor::Group *group) const
1948 if (value->IsInt32()) {
1949 *index = value->Int32Value();
1951 } else if (value->IsObject()) {
1952 v8::Local<v8::Object> object = value->ToObject();
1953 QQuickVisualDataModelItem * const cacheItem = v8_resource_cast<QQuickVisualDataModelItem>(object);
1954 for (int i = 1; cacheItem && i < cacheItem->metaType->groupCount; ++i) {
1955 if (cacheItem->groups & (1 << i)) {
1956 *group = Compositor::Group(i);
1957 *index = cacheItem->index[i];
1965 void QQuickVisualDataGroup::insert(QQmlV8Function *args)
1967 Q_D(QQuickVisualDataGroup);
1968 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
1970 int index = model->m_compositor.count(d->group);
1971 Compositor::Group group = d->group;
1973 if (args->Length() == 0)
1977 v8::Local<v8::Value> v = (*args)[i];
1978 if (d->parseIndex(v, &index, &group)) {
1979 if (index < 0 || index > model->m_compositor.count(group)) {
1980 qmlInfo(this) << tr("insert: index out of range");
1983 if (++i == args->Length())
1988 Compositor::insert_iterator before = index < model->m_compositor.count(group)
1989 ? model->m_compositor.findInsertPosition(group, index)
1990 : model->m_compositor.end();
1992 int groups = 1 << d->group;
1993 if (++i < args->Length())
1994 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
1998 } else if (v->IsObject()) {
1999 model->insert(before, v->ToObject(), groups);
2000 model->emitChanges();
2005 \qmlmethod QtQuick2::VisualDataGroup::create(var index)
2006 \qmlmethod QtQuick2::VisualDataGroup::create(var index, jsdict data)
2007 \qmlmethod QtQuick2::VisualDataGroup::create(jsdict data)
2009 Returns a reference to the instantiated item at \a index in the group.
2011 All items returned by create are added to the persistedItems group. Items in this
2012 group remain instantiated when not referenced by any view.
2015 void QQuickVisualDataGroup::create(QQmlV8Function *args)
2017 Q_D(QQuickVisualDataGroup);
2021 if (args->Length() == 0)
2024 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2026 int index = model->m_compositor.count(d->group);
2027 Compositor::Group group = d->group;
2030 v8::Local<v8::Value> v = (*args)[i];
2031 if (d->parseIndex(v, &index, &group))
2034 if (i < args->Length() && index >= 0 && index <= model->m_compositor.count(group)) {
2036 if (v->IsObject()) {
2037 int groups = 1 << d->group;
2038 if (++i < args->Length())
2039 groups |= model->m_cacheMetaType->parseGroups((*args)[i]);
2041 Compositor::insert_iterator before = index < model->m_compositor.count(group)
2042 ? model->m_compositor.findInsertPosition(group, index)
2043 : model->m_compositor.end();
2045 index = before.index[d->group];
2048 if (!model->insert(before, v->ToObject(), groups)) {
2053 if (index < 0 || index >= model->m_compositor.count(group)) {
2054 qmlInfo(this) << tr("create: index out of range");
2058 QObject *object = model->object(group, index, false, false);
2060 QVector<Compositor::Insert> inserts;
2061 Compositor::iterator it = model->m_compositor.find(group, index);
2062 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
2063 model->itemsInserted(inserts);
2066 args->returnValue(args->engine()->newQObject(object));
2067 model->emitChanges();
2070 void QQuickVisualDataGroup::resolve(QQmlV8Function *args)
2072 Q_D(QQuickVisualDataGroup);
2076 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2078 if (args->Length() < 2)
2083 Compositor::Group fromGroup = d->group;
2084 Compositor::Group toGroup = d->group;
2086 v8::Local<v8::Value> v = (*args)[0];
2087 if (d->parseIndex(v, &from, &fromGroup)) {
2088 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
2089 qmlInfo(this) << tr("resolve: from index out of range");
2093 qmlInfo(this) << tr("resolve: from index invalid");
2098 if (d->parseIndex(v, &to, &toGroup)) {
2099 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
2100 qmlInfo(this) << tr("resolve: to index out of range");
2104 qmlInfo(this) << tr("resolve: to index invalid");
2108 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
2109 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
2111 if (!fromIt->isUnresolved()) {
2112 qmlInfo(this) << tr("resolve: from is not an unresolved item");
2116 qmlInfo(this) << tr("resolve: to is not a model item");
2120 const int unresolvedFlags = fromIt->flags;
2121 const int resolvedFlags = toIt->flags;
2122 const int resolvedIndex = toIt.modelIndex();
2123 void * const resolvedList = toIt->list;
2125 QQuickVisualDataModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex);
2126 cacheItem->groups &= ~Compositor::UnresolvedFlag;
2128 if (toIt.cacheIndex > fromIt.cacheIndex)
2129 toIt.decrementIndexes(1, unresolvedFlags);
2130 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
2134 QVector<Compositor::Remove>() << Compositor::Remove(fromIt, 1, unresolvedFlags, 0),
2135 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, unresolvedFlags, 0));
2136 model->itemsInserted(
2137 QVector<Compositor::Insert>() << Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag));
2138 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
2139 model->itemsRemoved(QVector<Compositor::Remove>() << Compositor::Remove(toIt, 1, resolvedFlags));
2141 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
2142 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
2144 if (resolvedFlags & Compositor::CacheFlag)
2145 model->m_compositor.insert(Compositor::Cache, toIt.cacheIndex, resolvedList, resolvedIndex, 1, Compositor::CacheFlag);
2147 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2149 if (!cacheItem->isReferenced()) {
2150 Q_ASSERT(toIt.cacheIndex == model->m_cache.indexOf(cacheItem));
2151 model->m_cache.removeAt(toIt.cacheIndex);
2152 model->m_compositor.clearFlags(Compositor::Cache, toIt.cacheIndex, 1, Compositor::CacheFlag);
2154 Q_ASSERT(model->m_cache.count() == model->m_compositor.count(Compositor::Cache));
2156 cacheItem->resolveIndex(resolvedIndex);
2157 if (cacheItem->object)
2158 cacheItem->attached->emitUnresolvedChanged();
2161 model->emitChanges();
2165 \qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
2167 Removes \a count items starting at \a index from the group.
2170 void QQuickVisualDataGroup::remove(QQmlV8Function *args)
2172 Q_D(QQuickVisualDataGroup);
2175 Compositor::Group group = d->group;
2179 if (args->Length() == 0)
2183 v8::Local<v8::Value> v = (*args)[i];
2184 if (!d->parseIndex(v, &index, &group)) {
2185 qmlInfo(this) << tr("remove: invalid index");
2189 if (++i < args->Length()) {
2192 count = v->Int32Value();
2195 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2196 if (index < 0 || index >= model->m_compositor.count(group)) {
2197 qmlInfo(this) << tr("remove: index out of range");
2198 } else if (count != 0) {
2199 Compositor::iterator it = model->m_compositor.find(group, index);
2200 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2201 qmlInfo(this) << tr("remove: invalid count");
2203 model->removeGroups(it, count, d->group, 1 << d->group);
2208 bool QQuickVisualDataGroupPrivate::parseGroupArgs(
2209 QQmlV8Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
2211 if (!model || !QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType)
2214 if (args->Length() < 2)
2218 v8::Local<v8::Value> v = (*args)[i];
2219 if (!parseIndex(v, index, group))
2224 *count = v->Int32Value();
2226 if (++i == args->Length())
2231 *groups = QQuickVisualDataModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
2237 \qmlmethod QtQuick2::VisualDataGroup::addGroups(int index, int count, stringlist groups)
2239 Adds \a count items starting at \a index to \a groups.
2242 void QQuickVisualDataGroup::addGroups(QQmlV8Function *args)
2244 Q_D(QQuickVisualDataGroup);
2245 Compositor::Group group = d->group;
2250 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2253 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2254 if (index < 0 || index >= model->m_compositor.count(group)) {
2255 qmlInfo(this) << tr("addGroups: index out of range");
2256 } else if (count != 0) {
2257 Compositor::iterator it = model->m_compositor.find(group, index);
2258 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2259 qmlInfo(this) << tr("addGroups: invalid count");
2261 model->addGroups(it, count, d->group, groups);
2267 \qmlmethod QtQuick2::VisualDataGroup::removeGroups(int index, int count, stringlist groups)
2269 Removes \a count items starting at \a index from \a groups.
2272 void QQuickVisualDataGroup::removeGroups(QQmlV8Function *args)
2274 Q_D(QQuickVisualDataGroup);
2275 Compositor::Group group = d->group;
2280 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2283 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2284 if (index < 0 || index >= model->m_compositor.count(group)) {
2285 qmlInfo(this) << tr("removeGroups: index out of range");
2286 } else if (count != 0) {
2287 Compositor::iterator it = model->m_compositor.find(group, index);
2288 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2289 qmlInfo(this) << tr("removeGroups: invalid count");
2291 model->removeGroups(it, count, d->group, groups);
2297 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2299 Sets the \a groups \a count items starting at \a index belong to.
2302 void QQuickVisualDataGroup::setGroups(QQmlV8Function *args)
2304 Q_D(QQuickVisualDataGroup);
2305 Compositor::Group group = d->group;
2310 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
2313 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2314 if (index < 0 || index >= model->m_compositor.count(group)) {
2315 qmlInfo(this) << tr("setGroups: index out of range");
2316 } else if (count != 0) {
2317 Compositor::iterator it = model->m_compositor.find(group, index);
2318 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
2319 qmlInfo(this) << tr("setGroups: invalid count");
2321 model->setGroups(it, count, d->group, groups);
2327 \qmlmethod QtQuick2::VisualDataGroup::setGroups(int index, int count, stringlist groups)
2329 Sets the \a groups \a count items starting at \a index belong to.
2333 \qmlmethod QtQuick2::VisualDataGroup::move(var from, var to, int count)
2335 Moves \a count at \a from in a group \a to a new position.
2338 void QQuickVisualDataGroup::move(QQmlV8Function *args)
2340 Q_D(QQuickVisualDataGroup);
2342 if (args->Length() < 2)
2345 Compositor::Group fromGroup = d->group;
2346 Compositor::Group toGroup = d->group;
2351 if (!d->parseIndex((*args)[0], &from, &fromGroup)) {
2352 qmlInfo(this) << tr("move: invalid from index");
2356 if (!d->parseIndex((*args)[1], &to, &toGroup)) {
2357 qmlInfo(this) << tr("move: invalid to index");
2361 if (args->Length() > 2) {
2362 v8::Local<v8::Value> v = (*args)[2];
2364 count = v->Int32Value();
2367 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(d->model);
2370 qmlInfo(this) << tr("move: invalid count");
2371 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
2372 qmlInfo(this) << tr("move: from index out of range");
2373 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
2374 qmlInfo(this) << tr("move: to index out of range");
2375 } else if (count > 0) {
2376 QVector<Compositor::Remove> removes;
2377 QVector<Compositor::Insert> inserts;
2379 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
2380 model->itemsMoved(removes, inserts);
2381 model->emitChanges();
2387 \qmlsignal QtQuick2::VisualDataGroup::onChanged(array removed, array inserted)
2389 This handler is called when items have been removed from or inserted into the group.
2391 Each object in the \a removed and \a inserted arrays has two values; the \e index of the first
2392 item inserted or removed and a \e count of the number of consecutive items inserted or removed.
2394 Each index is adjusted for previous changes with all removed items preceding any inserted
2398 //============================================================================
2400 QQuickVisualPartsModel::QQuickVisualPartsModel(QQuickVisualDataModel *model, const QString &part, QObject *parent)
2401 : QQuickVisualModel(*new QObjectPrivate, parent)
2404 , m_compositorGroup(Compositor::Cache)
2405 , m_inheritGroup(true)
2407 QQuickVisualDataModelPrivate *d = QQuickVisualDataModelPrivate::get(m_model);
2408 if (d->m_cacheMetaType) {
2409 QQuickVisualDataGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
2410 m_compositorGroup = Compositor::Default;
2412 d->m_pendingParts.insert(this);
2416 QQuickVisualPartsModel::~QQuickVisualPartsModel()
2420 QString QQuickVisualPartsModel::filterGroup() const
2423 return m_model->filterGroup();
2424 return m_filterGroup;
2427 void QQuickVisualPartsModel::setFilterGroup(const QString &group)
2429 if (QQuickVisualDataModelPrivate::get(m_model)->m_transaction) {
2430 qmlInfo(this) << tr("The group of a VisualDataModel cannot be changed within onChanged");
2434 if (m_filterGroup != group || m_inheritGroup) {
2435 m_filterGroup = group;
2436 m_inheritGroup = false;
2437 updateFilterGroup();
2439 emit filterGroupChanged();
2443 void QQuickVisualPartsModel::resetFilterGroup()
2445 if (!m_inheritGroup) {
2446 m_inheritGroup = true;
2447 updateFilterGroup();
2448 emit filterGroupChanged();
2452 void QQuickVisualPartsModel::updateFilterGroup()
2454 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2455 if (!model->m_cacheMetaType)
2458 if (m_inheritGroup) {
2459 if (m_filterGroup == model->m_filterGroup)
2461 m_filterGroup = model->m_filterGroup;
2464 QQuickListCompositor::Group previousGroup = m_compositorGroup;
2465 m_compositorGroup = Compositor::Default;
2466 QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
2467 for (int i = 1; i < model->m_groupCount; ++i) {
2468 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
2469 m_compositorGroup = Compositor::Group(i);
2474 QQuickVisualDataGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
2475 if (m_compositorGroup != previousGroup) {
2476 QVector<QQuickChangeSet::Remove> removes;
2477 QVector<QQuickChangeSet::Insert> inserts;
2478 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
2480 QQuickChangeSet changeSet;
2481 changeSet.apply(removes, inserts);
2482 if (!changeSet.isEmpty())
2483 emit modelUpdated(changeSet, false);
2485 if (changeSet.difference() != 0)
2486 emit countChanged();
2490 void QQuickVisualPartsModel::updateFilterGroup(
2491 Compositor::Group group, const QQuickChangeSet &changeSet)
2493 if (!m_inheritGroup)
2496 m_compositorGroup = group;
2497 QQuickVisualDataGroupPrivate::get(QQuickVisualDataModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
2499 if (!changeSet.isEmpty())
2500 emit modelUpdated(changeSet, false);
2502 if (changeSet.difference() != 0)
2503 emit countChanged();
2505 emit filterGroupChanged();
2508 int QQuickVisualPartsModel::count() const
2510 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2511 return model->m_delegate
2512 ? model->m_compositor.count(m_compositorGroup)
2516 bool QQuickVisualPartsModel::isValid() const
2518 return m_model->isValid();
2521 QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous)
2523 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2525 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
2526 qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
2530 QObject *object = model->object(m_compositorGroup, index, asynchronous, true);
2532 if (QQuickPackage *package = qobject_cast<QQuickPackage *>(object)) {
2533 QObject *part = package->part(m_part);
2536 if (QQuickItem *item = qobject_cast<QQuickItem *>(part)) {
2537 m_packaged.insertMulti(item, package);
2542 model->release(object);
2543 if (!model->m_delegateValidated) {
2545 qmlInfo(model->m_delegate) << tr("Delegate component must be Package type.");
2546 model->m_delegateValidated = true;
2552 QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item)
2554 QQuickVisualModel::ReleaseFlags flags = 0;
2556 QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
2557 if (it != m_packaged.end()) {
2558 QQuickPackage *package = *it;
2559 QQml_setParent_noEvent(item, package);
2560 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2561 flags = model->release(package);
2562 m_packaged.erase(it);
2563 if (!m_packaged.contains(item))
2564 flags &= ~Referenced;
2565 if (flags & Destroyed)
2566 QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package);
2571 QString QQuickVisualPartsModel::stringValue(int index, const QString &role)
2573 return QQuickVisualDataModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
2576 void QQuickVisualPartsModel::setWatchedRoles(QList<QByteArray> roles)
2578 QQuickVisualDataModelPrivate *model = QQuickVisualDataModelPrivate::get(m_model);
2579 model->m_adaptorModel->replaceWatchedRoles(m_watchedRoles, roles);
2580 m_watchedRoles = roles;
2583 int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const
2585 QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
2586 if (it != m_packaged.end()) {
2587 if (QQuickVisualDataModelAttached *attached = QQuickVisualDataModelAttached::properties(*it))
2588 return attached->m_cacheItem->index[m_compositorGroup];
2593 void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package)
2595 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2596 emit createdItem(index, item);
2599 void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package)
2601 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part)))
2602 emit initItem(index, item);
2605 void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package)
2607 if (QQuickItem *item = qobject_cast<QQuickItem *>(package->part(m_part))) {
2608 Q_ASSERT(!m_packaged.contains(item));
2609 emit destroyingItem(item);
2610 item->setParentItem(0);
2611 QQml_setParent_noEvent(item, package);
2615 void QQuickVisualPartsModel::emitModelUpdated(const QQuickChangeSet &changeSet, bool reset)
2617 emit modelUpdated(changeSet, reset);
2618 if (changeSet.difference() != 0)
2619 emit countChanged();