aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)
{