summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBea Lam <bea.lam@nokia.com>2010-03-02 02:07:40 (GMT)
committerBea Lam <bea.lam@nokia.com>2010-03-02 02:07:40 (GMT)
commit8da93faace82eb2bc86e76c0ad0a0c5c95e3b8bf (patch)
tree1559fc7e2fb0b983979d5e2d9abc53c16cede957
parent5bfe57bbd1e6055e9b2d70d0b4c28052fefce430 (diff)
downloadQt-8da93faace82eb2bc86e76c0ad0a0c5c95e3b8bf.zip
Qt-8da93faace82eb2bc86e76c0ad0a0c5c95e3b8bf.tar.gz
Qt-8da93faace82eb2bc86e76c0ad0a0c5c95e3b8bf.tar.bz2
Add docs and tests for WorkerListModel.
Task-number: QT-2807
-rw-r--r--doc/src/declarative/elements.qdoc2
-rw-r--r--examples/declarative/workerlistmodel/dataloader.js14
-rw-r--r--examples/declarative/workerlistmodel/timedisplay.qml33
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript.cpp137
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript_p.h9
-rw-r--r--tests/auto/declarative/qdeclarativeworkerlistmodel/data/model.qml14
-rw-r--r--tests/auto/declarative/qdeclarativeworkerlistmodel/data/script.js6
-rw-r--r--tests/auto/declarative/qdeclarativeworkerlistmodel/qdeclarativeworkerlistmodel.pro9
-rw-r--r--tests/auto/declarative/qdeclarativeworkerlistmodel/tst_qdeclarativeworkerlistmodel.cpp193
9 files changed, 414 insertions, 3 deletions
diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc
index 1fd4dad..6cca39b 100644
--- a/doc/src/declarative/elements.qdoc
+++ b/doc/src/declarative/elements.qdoc
@@ -91,6 +91,7 @@ The following table lists the QML elements provided by the Qt Declarative module
\o \l VisualDataModel
\o \l Package
\o \l XmlListModel and XmlRole
+\o \l WorkerListModel
\o \l DateTimeFormatter
\o \l NumberFormatter
\endlist
@@ -102,6 +103,7 @@ The following table lists the QML elements provided by the Qt Declarative module
\o \l Component
\o \l Timer
\o \l QtObject
+\o \l WorkerScript
\endlist
\endtable
diff --git a/examples/declarative/workerlistmodel/dataloader.js b/examples/declarative/workerlistmodel/dataloader.js
new file mode 100644
index 0000000..eac7478
--- /dev/null
+++ b/examples/declarative/workerlistmodel/dataloader.js
@@ -0,0 +1,14 @@
+// ![0]
+WorkerScript.onMessage = function(msg) {
+ console.log("Worker told to", msg.action);
+
+ if (msg.action == 'appendCurrentTime') {
+ var data = {'time': new Date().toTimeString()};
+ msg.model.append(data);
+ msg.model.sync(); // updates the changes to the list
+
+ var msgToSend = {'msg': 'Model updated!'};
+ WorkerScript.sendMessage(msgToSend);
+ }
+}
+// ![0]
diff --git a/examples/declarative/workerlistmodel/timedisplay.qml b/examples/declarative/workerlistmodel/timedisplay.qml
new file mode 100644
index 0000000..3bf2630
--- /dev/null
+++ b/examples/declarative/workerlistmodel/timedisplay.qml
@@ -0,0 +1,33 @@
+// ![0]
+import Qt 4.6
+
+ListView {
+ width: 200
+ height: 300
+
+ model: listModel
+ delegate: Component {
+ Text { text: time }
+ }
+
+ WorkerListModel { id: listModel }
+
+ WorkerScript {
+ id: worker
+ source: "dataloader.js"
+ onMessage: {
+ console.log("Worker said", messageObject.msg);
+ }
+ }
+
+ Timer {
+ id: timer
+ interval: 2000; repeat: true; running: true; triggeredOnStart: true
+
+ onTriggered: {
+ var msg = {'action': 'appendCurrentTime', 'model': listModel};
+ worker.sendMessage(msg);
+ }
+ }
+}
+// ![0]
diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp
index 03151e4..c1d090e 100644
--- a/src/declarative/qml/qdeclarativeworkerscript.cpp
+++ b/src/declarative/qml/qdeclarativeworkerscript.cpp
@@ -841,6 +841,41 @@ bool QDeclarativeWorkerListModelAgent::event(QEvent *e)
return QObject::event(e);
}
+/*!
+ \qmlclass WorkerListModel QDeclarativeWorkerListModel
+ \brief The WorkerListModel element provides a threaded list model.
+
+ Use WorkerListModel together with WorkerScript to define a list model
+ that is controlled by a separate thread. This is useful if list modification
+ operations are synchronous and take some time: using WorkerListModel
+ moves these operations to a different thread and avoids blocking of the
+ main GUI thread.
+
+ The thread that creates the WorkerListModel can modify the model for any
+ initial set-up requirements. However, once the model has been modified by
+ the associated WorkerScript, the model can only be modified by that worker
+ script and becomes read-only to all other threads.
+
+ Here is an example application that uses WorkerScript to append the
+ current time to a WorkerListModel:
+
+ \snippet examples/declarative/workerlistmodel/timedisplay.qml 0
+
+ The included file, \tt dataloader.js, looks like this:
+
+ \snippet examples/declarative/workerlistmodel/dataloader.js 0
+
+ The application's \tt Timer object periodically sends a message to the
+ worker script by calling \tt WorkerScript::sendMessage(). When this message
+ is received, \tt WorkerScript.onMessage() is invoked in
+ \tt dataloader.js, which appends the current time to the worker list
+ model.
+
+ Note that unlike ListModel, WorkerListModel does not have \tt move() and
+ \tt setProperty() methods.
+
+ \sa WorkerScript, ListModel
+*/
QDeclarativeWorkerListModel::QDeclarativeWorkerListModel(QObject *parent)
: QListModelInterface(parent), m_agent(0)
{
@@ -854,6 +889,14 @@ QDeclarativeWorkerListModel::~QDeclarativeWorkerListModel()
}
}
+/*!
+ \qmlmethod WorkerListModel::clear()
+
+ Deletes all content from the model. The properties are cleared such that
+ different properties may be set on subsequent additions.
+
+ \sa append() remove()
+*/
void QDeclarativeWorkerListModel::clear()
{
if (m_agent) {
@@ -869,6 +912,13 @@ void QDeclarativeWorkerListModel::clear()
}
}
+/*!
+ \qmlmethod WorkerListModel::remove(int index)
+
+ Deletes the content at \a index from the model.
+
+ \sa clear()
+*/
void QDeclarativeWorkerListModel::remove(int index)
{
if (m_agent) {
@@ -884,6 +934,18 @@ void QDeclarativeWorkerListModel::remove(int index)
emit countChanged();
}
+/*!
+ \qmlmethod WorkerListModel::append(jsobject dict)
+
+ Adds a new item to the end of the list model, with the
+ values in \a dict.
+
+ \code
+ FruitModel.append({"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ \sa set() remove()
+*/
void QDeclarativeWorkerListModel::append(const QScriptValue &value)
{
if (m_agent) {
@@ -914,6 +976,21 @@ void QDeclarativeWorkerListModel::append(const QScriptValue &value)
emit countChanged();
}
+/*!
+ \qmlmethod WorkerListModel::insert(int index, jsobject dict)
+
+ Adds a new item to the list model at position \a index, with the
+ values in \a dict.
+
+ \code
+ FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be to an existing item in the list, or one past
+ the end of the list (equivalent to append).
+
+ \sa set() append()
+*/
void QDeclarativeWorkerListModel::insert(int index, const QScriptValue &value)
{
if (m_agent) {
@@ -946,6 +1023,30 @@ void QDeclarativeWorkerListModel::insert(int index, const QScriptValue &value)
emit countChanged();
}
+/*!
+ \qmlmethod object ListModel::get(int index)
+
+ Returns the item at \a index in the list model.
+
+ \code
+ FruitModel.append({"cost": 5.95, "name":"Jackfruit"})
+ FruitModel.get(0).cost
+ \endcode
+
+ The \a index must be an element in the list.
+
+ Note that properties of the returned object that are themselves objects
+ will also be models, and this get() method is used to access elements:
+
+ \code
+ FruitModel.append(..., "attributes":
+ [{"name":"spikes","value":"7mm"},
+ {"name":"color","value":"green"}]);
+ FruitModel.get(0).attributes.get(1).value; // == "green"
+ \endcode
+
+ \sa append()
+*/
QScriptValue QDeclarativeWorkerListModel::get(int index) const
{
QDeclarativeEngine *engine = qmlEngine(this);
@@ -962,6 +1063,21 @@ QScriptValue QDeclarativeWorkerListModel::get(int index) const
return rv;
}
+/*!
+ \qmlmethod WorkerListModel::set(int index, jsobject dict)
+
+ Changes the item at \a index in the list model with the
+ values in \a dict. Properties not appearing in \a valuemap
+ are left unchanged.
+
+ \code
+ FruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be an element in the list.
+
+ \sa append()
+*/
void QDeclarativeWorkerListModel::set(int index, const QScriptValue &value)
{
if (m_agent) {
@@ -995,6 +1111,22 @@ void QDeclarativeWorkerListModel::set(int index, const QScriptValue &value)
}
}
+/*!
+ \qmlmethod WorkerListModel::sync()
+
+ Writes any unsaved changes to the list model. This must be called after
+ changes have been made to the list model in the worker script.
+
+ Note that this method can only be called from the associated worker script.
+*/
+void QDeclarativeWorkerListModel::sync()
+{
+ // This is really a dummy method to make it look like sync() exists in
+ // WorkerListModel (and not QDeclarativeWorkerListModelAgent) and to let
+ // us document sync().
+ qmlInfo(this) << "sync() can only be called from a WorkerScript";
+}
+
QDeclarativeWorkerListModelAgent *QDeclarativeWorkerListModel::agent()
{
if (!m_agent)
@@ -1013,6 +1145,10 @@ QString QDeclarativeWorkerListModel::toString(int role) const
return m_roles.value(role);
}
+/*!
+ \qmlproperty int ListModel::count
+ The number of data entries in the model.
+*/
int QDeclarativeWorkerListModel::count() const
{
return m_values.count();
@@ -1038,4 +1174,3 @@ QT_END_NAMESPACE
#include "qdeclarativeworkerscript.moc"
-
diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h
index 8ebd2c1..01cc72a 100644
--- a/src/declarative/qml/qdeclarativeworkerscript_p.h
+++ b/src/declarative/qml/qdeclarativeworkerscript_p.h
@@ -61,6 +61,8 @@
#include <QtScript/qscriptvalue.h>
#include <QtCore/qurl.h>
+QT_BEGIN_HEADER
+
QT_BEGIN_NAMESPACE
class QDeclarativeWorkerScript;
@@ -84,7 +86,7 @@ private:
QDeclarativeWorkerScriptEnginePrivate *d;
};
-class QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus
+class Q_DECLARATIVE_EXPORT QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
@@ -115,7 +117,7 @@ private:
};
class QDeclarativeWorkerListModelAgent;
-class QDeclarativeWorkerListModel : public QListModelInterface
+class Q_DECLARATIVE_EXPORT QDeclarativeWorkerListModel : public QListModelInterface
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
@@ -130,6 +132,7 @@ public:
Q_INVOKABLE void insert(int index, const QScriptValue&);
Q_INVOKABLE QScriptValue get(int index) const;
Q_INVOKABLE void set(int index, const QScriptValue &);
+ Q_INVOKABLE void sync();
QDeclarativeWorkerListModelAgent *agent();
@@ -157,4 +160,6 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QDeclarativeWorkerScript);
QML_DECLARE_TYPE(QDeclarativeWorkerListModel);
+QT_END_HEADER
+
#endif // QDECLARATIVEWORKERSCRIPT_P_H
diff --git a/tests/auto/declarative/qdeclarativeworkerlistmodel/data/model.qml b/tests/auto/declarative/qdeclarativeworkerlistmodel/data/model.qml
new file mode 100644
index 0000000..be94e00
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeworkerlistmodel/data/model.qml
@@ -0,0 +1,14 @@
+import Qt 4.6
+
+Item {
+ property alias model: model
+
+ WorkerListModel { id: model }
+
+ function workerModifyModel(cmd) { worker.sendMessage({'command': cmd, 'model': model}) }
+
+ WorkerScript {
+ id: worker
+ source: "script.js"
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeworkerlistmodel/data/script.js b/tests/auto/declarative/qdeclarativeworkerlistmodel/data/script.js
new file mode 100644
index 0000000..8ee62b4
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeworkerlistmodel/data/script.js
@@ -0,0 +1,6 @@
+WorkerScript.onMessage = function(msg) {
+ eval("msg.model." + msg.command)
+ msg.model.sync()
+}
+
+
diff --git a/tests/auto/declarative/qdeclarativeworkerlistmodel/qdeclarativeworkerlistmodel.pro b/tests/auto/declarative/qdeclarativeworkerlistmodel/qdeclarativeworkerlistmodel.pro
new file mode 100644
index 0000000..960dbe1
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeworkerlistmodel/qdeclarativeworkerlistmodel.pro
@@ -0,0 +1,9 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+QT += script
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qdeclarativeworkerlistmodel.cpp
+
+# Define SRCDIR equal to test's source directory
+DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/auto/declarative/qdeclarativeworkerlistmodel/tst_qdeclarativeworkerlistmodel.cpp b/tests/auto/declarative/qdeclarativeworkerlistmodel/tst_qdeclarativeworkerlistmodel.cpp
new file mode 100644
index 0000000..11a7447
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeworkerlistmodel/tst_qdeclarativeworkerlistmodel.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QtCore/qdebug.h>
+
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeitem.h>
+
+#include <private/qdeclarativeworkerscript_p.h>
+#include <private/qdeclarativelistmodel_p.h>
+#include "../../../shared/util.h"
+
+
+
+class tst_QDeclarativeWorkerListModel : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QDeclarativeWorkerListModel() {}
+private slots:
+ void clear();
+ void remove();
+ void append();
+ void insert();
+ void get();
+ void set();
+
+private:
+ QByteArray modificationWarning() const {
+ QString file = QUrl::fromLocalFile(SRCDIR "/data/model.qml").toString();
+ return QString("QML WorkerListModel (" + file + ":6:5) List can only be modified from a WorkerScript").toUtf8();
+ }
+
+ QDeclarativeEngine m_engine;
+};
+
+void tst_QDeclarativeWorkerListModel::clear()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QCOMPARE(model->count(), 0);
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "append({'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+
+ QTest::ignoreMessage(QtWarningMsg, modificationWarning().constData());
+ model->clear();
+ QCOMPARE(model->count(), 1);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "clear()")));
+ QTRY_COMPARE(model->count(), 0);
+
+ qApp->processEvents();
+}
+
+void tst_QDeclarativeWorkerListModel::remove()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "append({'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+
+ QTest::ignoreMessage(QtWarningMsg, modificationWarning().constData());
+ model->remove(0);
+ QCOMPARE(model->count(), 1);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "remove(0)")));
+ QTRY_COMPARE(model->count(), 0);
+
+ qApp->processEvents();
+}
+
+void tst_QDeclarativeWorkerListModel::append()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "append({'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+
+ QTest::ignoreMessage(QtWarningMsg, modificationWarning().constData());
+ model->append(QScriptValue(1));
+ QCOMPARE(model->count(), 1);
+
+ qApp->processEvents();
+}
+
+void tst_QDeclarativeWorkerListModel::insert()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "insert(0, {'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+
+ QTest::ignoreMessage(QtWarningMsg, modificationWarning().constData());
+ model->insert(0, QScriptValue(1));
+ QCOMPARE(model->count(), 1);
+
+ qApp->processEvents();
+}
+
+void tst_QDeclarativeWorkerListModel::get()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "append({'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+ QCOMPARE(model->get(0).property("name").toString(), QString("A"));
+
+ qApp->processEvents();
+}
+
+void tst_QDeclarativeWorkerListModel::set()
+{
+ QDeclarativeComponent component(&m_engine, SRCDIR "/data/model.qml");
+ QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(item != 0);
+ QDeclarativeWorkerListModel *model = item->property("model").value<QDeclarativeWorkerListModel*>();
+ QVERIFY(model != 0);
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "append({'name': 'A'})")));
+ QTRY_COMPARE(model->count(), 1);
+
+ QTest::ignoreMessage(QtWarningMsg, modificationWarning().constData());
+ model->set(0, QScriptValue(1));
+
+ QVERIFY(QMetaObject::invokeMethod(item, "workerModifyModel", Q_ARG(QVariant, "set(0, {'name': 'Z'})")));
+ QTRY_COMPARE(model->get(0).property("name").toString(), QString("Z"));
+
+ qApp->processEvents();
+}
+
+QTEST_MAIN(tst_QDeclarativeWorkerListModel)
+
+#include "tst_qdeclarativeworkerlistmodel.moc"
+