aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/declarative/modelviews/visualdatamodel/sortedmodel.qml141
-rw-r--r--examples/declarative/modelviews/visualdatamodel/visualdatamodel.qmlproject16
-rw-r--r--src/declarative/items/qsgvisualdatamodel.cpp246
-rw-r--r--src/declarative/items/qsgvisualdatamodel_p.h5
-rw-r--r--src/declarative/qml/v8/qv8engine_p.h2
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/data/groups.qml8
-rw-r--r--tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp235
7 files changed, 636 insertions, 17 deletions
diff --git a/examples/declarative/modelviews/visualdatamodel/sortedmodel.qml b/examples/declarative/modelviews/visualdatamodel/sortedmodel.qml
new file mode 100644
index 0000000000..2a72060422
--- /dev/null
+++ b/examples/declarative/modelviews/visualdatamodel/sortedmodel.qml
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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 {
+ width: 480; height: 640
+
+ Component {
+ id: numberDelegate
+
+ Text {
+ id: numberText
+ anchors { left: parent.left; right: parent.right }
+ text: number
+
+ horizontalAlignment: Text.AlignHCenter
+ font.pixelSize: 18
+
+ Text {
+ anchors { left: parent.left; baseline: parent.baseline }
+ text: index
+
+ horizontalAlignment: Text.AlignLeft
+ font.pixelSize: 12
+ }
+ Text {
+ anchors { right: parent.right; baseline: parent.baseline }
+ text: numberText.VisualDataModel.itemsIndex
+
+ horizontalAlignment: Text.AlignRight
+ font.pixelSize: 12
+ }
+ }
+ }
+
+ ListView {
+ anchors {
+ left: parent.left; top: parent.top;
+ right: parent.horizontalCenter; bottom: button.top
+ leftMargin: 2; topMargin: 2; rightMargin: 1; bottomMargin: 2
+ }
+
+ model: ListModel {
+ id: unsortedModel
+ }
+ delegate: numberDelegate
+ }
+ ListView {
+ anchors {
+ left: parent.horizontalCenter; top: parent.top;
+ right: parent.right; bottom: button.top
+ leftMargin: 1; topMargin: 2; rightMargin: 2; bottomMargin: 2
+ }
+ model: VisualDataModel {
+ model: unsortedModel
+ delegate: numberDelegate
+
+ items.onChanged: {
+ for (var i = 0; i < inserted.length; ++i) {
+ for (var j = inserted[i].index; j < inserted[i].index + inserted[i].count; ++j) {
+ var number = items.get(j).model.number
+ for (var l = 0, k = 0; l < unsortedModel.count; ++l) {
+ if (l == inserted[k].index) {
+ l += inserted[k].count - 1
+ ++k
+ } else if (number < items.get(l).model.number) {
+ items.move(j, l, 1)
+ break
+ }
+ }
+ inserted[i].index += 1;
+ inserted[i].count -= 1;
+ }
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: button
+
+ anchors { left: parent.left; right: parent.right; bottom: parent.bottom; margins: 2 }
+ height: moreText.implicitHeight + 4
+
+ color: "black"
+
+ Text {
+ id: moreText
+
+ anchors.fill: parent
+ text: "More"
+ color: "white"
+ font.pixelSize: 18
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+
+ onClicked: unsortedModel.append({ "number": Math.floor(Math.random() * 100) })
+ }
+ }
+}
diff --git a/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qmlproject b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/modelviews/visualdatamodel/visualdatamodel.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/src/declarative/items/qsgvisualdatamodel.cpp b/src/declarative/items/qsgvisualdatamodel.cpp
index 7793230f35..f5c86b8faf 100644
--- a/src/declarative/items/qsgvisualdatamodel.cpp
+++ b/src/declarative/items/qsgvisualdatamodel.cpp
@@ -290,28 +290,42 @@ QSGVisualDataModelParts::QSGVisualDataModelParts(QSGVisualDataModel *parent)
class QSGVisualDataModelCacheMetaType : public QDeclarativeRefCount
{
public:
- QSGVisualDataModelCacheMetaType(QSGVisualDataModel *model, const QStringList &groupNames);
+ QSGVisualDataModelCacheMetaType(QV8Engine *engine, QSGVisualDataModel *model, const QStringList &groupNames);
~QSGVisualDataModelCacheMetaType();
int parseGroups(const QStringList &groupNames) const;
int parseGroups(QV8Engine *engine, const v8::Local<v8::Value> &groupNames) const;
+ static v8::Handle<v8::Value> get_model(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_groups(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_groups(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_member(v8::Local<v8::String>, const v8::AccessorInfo &info);
+ static void set_member(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> get_index(v8::Local<v8::String>, const v8::AccessorInfo &info);
+
QDeclarativeGuard<QSGVisualDataModel> model;
const int groupCount;
const int memberPropertyOffset;
const int indexPropertyOffset;
+ QV8Engine * const v8Engine;
QMetaObject *metaObject;
const QStringList groupNames;
+ v8::Persistent<v8::Function> constructor;
};
-class QSGVisualDataModelCacheItem
+class QSGVisualDataModelCacheItem : public QV8ObjectResource
{
+ V8_RESOURCE_TYPE(VisualDataItemType)
public:
QSGVisualDataModelCacheItem(QSGVisualDataModelCacheMetaType *metaType)
- : metaType(metaType)
+ : QV8ObjectResource(metaType->v8Engine)
+ , metaType(metaType)
, object(0)
, attached(0)
, objectRef(0)
+ , scriptRef(0)
, groups(0)
{
metaType->addref();
@@ -319,6 +333,7 @@ public:
~QSGVisualDataModelCacheItem()
{
+ Q_ASSERT(scriptRef == 0);
Q_ASSERT(objectRef == 0);
Q_ASSERT(!object);
@@ -328,12 +343,15 @@ public:
void referenceObject() { ++objectRef; }
bool releaseObject() { return --objectRef == 0; }
- bool isReferenced() const { return objectRef; }
+ bool isReferenced() const { return objectRef || scriptRef; }
+
+ void Dispose();
QSGVisualDataModelCacheMetaType * const metaType;
QDeclarativeGuard<QObject> object;
QSGVisualDataModelAttached *attached;
int objectRef;
+ int scriptRef;
int groups;
int index[Compositor::MaximumGroupCount];
};
@@ -437,7 +455,8 @@ QSGVisualDataModel::~QSGVisualDataModel()
foreach (QSGVisualDataModelCacheItem *cacheItem, d->m_cache) {
cacheItem->object = 0;
cacheItem->objectRef = 0;
- delete cacheItem;
+ if (!cacheItem->isReferenced())
+ delete cacheItem;
}
delete d->m_adaptorModel;
@@ -483,7 +502,8 @@ void QSGVisualDataModel::componentComplete()
if (!d->m_context)
d->m_context = qmlContext(this);
- d->m_cacheMetaType = new QSGVisualDataModelCacheMetaType(this, groupNames);
+ d->m_cacheMetaType = new QSGVisualDataModelCacheMetaType(
+ QDeclarativeEnginePrivate::getV8Engine(d->m_context->engine()), this, groupNames);
d->m_compositor.setGroupCount(d->m_groupCount);
d->m_compositor.setDefaultGroups(defaultGroups);
@@ -681,10 +701,12 @@ QSGVisualDataModel::ReleaseFlags QSGVisualDataModelPrivate::release(QObject *obj
object->deleteLater();
cacheItem->object = 0;
stat |= QSGVisualModel::Destroyed;
- m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
- m_cache.removeAt(cacheIndex);
- delete cacheItem;
- Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ if (!cacheItem->isReferenced()) {
+ m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
+ m_cache.removeAt(cacheIndex);
+ delete cacheItem;
+ Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache));
+ }
} else {
stat |= QSGVisualDataModel::Referenced;
}
@@ -1390,11 +1412,12 @@ QSGVisualDataModelAttached *QSGVisualDataModel::qmlAttachedProperties(QObject *o
//============================================================================
QSGVisualDataModelCacheMetaType::QSGVisualDataModelCacheMetaType(
- QSGVisualDataModel *model, const QStringList &groupNames)
+ QV8Engine *engine, QSGVisualDataModel *model, const QStringList &groupNames)
: model(model)
, groupCount(groupNames.count() + 1)
, memberPropertyOffset(QSGVisualDataModelAttached::staticMetaObject.propertyCount())
, indexPropertyOffset(QSGVisualDataModelAttached::staticMetaObject.propertyCount() + groupNames.count())
+ , v8Engine(engine)
, metaObject(0)
, groupNames(groupNames)
{
@@ -1403,6 +1426,13 @@ QSGVisualDataModelCacheMetaType::QSGVisualDataModelCacheMetaType(
builder.setClassName(QSGVisualDataModelAttached::staticMetaObject.className());
builder.setSuperClass(&QSGVisualDataModelAttached::staticMetaObject);
+ v8::HandleScope handleScope;
+ v8::Context::Scope contextScope(engine->context());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("model"), get_model);
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("groups"), get_groups, set_groups);
+
int notifierId = 0;
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
QString propertyName = QStringLiteral("in") + groupNames.at(i);
@@ -1411,6 +1441,9 @@ QSGVisualDataModelCacheMetaType::QSGVisualDataModelCacheMetaType(
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
propertyName.toUtf8(), "bool", notifierId);
propertyBuilder.setWritable(true);
+
+ ft->PrototypeTemplate()->SetAccessor(
+ engine->toString(propertyName), get_member, set_member, v8::Int32::New(i + 1));
}
for (int i = 0; i < groupNames.count(); ++i, ++notifierId) {
const QString propertyName = groupNames.at(i) + QStringLiteral("Index");
@@ -1418,14 +1451,20 @@ QSGVisualDataModelCacheMetaType::QSGVisualDataModelCacheMetaType(
QMetaPropertyBuilder propertyBuilder = builder.addProperty(
propertyName.toUtf8(), "int", notifierId);
propertyBuilder.setWritable(true);
+
+ ft->PrototypeTemplate()->SetAccessor(
+ engine->toString(propertyName), get_index, 0, v8::Int32::New(i + 1));
}
metaObject = builder.toMetaObject();
+
+ constructor = qPersistentNew<v8::Function>(ft->GetFunction());
}
QSGVisualDataModelCacheMetaType::~QSGVisualDataModelCacheMetaType()
{
qFree(metaObject);
+ qPersistentDispose(constructor);
}
int QSGVisualDataModelCacheMetaType::parseGroups(const QStringList &groups) const
@@ -1459,6 +1498,135 @@ int QSGVisualDataModelCacheMetaType::parseGroups(QV8Engine *engine, const v8::Lo
return groupFlags;
}
+v8::Handle<v8::Value> QSGVisualDataModelCacheMetaType::get_model(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+ if (!cacheItem->metaType->model)
+ return v8::Undefined();
+ QObject *data = 0;
+
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(cacheItem->metaType->model);
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ Compositor::iterator it = model->m_compositor.find(
+ Compositor::Group(i), cacheItem->index[i]);
+ if (QSGVisualAdaptorModel *list = it.list<QSGVisualAdaptorModel>())
+ data = list->data(it.modelIndex());
+ break;
+ }
+ }
+ if (!data)
+ return v8::Undefined();
+ return cacheItem->engine->newQObject(data);
+}
+
+v8::Handle<v8::Value> QSGVisualDataModelCacheMetaType::get_groups(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ QStringList groups;
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i))
+ groups.append(cacheItem->metaType->groupNames.at(i - 1));
+ }
+
+ return cacheItem->engine->fromVariant(groups);
+}
+
+void QSGVisualDataModelCacheMetaType::set_groups(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR_SETTER("Not a valid VisualData object");
+
+ if (!cacheItem->metaType->model)
+ return;
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(cacheItem->metaType->model);
+
+ const int groupFlags = model->m_cacheMetaType->parseGroups(cacheItem->engine, value);
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ model->setGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlags);
+ break;
+ }
+ }
+}
+
+v8::Handle<v8::Value> QSGVisualDataModelCacheMetaType::get_member(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ return v8::Boolean::New(cacheItem->groups & (1 << info.Data()->Int32Value()));
+}
+
+void QSGVisualDataModelCacheMetaType::set_member(
+ v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR_SETTER("Not a valid VisualData object");
+
+ if (!cacheItem->metaType->model)
+ return;
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(cacheItem->metaType->model);
+
+ Compositor::Group group = Compositor::Group(info.Data()->Int32Value());
+ const bool member = value->BooleanValue();
+ const int groupFlag = (1 << group);
+ if (member == ((cacheItem->groups & groupFlag) != 0))
+ return;
+
+ for (int i = 1; i < cacheItem->metaType->groupCount; ++i) {
+ if (cacheItem->groups & (1 << i)) {
+ if (member)
+ model->addGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
+ else
+ model->removeGroups(Compositor::Group(i), cacheItem->index[i], 1, groupFlag);
+ break;
+ }
+ }
+}
+
+v8::Handle<v8::Value> QSGVisualDataModelCacheMetaType::get_index(
+ v8::Local<v8::String>, const v8::AccessorInfo &info)
+{
+ QSGVisualDataModelCacheItem *cacheItem = v8_resource_cast<QSGVisualDataModelCacheItem>(info.This());
+ if (!cacheItem)
+ V8THROW_ERROR("Not a valid VisualData object");
+
+ return v8::Integer::New(cacheItem->index[info.Data()->Int32Value()]);
+}
+
+
+//---------------------------------------------------------------------------
+
+void QSGVisualDataModelCacheItem::Dispose()
+{
+ --scriptRef;
+ if (isReferenced())
+ return;
+
+ if (metaType->model) {
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(metaType->model);
+ const int cacheIndex = model->m_cache.indexOf(this);
+ if (cacheIndex != -1) {
+ model->m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
+ model->m_cache.removeAt(cacheIndex);
+ }
+ }
+ delete this;
+}
+
//---------------------------------------------------------------------------
QSGVisualDataModelAttachedMetaObject::QSGVisualDataModelAttachedMetaObject(
@@ -1743,6 +1911,62 @@ void QSGVisualDataGroup::setDefaultInclude(bool include)
}
/*!
+ \qmlmethod var QtQuick2::VisualDataGroup::get(int index)
+
+ Returns a javascript object describing the item at \a index in the group.
+
+ The returned object contains the same information that is available to a delegate from the
+ VisualDataModel attached as well as the model for that item. It has the properties:
+
+ \list
+ \o \b model The model data of the item. This is the same as the model context property in
+ 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.
+ 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 {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.
+ \endlist
+*/
+
+QDeclarativeV8Handle QSGVisualDataGroup::get(int index)
+{
+ Q_D(QSGVisualDataGroup);
+ if (!d->model)
+ return QDeclarativeV8Handle::fromHandle(v8::Undefined());;
+
+ QSGVisualDataModelPrivate *model = QSGVisualDataModelPrivate::get(d->model);
+ if (index < 0 || index >= model->m_compositor.count(d->group)) {
+ qmlInfo(this) << tr("get: index out of range");
+ return QDeclarativeV8Handle::fromHandle(v8::Undefined());
+ }
+
+ Compositor::iterator it = model->m_compositor.find(d->group, index);
+ QSGVisualDataModelCacheItem *cacheItem = it->inCache()
+ ? model->m_cache.at(it.cacheIndex)
+ : 0;
+
+ if (!cacheItem) {
+ cacheItem = new QSGVisualDataModelCacheItem(model->m_cacheMetaType);
+ for (int i = 0; i < model->m_groupCount; ++i)
+ cacheItem->index[i] = it.index[i];
+ cacheItem->groups = it->flags & Compositor::GroupMask;
+
+ model->m_cache.insert(it.cacheIndex, cacheItem);
+ model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
+ }
+
+ ++cacheItem->scriptRef;
+
+ v8::Local<v8::Object> rv = model->m_cacheMetaType->constructor->NewInstance();
+ rv->SetExternalResource(cacheItem);
+ return QDeclarativeV8Handle::fromHandle(rv);
+}
+
+/*!
\qmlmethod QtQuick2::VisualDataGroup::remove(int index, int count)
Removes \a count items starting at \a index from the group.
diff --git a/src/declarative/items/qsgvisualdatamodel_p.h b/src/declarative/items/qsgvisualdatamodel_p.h
index 94640a65a0..9b4542d08a 100644
--- a/src/declarative/items/qsgvisualdatamodel_p.h
+++ b/src/declarative/items/qsgvisualdatamodel_p.h
@@ -50,6 +50,8 @@
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qstringlist.h>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_HEADER
Q_DECLARE_METATYPE(QModelIndex)
@@ -63,7 +65,6 @@ class QDeclarativeChangeSet;
class QDeclarativeComponent;
class QDeclarativePackage;
class QDeclarativeV8Function;
-class QDeclarativeV8Handle;
class QSGVisualDataGroup;
class QSGVisualDataModelAttached;
class QSGVisualDataModelPrivate;
@@ -161,6 +162,8 @@ public:
bool defaultInclude() const;
void setDefaultInclude(bool include);
+ Q_INVOKABLE QDeclarativeV8Handle get(int index);
+
public Q_SLOTS:
void remove(QDeclarativeV8Function *);
void addGroups(QDeclarativeV8Function *);
diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h
index 114584cdc2..185eb545ef 100644
--- a/src/declarative/qml/v8/qv8engine_p.h
+++ b/src/declarative/qml/v8/qv8engine_p.h
@@ -136,7 +136,7 @@ public:
enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType,
- ParticleDataType, SignalHandlerType, IncubatorType };
+ ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType };
virtual ResourceType resourceType() const = 0;
QV8Engine *engine;
diff --git a/tests/auto/declarative/qsgvisualdatamodel/data/groups.qml b/tests/auto/declarative/qsgvisualdatamodel/data/groups.qml
index 0189697a89..a24e223bc5 100644
--- a/tests/auto/declarative/qsgvisualdatamodel/data/groups.qml
+++ b/tests/auto/declarative/qsgvisualdatamodel/data/groups.qml
@@ -3,6 +3,14 @@ import QtQuick 2.0
ListView {
width: 100
height: 100
+
+ function contains(array, value) {
+ for (var i = 0; i < array.length; ++i)
+ if (array[i] == value)
+ return true
+ return false
+ }
+
model: VisualDataModel {
groups: [
VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true },
diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
index e8659bcf16..50e1b8f9df 100644
--- a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
+++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp
@@ -52,6 +52,7 @@
#include <private/qsgvisualdatamodel_p.h>
#include <private/qdeclarativevaluetype_p.h>
#include <private/qdeclarativechangeset_p.h>
+#include <private/qdeclarativeengine_p.h>
#include <math.h>
#include <QtOpenGL/QGLShaderProgram>
@@ -133,6 +134,7 @@ private slots:
void remove();
void move();
void groups();
+ void get();
private:
template <int N> void groups_verify(
@@ -145,6 +147,18 @@ private:
const bool (&vMember)[N],
const bool (&sMember)[N]);
+ template <int N> void get_verify(
+ const SingleRoleModel &model,
+ QSGVisualDataModel *visualModel,
+ QSGVisualDataGroup *visibleItems,
+ QSGVisualDataGroup *selectedItems,
+ const int (&mIndex)[N],
+ const int (&iIndex)[N],
+ const int (&vIndex)[N],
+ const int (&sIndex)[N],
+ const bool (&vMember)[N],
+ const bool (&sMember)[N]);
+
bool failed;
QDeclarativeEngine engine;
template<typename T>
@@ -203,13 +217,12 @@ private:
template <typename T> static T evaluate(QObject *scope, const QString &expression)
{
QDeclarativeExpression expr(qmlContext(scope), scope, expression);
- QVariant result = expr.evaluate();
+ T result = expr.evaluate().value<T>();
if (expr.hasError())
qWarning() << expr.error().toString();
- return result.value<T>();
+ return result;
}
-
template <> void evaluate<void>(QObject *scope, const QString &expression)
{
QDeclarativeExpression expr(qmlContext(scope), scope, expression);
@@ -218,7 +231,6 @@ template <> void evaluate<void>(QObject *scope, const QString &expression)
qWarning() << expr.error().toString();
}
-
tst_qsgvisualdatamodel::tst_qsgvisualdatamodel()
{
}
@@ -1183,6 +1195,221 @@ void tst_qsgvisualdatamodel::groups()
}
}
+template <int N> void tst_qsgvisualdatamodel::get_verify(
+ const SingleRoleModel &model,
+ QSGVisualDataModel *visualModel,
+ QSGVisualDataGroup *visibleItems,
+ QSGVisualDataGroup *selectedItems,
+ const int (&mIndex)[N],
+ const int (&iIndex)[N],
+ const int (&vIndex)[N],
+ const int (&sIndex)[N],
+ const bool (&vMember)[N],
+ const bool (&sMember)[N])
+{
+ failed = true;
+ for (int i = 0; i < N; ++i) {
+ QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.name").arg(i)), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<QString>(visualModel, QString("items.get(%1).model.modelData").arg(i)), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).model.index").arg(i)), mIndex[i]);
+ QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).itemsIndex").arg(i)), iIndex[i]);
+ QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inItems").arg(i)), true);
+ QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).visibleIndex").arg(i)), vIndex[i]);
+ QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inVisible").arg(i)), vMember[i]);
+ QCOMPARE(evaluate<int>(visualModel, QString("items.get(%1).selectedIndex").arg(i)), sIndex[i]);
+ QCOMPARE(evaluate<bool>(visualModel, QString("items.get(%1).inSelected").arg(i)), sMember[i]);
+ QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"items\")").arg(i)), true);
+ QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"visible\")").arg(i)), vMember[i]);
+ QCOMPARE(evaluate<bool>(visualModel, QString("contains(items.get(%1).groups, \"selected\")").arg(i)), sMember[i]);
+
+ if (vMember[i]) {
+ QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.name").arg(vIndex[i])), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<QString>(visibleItems, QString("get(%1).model.modelData").arg(vIndex[i])), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).model.index").arg(vIndex[i])), mIndex[i]);
+ QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).itemsIndex").arg(vIndex[i])), iIndex[i]);
+ QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inItems").arg(vIndex[i])), true);
+ QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).visibleIndex").arg(vIndex[i])), vIndex[i]);
+ QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inVisible").arg(vIndex[i])), vMember[i]);
+ QCOMPARE(evaluate<int>(visibleItems, QString("get(%1).selectedIndex").arg(vIndex[i])), sIndex[i]);
+ QCOMPARE(evaluate<bool>(visibleItems, QString("get(%1).inSelected").arg(vIndex[i])), sMember[i]);
+
+ QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"items\")").arg(vIndex[i])), true);
+ QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"visible\")").arg(vIndex[i])), vMember[i]);
+ QCOMPARE(evaluate<bool>(visibleItems, QString("contains(get(%1).groups, \"selected\")").arg(vIndex[i])), sMember[i]);
+ }
+ if (sMember[i]) {
+ QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.name").arg(sIndex[i])), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<QString>(selectedItems, QString("get(%1).model.modelData").arg(sIndex[i])), model.list.at(mIndex[i]));
+ QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).model.index").arg(sIndex[i])), mIndex[i]);
+ QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).itemsIndex").arg(sIndex[i])), iIndex[i]);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inItems").arg(sIndex[i])), true);
+ QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).visibleIndex").arg(sIndex[i])), vIndex[i]);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inVisible").arg(sIndex[i])), vMember[i]);
+ QCOMPARE(evaluate<int>(selectedItems, QString("get(%1).selectedIndex").arg(sIndex[i])), sIndex[i]);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("get(%1).inSelected").arg(sIndex[i])), sMember[i]);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"items\")").arg(sIndex[i])), true);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"visible\")").arg(sIndex[i])), vMember[i]);
+ QCOMPARE(evaluate<bool>(selectedItems, QString("contains(get(%1).groups, \"selected\")").arg(sIndex[i])), sMember[i]);
+ }
+ }
+ failed = false;
+}
+
+#define VERIFY_GET \
+ get_verify(model, visualModel, visibleItems, selectedItems, mIndex, iIndex, vIndex, sIndex, vMember, sMember); \
+ QVERIFY(!failed)
+
+void tst_qsgvisualdatamodel::get()
+{
+ QSGView view;
+
+ SingleRoleModel model;
+ model.list = QStringList()
+ << "one"
+ << "two"
+ << "three"
+ << "four"
+ << "five"
+ << "six"
+ << "seven"
+ << "eight"
+ << "nine"
+ << "ten"
+ << "eleven"
+ << "twelve";
+
+ QDeclarativeContext *ctxt = view.rootContext();
+ ctxt->setContextProperty("myModel", &model);
+
+ view.setSource(QUrl::fromLocalFile(SRCDIR "/data/groups.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);
+
+ QSGVisualDataGroup *visibleItems = visualModel->findChild<QSGVisualDataGroup *>("visibleItems");
+ QVERIFY(visibleItems);
+
+ QSGVisualDataGroup *selectedItems = visualModel->findChild<QSGVisualDataGroup *>("selectedItems");
+ QVERIFY(selectedItems);
+
+ QV8Engine *v8Engine = QDeclarativeEnginePrivate::getV8Engine(ctxt->engine());
+ QVERIFY(v8Engine);
+
+ const bool f = false;
+ const bool t = true;
+
+ {
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 12);
+ QCOMPARE(selectedItems->count(), 0);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ static const bool sMember[] = { f, f, f, f, f, f, f, f, f, f, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.addGroups(8, \"selected\")");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 12);
+ QCOMPARE(selectedItems->count(), 1);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 };
+ static const bool sMember[] = { f, f, f, f, f, f, f, f, t, f, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.addGroups(6, 4, [\"visible\", \"selected\"])");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 12);
+ QCOMPARE(selectedItems->count(), 4);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const bool vMember[] = { t, t, t, t, t, t, t, t, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4 };
+ static const bool sMember[] = { f, f, f, f, f, f, t, t, t, t, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.setGroups(2, [\"items\", \"selected\"])");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 11);
+ QCOMPARE(selectedItems->count(), 5);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9,10 };
+ static const bool vMember[] = { t, t, f, t, t, t, t, t, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 5, 5 };
+ static const bool sMember[] = { f, f, t, f, f, f, t, t, t, t, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(selectedItems, "setGroups(0, 3, \"items\")");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 9);
+ QCOMPARE(selectedItems->count(), 2);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
+ static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
+ static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.get(5).inVisible = false");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 8);
+ QCOMPARE(selectedItems->count(), 2);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
+ static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
+ static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.get(5).inSelected = true");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 8);
+ QCOMPARE(selectedItems->count(), 3);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 6, 7 };
+ static const bool vMember[] = { t, t, f, t, t, f, f, f, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3 };
+ static const bool sMember[] = { f, f, f, f, f, t, f, f, t, t, f, f };
+ VERIFY_GET;
+ } {
+ evaluate<void>(visualModel, "items.get(5).groups = [\"visible\", \"items\"]");
+ QCOMPARE(listview->count(), 12);
+ QCOMPARE(visualModel->items()->count(), 12);
+ QCOMPARE(visibleItems->count(), 9);
+ QCOMPARE(selectedItems->count(), 2);
+ static const int mIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int iIndex [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 };
+ static const int vIndex [] = { 0, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8 };
+ static const bool vMember[] = { t, t, f, t, t, t, f, f, t, t, t, t };
+ static const int sIndex [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2 };
+ static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f };
+ VERIFY_GET;
+ }
+}
+
template<typename T>
T *tst_qsgvisualdatamodel::findItem(QSGItem *parent, const QString &objectName, int index)
{