aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2011-09-29 09:58:42 +1000
committerQt by Nokia <qt-info@nokia.com>2011-10-12 02:36:56 +0200
commitae623976b8920117e751448e2a65dab174731476 (patch)
tree21c1e44764a77e50f4fc7202d000c0670692bdee
parent959778a2b750cbc211643929a6e85a8694d72891 (diff)
Allow view items to be preserved.
Do not destroy items that are members of the VisualDataModel persistedItems group when they are released by the view. The create function on VisualDataGroup will return a reference to an instantiated item within that group, any item returned by this function is automatically added to the persistedItems group and can be released by removing it from the group. Uninstantiated items added to the persistedItems group by any other means are not instantiated until requested by a view or create. Task-number: QTBUG-21518 Task-number: QTBUG-20854 Change-Id: I59554711208504c8f20a3ebe783bddab9b21a558 Reviewed-on: http://codereview.qt-project.org/5831 Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
-rw-r--r--examples/declarative/modelviews/visualdatamodel/slideshow.qml155
-rw-r--r--src/declarative/items/qsgvisualdatamodel.cpp152
-rw-r--r--src/declarative/items/qsgvisualdatamodel_p.h3
-rw-r--r--src/declarative/util/qdeclarativelistcompositor.cpp3
-rw-r--r--src/declarative/util/qdeclarativelistcompositor_p.h11
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/create.qml22
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp114
7 files changed, 430 insertions, 30 deletions
diff --git a/examples/declarative/modelviews/visualdatamodel/slideshow.qml b/examples/declarative/modelviews/visualdatamodel/slideshow.qml
new file mode 100644
index 0000000000..edf1f0f057
--- /dev/null
+++ b/examples/declarative/modelviews/visualdatamodel/slideshow.qml
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+
+ property Item displayItem: null
+
+ width: 300; height: 400
+
+ color: "black"
+
+ VisualDataModel {
+ id: visualModel
+
+ model: XmlListModel {
+ source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2"
+ query: "/rss/channel/item"
+ namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
+
+ XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ XmlRole { name: "url"; query: "media:content/@url/string()" }
+ }
+
+ delegate: Item {
+ id: delegateItem
+
+ width: 76; height: 76
+
+ Rectangle {
+ id: image
+ x: 0; y: 0; width: 76; height: 76
+ border.width: 1
+ border.color: "white"
+ color: "black"
+
+ Image {
+ anchors.fill: parent
+ anchors.leftMargin: 1
+ anchors.topMargin: 1
+
+ source: imagePath
+ fillMode: Image.PreserveAspectFit
+
+ }
+
+ MouseArea {
+ id: clickArea
+ anchors.fill: parent
+
+ onClicked: root.displayItem = root.displayItem !== delegateItem ? delegateItem : null
+ }
+
+ states: [
+ State {
+ when: root.displayItem === delegateItem
+ name: "inDisplay";
+ ParentChange { target: image; parent: imageContainer; x: 75; y: 75; width: 150; height: 150 }
+ PropertyChanges { target: image; z: 2 }
+ PropertyChanges { target: delegateItem; VisualDataModel.inItems: false }
+ },
+ State {
+ when: root.displayItem !== delegateItem
+ name: "inList";
+ ParentChange { target: image; parent: delegateItem; x: 2; y: 2; width: 75; height: 75 }
+ PropertyChanges { target: image; z: 1 }
+ PropertyChanges { target: delegateItem; VisualDataModel.inItems: true }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "inList"
+ SequentialAnimation {
+ PropertyAction { target: delegateItem; property: "VisualDataModel.inPersistedItems"; value: true }
+ ParentAnimation {
+ target: image;
+ via: root
+ NumberAnimation { target: image; properties: "x,y,width,height"; duration: 1000 }
+ }
+ }
+ }, Transition {
+ from: "inDisplay"
+ SequentialAnimation {
+ ParentAnimation {
+ target: image
+ NumberAnimation { target: image; properties: "x,y,width,height"; duration: 1000 }
+ }
+ PropertyAction { target: delegateItem; property: "VisualDataModel.inPersistedItems"; value: false }
+ }
+ }
+ ]
+ }
+ }
+ }
+
+
+ PathView {
+ id: imagePath
+
+ anchors { left: parent.left; top: imageContainer.bottom; right: parent.right; bottom: parent.bottom }
+ model: visualModel
+
+ pathItemCount: 7
+ path: Path {
+ startX: -50; startY: 0
+ PathQuad { x: 150; y: 50; controlX: 0; controlY: 50 }
+ PathQuad { x: 350; y: 0; controlX: 300; controlY: 50 }
+ }
+ }
+
+ Item {
+ id: imageContainer
+ anchors { fill: parent; bottomMargin: 100 }
+ }
+}
diff --git a/src/declarative/items/qsgvisualdatamodel.cpp b/src/declarative/items/qsgvisualdatamodel.cpp
index e0d353a93f..47edc5d8f0 100644
--- a/src/declarative/items/qsgvisualdatamodel.cpp
+++ b/src/declarative/items/qsgvisualdatamodel.cpp
@@ -131,14 +131,14 @@ public:
void init();
void connectModel(QSGVisualAdaptorModel *model);
- QObject *object(Compositor::Group group, int index, bool complete);
- QSGItem *item(Compositor::Group group, int index, bool complete);
+ QObject *object(Compositor::Group group, int index, bool complete, bool reference);
void destroy(QObject *object);
QSGVisualDataModel::ReleaseFlags release(QObject *object);
QString stringValue(Compositor::Group group, int index, const QString &name);
int cacheIndexOf(QObject *object) const;
void emitCreatedPackage(Compositor::iterator at, QDeclarativePackage *package);
- void emitCreatedItem(int index, QSGItem *item) { emit q_func()->createdItem(index, item); }
+ void emitCreatedItem(Compositor::iterator at, QSGItem *item) {
+ emit q_func()->createdItem(at.index[m_compositorGroup], item); }
void emitDestroyingPackage(QDeclarativePackage *package);
void emitDestroyingItem(QSGItem *item) { emit q_func()->destroyingItem(item); }
@@ -194,6 +194,7 @@ public:
struct {
QSGVisualDataGroup *m_cacheItems;
QSGVisualDataGroup *m_items;
+ QSGVisualDataGroup *m_persistedItems;
};
QSGVisualDataGroup *m_groups[Compositor::MaximumGroupCount];
};
@@ -341,9 +342,10 @@ public:
}
void referenceObject() { ++objectRef; }
- bool releaseObject() { return --objectRef == 0; }
+ bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
+ bool isObjectReferenced() const { return objectRef == 0 && !(groups & Compositor::PersistedFlag); }
- bool isReferenced() const { return objectRef || scriptRef; }
+ bool isReferenced() const { return objectRef || scriptRef || (groups & Compositor::PersistedFlag); }
void Dispose();
@@ -409,7 +411,7 @@ QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt)
, m_filterGroup(QStringLiteral("items"))
, m_cacheItems(0)
, m_items(0)
- , m_groupCount(2)
+ , m_groupCount(3)
{
}
@@ -427,11 +429,14 @@ void QSGVisualDataModelPrivate::connectModel(QSGVisualAdaptorModel *model)
void QSGVisualDataModelPrivate::init()
{
Q_Q(QSGVisualDataModel);
+ m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
+
m_adaptorModel = new QSGVisualAdaptorModel;
QObject::connect(m_adaptorModel, SIGNAL(rootIndexChanged()), q, SIGNAL(rootIndexChanged()));
m_items = new QSGVisualDataGroup(QStringLiteral("items"), q, Compositor::Default, q);
m_items->setDefaultInclude(true);
+ m_persistedItems = new QSGVisualDataGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
QSGVisualDataGroupPrivate::get(m_items)->emitters.insert(this);
}
@@ -477,9 +482,12 @@ void QSGVisualDataModel::componentComplete()
int defaultGroups = 0;
QStringList groupNames;
groupNames.append(QStringLiteral("items"));
+ groupNames.append(QStringLiteral("persistedItems"));
if (QSGVisualDataGroupPrivate::get(d->m_items)->defaultInclude)
defaultGroups |= Compositor::DefaultFlag;
- for (int i = 2; i < d->m_groupCount; ++i) {
+ if (QSGVisualDataGroupPrivate::get(d->m_persistedItems)->defaultInclude)
+ defaultGroups |= Compositor::PersistedFlag;
+ for (int i = 3; i < d->m_groupCount; ++i) {
QString name = d->m_groups[i]->name();
if (name.isEmpty()) {
d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
@@ -683,6 +691,16 @@ int QSGVisualDataModel::count() const
return d->m_compositor.count(d->m_compositorGroup);
}
+void QSGVisualDataModelPrivate::destroy(QObject *object)
+{
+ QObjectPrivate *p = QObjectPrivate::get(object);
+ Q_ASSERT(p->declarativeData);
+ QDeclarativeData *data = static_cast<QDeclarativeData*>(p->declarativeData);
+ if (data->ownContext && data->context)
+ data->context->clearContext();
+ object->deleteLater();
+}
+
QSGVisualDataModel::ReleaseFlags QSGVisualDataModelPrivate::release(QObject *object)
{
QSGVisualDataModel::ReleaseFlags stat = 0;
@@ -693,12 +711,7 @@ QSGVisualDataModel::ReleaseFlags QSGVisualDataModelPrivate::release(QObject *obj
if (cacheIndex != -1) {
QSGVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
if (cacheItem->releaseObject()) {
- QObjectPrivate *p = QObjectPrivate::get(object);
- Q_ASSERT(p->declarativeData);
- QDeclarativeData *data = static_cast<QDeclarativeData*>(p->declarativeData);
- if (data->ownContext && data->context)
- data->context->clearContext();
- object->deleteLater();
+ destroy(object);
cacheItem->object = 0;
stat |= QSGVisualModel::Destroyed;
if (!cacheItem->isReferenced()) {
@@ -733,7 +746,7 @@ void QSGVisualDataModelPrivate::group_append(
QSGVisualDataModelPrivate *d = static_cast<QSGVisualDataModelPrivate *>(property->data);
if (d->m_complete)
return;
- if (d->m_groupCount == 10) {
+ if (d->m_groupCount == 11) {
qmlInfo(d->q_func()) << QSGVisualDataModel::tr("The maximum number of supported VisualDataGroups is 8");
return;
}
@@ -799,6 +812,29 @@ QSGVisualDataGroup *QSGVisualDataModel::items()
}
/*!
+ \qmlproperty VisualDataGroup QtQuick2::VisualDataModel::persistedItems
+
+ This property holds visual data model's persisted items group.
+
+ Items in this group are not destroyed when released by a view, instead they are persisted
+ until removed from the group.
+
+ An item can be removed from the persistedItems group by setting the
+ VisualDataModel.inPersistedItems property to false. If the item is not referenced by a view
+ at that time it will be destroyed. Adding an item to this group will not create a new
+ instance.
+
+ Items returned by the \l QtQuick2::VisualDataGroup::create() function are automatically added
+ to this group.
+*/
+
+QSGVisualDataGroup *QSGVisualDataModel::persistedItems()
+{
+ Q_D(QSGVisualDataModel);
+ return d->m_persistedItems;
+}
+
+/*!
\qmlproperty string QtQuick2::VisualDataModel::filterOnGroup
This property holds the name of the group used to filter the visual data model.
@@ -918,13 +954,9 @@ void QSGVisualDataModelPrivate::emitDestroyingPackage(QDeclarativePackage *packa
QSGVisualDataGroupPrivate::get(m_groups[i])->destroyingPackage(package);
}
-QObject *QSGVisualDataModelPrivate::object(Compositor::Group group, int index, bool complete)
+QObject *QSGVisualDataModelPrivate::object(Compositor::Group group, int index, bool complete, bool reference)
{
Q_Q(QSGVisualDataModel);
- if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
- qWarning() << "VisualDataModel::item: index out range" << index << m_compositor.count(group);
- return 0;
- }
Compositor::iterator it = m_compositor.find(group, index);
QSGVisualDataModelCacheItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
@@ -970,8 +1002,12 @@ QObject *QSGVisualDataModelPrivate::object(Compositor::Group group, int index, b
new QSGVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType);
cacheItem->attached->emitChanges();
- if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object)) {
emitCreatedPackage(it, package);
+ } else if (!reference) {
+ if (QSGItem *item = qobject_cast<QSGItem *>(cacheItem->object))
+ emitCreatedItem(it, item);
+ }
m_completePending = !complete;
if (complete)
@@ -987,14 +1023,20 @@ QObject *QSGVisualDataModelPrivate::object(Compositor::Group group, int index, b
if (index == m_compositor.count(group) - 1 && m_adaptorModel->canFetchMore())
QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
- cacheItem->referenceObject();
+ if (reference)
+ cacheItem->referenceObject();
return cacheItem->object;
}
QSGItem *QSGVisualDataModel::item(int index, bool complete)
{
Q_D(QSGVisualDataModel);
- QObject *object = d->object(d->m_compositorGroup, index, complete);
+ if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
+ return 0;
+ }
+
+ QObject *object = d->object(d->m_compositorGroup, index, complete, true);
if (QSGItem *item = qobject_cast<QSGItem *>(object))
return item;
if (d->m_completePending)
@@ -1251,6 +1293,14 @@ void QSGVisualDataModelPrivate::itemsRemoved(
} else {
for (; cacheIndex < remove.cacheIndex + remove.count - removedCache; ++cacheIndex) {
QSGVisualDataModelCacheItem *cacheItem = m_cache.at(cacheIndex);
+ if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0) {
+ destroy(cacheItem->object);
+ if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(cacheItem->object))
+ emitDestroyingPackage(package);
+ else if (QSGItem *item = qobject_cast<QSGItem *>(cacheItem->object))
+ emitDestroyingItem(item);
+ cacheItem->object = 0;
+ }
if (remove.groups() == cacheItem->groups && !cacheItem->isReferenced()) {
m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
m_cache.removeAt(cacheIndex);
@@ -1742,6 +1792,26 @@ void QSGVisualDataModelAttached::setGroups(const QStringList &groups)
It is attached to each instance of the delegate.
*/
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::inPersistedItems
+
+ This attached property holds whether the item belongs to the \l persistedItems VisualDataGroup.
+
+ Changing this property will add or remove the item from the items group. Change with caution
+ as removing an item from the persistedItems group will destroy the current instance if it is
+ not referenced by a model.
+
+ It is attached to each instance of the delegate.
+*/
+
+/*!
+ \qmlattachedproperty int QtQuick2::VisualDataModel::persistedItemsIndex
+
+ This attached property holds the index of the item in the \l persistedItems VisualDataGroup.
+
+ It is attached to each instance of the delegate.
+*/
+
void QSGVisualDataModelAttached::emitChanges()
{
if (m_modelChanged) {
@@ -1925,9 +1995,9 @@ void QSGVisualDataGroup::setDefaultInclude(bool include)
a delegate
\o \b groups A list the of names of groups the item is a member of. This property can be
written to change the item's membership.
- \o \b inItems Whether the item belongs to the \l {VisualDataModel::items}{items} group.
+ \o \b inItems Whether the item belongs to the \l {QtQuick2::VisualDataModel::items}{items} group.
Writing to this property will add or remove the item from the group.
- \o \b itemsIndex The index of the item within the \l {VisualDataModel::items}{items} group.
+ \o \b itemsIndex The index of the item within the \l {QtQuick2::VisualDataModel::items}{items} group.
\o \b {in\i{GroupName}} Whether the item belongs to the dynamic group \i groupName. Writing to
this property will add or remove the item from the group.
\o \b {\i{groupName}Index} The index of the item within the dynamic group \i groupName.
@@ -1969,6 +2039,33 @@ QDeclarativeV8Handle QSGVisualDataGroup::get(int index)
}
/*!
+ \qmlmethod QtQuick2::VisualDataGroup::create(int index)
+
+ Returns a reference to the instantiated item at \a index in the group.
+
+ All items returned by create are added to the persistedItems group. Items in this
+ group remain instantiated when not referenced by any view.
+*/
+
+QObject *QSGVisualDataGroup::create(int index)
+{
+ Q_D(QSGVisualDataGroup);
+ if (!d->model)
+ return 0;
+
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(d->model);
+ if (index < 0 || index >= model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("create: index out of range");
+ return 0;
+ }
+
+ QObject *object = model->object(d->group, index, true, false);
+ if (object)
+ model->addGroups(d->group, index, 1, Compositor::PersistedFlag);
+ return object;
+}
+
+/*!
\qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
Removes \a count items starting at \a index from the group.
@@ -2332,7 +2429,12 @@ QSGItem *QSGVisualPartsModel::item(int index, bool complete)
{
QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(m_model);
- QObject *object = model->object(m_compositorGroup, index, complete);
+ if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
+ qWarning() << "VisualDataModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
+ return 0;
+ }
+
+ QObject *object = model->object(m_compositorGroup, index, complete, true);
if (QDeclarativePackage *package = qobject_cast<QDeclarativePackage *>(object)) {
QObject *part = package->part(m_part);
diff --git a/src/declarative/items/qsgvisualdatamodel_p.h b/src/declarative/items/qsgvisualdatamodel_p.h
index 9b4542d08a..896c51c22a 100644
--- a/src/declarative/items/qsgvisualdatamodel_p.h
+++ b/src/declarative/items/qsgvisualdatamodel_p.h
@@ -79,6 +79,7 @@ class Q_DECLARATIVE_EXPORT QSGVisualDataModel : public QSGVisualModel, public QD
Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate)
Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
Q_PROPERTY(QSGVisualDataGroup *items READ items CONSTANT)
+ Q_PROPERTY(QSGVisualDataGroup *persistedItems READ persistedItems CONSTANT)
Q_PROPERTY(QDeclarativeListProperty<QSGVisualDataGroup> groups READ groups CONSTANT)
Q_PROPERTY(QObject *parts READ parts CONSTANT)
Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
@@ -120,6 +121,7 @@ public:
void resetFilterGroup();
QSGVisualDataGroup *items();
+ QSGVisualDataGroup *persistedItems();
QDeclarativeListProperty<QSGVisualDataGroup> groups();
QObject *parts();
@@ -163,6 +165,7 @@ public:
void setDefaultInclude(bool include);
Q_INVOKABLE QDeclarativeV8Handle get(int index);
+ Q_INVOKABLE QObject *create(int index);
public Q_SLOTS:
void remove(QDeclarativeV8Function *);
diff --git a/src/declarative/util/qdeclarativelistcompositor.cpp b/src/declarative/util/qdeclarativelistcompositor.cpp
index 7beefdaafa..be0d543368 100644
--- a/src/declarative/util/qdeclarativelistcompositor.cpp
+++ b/src/declarative/util/qdeclarativelistcompositor.cpp
@@ -283,6 +283,7 @@ QDeclarativeListCompositor::QDeclarativeListCompositor()
, m_cacheIt(m_end)
, m_groupCount(2)
, m_defaultFlags(PrependFlag | DefaultFlag)
+ , m_removeFlags(AppendFlag | PrependFlag | GroupMask)
{
}
@@ -896,7 +897,7 @@ void QDeclarativeListCompositor::listItemsRemoved(
const int offset = qMax(0, relativeIndex);
int removeCount = qMin(it->count, relativeIndex + removal->count) - offset;
it->count -= removeCount;
- int removeFlags = it->flags & RemoveFlags;
+ int removeFlags = it->flags & m_removeFlags;
Remove translatedRemoval(it, removeCount, it->flags);
for (int i = 0; i < m_groupCount; ++i) {
if (it->inGroup(i))
diff --git a/src/declarative/util/qdeclarativelistcompositor_p.h b/src/declarative/util/qdeclarativelistcompositor_p.h
index cd2d9b3f5f..60df819884 100644
--- a/src/declarative/util/qdeclarativelistcompositor_p.h
+++ b/src/declarative/util/qdeclarativelistcompositor_p.h
@@ -65,23 +65,24 @@ QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QDeclarativeListCompositor
{
public:
- enum { MaximumGroupCount = 10 };
+ enum { MaximumGroupCount = 11 };
enum Group
{
Cache = 0,
- Default = 1
+ Default = 1,
+ Persisted = 2
};
enum Flag
{
CacheFlag = 0x000001,
DefaultFlag = 0x000002,
+ PersistedFlag = 0x000004,
GroupMask = 0x00FFFE,
PrependFlag = 0x100000,
AppendFlag = 0x200000,
- MovedFlag = 0x400000,
- RemoveFlags = GroupMask | PrependFlag | AppendFlag
+ MovedFlag = 0x400000
};
class Range
@@ -215,6 +216,7 @@ public:
void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
+ void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
void setGroupCount(int count);
int count(Group group) const;
@@ -272,6 +274,7 @@ private:
iterator m_cacheIt;
int m_groupCount;
int m_defaultFlags;
+ int m_removeFlags;
inline Range *insert(Range *before, void *list, int index, int count, int flags);
inline Range *erase(Range *range);
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/create.qml b/tests/auto/declarative/qsgvisualdatamodel/data/create.qml
new file mode 100644
index 0000000000..36ea3baf76
--- /dev/null
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/create.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+ListView {
+ width: 200
+ height: 200
+
+ model: VisualDataModel {
+ id: visualModel
+
+ model: myModel
+ delegate: Item {
+ id: delegate
+ objectName: "delegate"
+ width: 200
+ height: 20
+
+ property bool destroyed: false
+
+ Component.onDestruction: destroyed = true
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
index 50e1b8f9df..63e40cdb60 100644
--- a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
+++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
@@ -135,6 +135,7 @@ private slots:
void move();
void groups();
void get();
+ void create();
private:
template <int N> void groups_verify(
@@ -1410,6 +1411,119 @@ void tst_qsgvisualdatamodel::get()
}
}
+void tst_qsgvisualdatamodel::create()
+{
+ QSGView view;
+
+ SingleRoleModel model;
+ model.list = QStringList()
+ << "one"
+ << "two"
+ << "three"
+ << "four"
+ << "five"
+ << "six"
+ << "seven"
+ << "eight"
+ << "nine"
+ << "ten"
+ << "eleven"
+ << "twelve"
+ << "thirteen"
+ << "fourteen"
+ << "fifteen"
+ << "sixteen"
+ << "seventeen"
+ << "eighteen"
+ << "nineteen"
+ << "twenty";
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/create.qml"));
+
+ QSGListView *listview = qobject_cast<QSGListView*>(view.rootObject());
+ QVERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != 0);
+
+ QSGVisualDataModel *visualModel = qobject_cast<QSGVisualDataModel *>(qvariant_cast<QObject *>(listview->model()));
+ QVERIFY(visualModel);
+
+ QCOMPARE(listview->count(), 20);
+
+ QSGItem *delegate;
+
+ // Request an item instantiated by the view.
+ QVERIFY(findItem<QSGItem>(contentItem, "delegate", 1));
+ QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(1)")));
+ QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 1));
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
+
+ evaluate<void>(delegate, "VisualDataModel.inPersistedItems = false");
+ QCOMPARE(listview->count(), 20);
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
+
+ // Request an item not instantiated by the view.
+ QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 15));
+ QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(15)")));
+ QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 15));
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
+
+ evaluate<void>(visualModel, "persistedItems.remove(0)");
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), true);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
+
+ // Request an item not instantiated by the view, then scroll the view so it will request it.
+ QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 16));
+ QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(16)")));
+ QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 16));
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
+
+ evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
+ QCOMPARE(listview->count(), 20);
+ evaluate<void>(delegate, "VisualDataModel.groups = [\"items\"]");
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
+
+ // Request and release an item instantiated by the view, then scroll the view so it releases it.
+ QVERIFY(findItem<QSGItem>(contentItem, "delegate", 17));
+ QVERIFY(delegate = qobject_cast<QSGItem *>(evaluate<QObject *>(visualModel, "items.create(17)")));
+ QCOMPARE(delegate, findItem<QSGItem>(contentItem, "delegate", 17));
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
+
+ evaluate<void>(visualModel, "items.removeGroups(17, \"persistedItems\")");
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false);
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0);
+ evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
+ QCOMPARE(listview->count(), 20);
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), true);
+
+ // Adding an item to the persistedItems group won't instantiate it, but if later requested by
+ // the view it will be persisted.
+ evaluate<void>(visualModel, "items.addGroups(18, \"persistedItems\")");
+ QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1);
+ QVERIFY(!findItem<QSGItem>(contentItem, "delegate", 18));
+ evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)");
+ QCOMPARE(listview->count(), 20);
+ QVERIFY(delegate = findItem<QSGItem>(contentItem, "delegate", 18));
+ QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true);
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
+ evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)");
+ QCOMPARE(listview->count(), 20);
+ QCOMPARE(evaluate<bool>(delegate, "destroyed"), false);
+}
+
template<typename T>
T *tst_qsgvisualdatamodel::findItem(QSGItem *parent, const QString &objectName, int index)
{