summaryrefslogtreecommitdiffstats
path: root/src/declarative/util
diff options
context:
space:
mode:
authorBea Lam <bea.lam@nokia.com>2010-03-16 01:16:13 (GMT)
committerBea Lam <bea.lam@nokia.com>2010-03-16 01:16:13 (GMT)
commit081fafe395d52ae42b57c36d1279e6ac05ae2cde (patch)
treebf1fa2e0478ed0ea89f5d03aa54555d724017d1b /src/declarative/util
parentdb0c932bf816b76547798ec62336e25b453d29b8 (diff)
downloadQt-081fafe395d52ae42b57c36d1279e6ac05ae2cde.zip
Qt-081fafe395d52ae42b57c36d1279e6ac05ae2cde.tar.gz
Qt-081fafe395d52ae42b57c36d1279e6ac05ae2cde.tar.bz2
Remove WorkerListModel and integrate its functionality into ListModel.
Task-number: QT-2829
Diffstat (limited to 'src/declarative/util')
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp954
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p.h21
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p_p.h199
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp245
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent_p.h155
-rw-r--r--src/declarative/util/util.pri7
6 files changed, 1273 insertions, 308 deletions
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
index e3f26d7..b290742 100644
--- a/src/declarative/util/qdeclarativelistmodel.cpp
+++ b/src/declarative/util/qdeclarativelistmodel.cpp
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#include "qdeclarativelistmodel_p.h"
-
+#include "qdeclarativelistmodel_p_p.h"
+#include "qdeclarativelistmodelworkeragent_p.h"
#include "qdeclarativeopenmetaobject_p.h"
#include <qdeclarativecustomparser_p.h>
@@ -66,8 +66,6 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM
return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData));
}
-static void dump(ModelNode *node, int ind);
-
/*!
\qmlclass ListModel QDeclarativeListModel
\since 4.7
@@ -193,253 +191,146 @@ static void dump(ModelNode *node, int ind);
except by first clearing the model - whatever properties are first added are then the
only permitted properties in the model.
- \sa {qmlmodels}{Data Models}
-*/
-
-class ModelObject : public QObject
-{
- Q_OBJECT
-public:
- ModelObject();
-
- void setValue(const QByteArray &name, const QVariant &val)
- {
- _mo->setValue(name, val);
- }
-private:
- QDeclarativeOpenMetaObject *_mo;
-};
+ \section2 Using threaded list models with WorkerScript
-struct ModelNode
-{
- ModelNode();
- ~ModelNode();
+ ListModel can be used together with WorkerScript to define a list model
+ that is accessible from multiple threads. This is useful if list
+ modifications are synchronous and take some time: the list operations can
+ be moved to a different thread to avoid blocking of the main GUI thread.
- QList<QVariant> values;
- QHash<QString, ModelNode *> properties;
+ Note that a list model is to be accessed from a WorkerScript, it \bold cannot
+ contain nested list data. So, this model cannot be used from a WorkerScript
+ because of the "attributes" value which contains a list:
- QDeclarativeListModel *model(const QDeclarativeListModel *parent) {
- if (!modelCache) {
- modelCache = new QDeclarativeListModel;
- QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(parent));
-
- modelCache->_root = this;
+ \code
+ ListModel {
+ id: fruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ attributes: [
+ ListElement { description: "Core" },
+ ListElement { description: "Deciduous" }
+ ]
}
- return modelCache;
}
+ \endcode
- ModelObject *object(const QDeclarativeListModel *parent) {
- if (!objectCache) {
- objectCache = new ModelObject();
- QHash<QString, ModelNode *>::iterator it;
- for (it = properties.begin(); it != properties.end(); ++it) {
- objectCache->setValue(it.key().toUtf8(), parent->valueForNode(*it));
- }
- }
- return objectCache;
- }
+ In addition, the WorkerScript cannot add any nested list data to the model.
- void setObjectValue(const QScriptValue& valuemap);
- void setListValue(const QScriptValue& valuelist);
+ \section3 Example
- void setProperty(const QString& prop, const QVariant& val) {
- QHash<QString, ModelNode *>::const_iterator it = properties.find(prop);
- if (it != properties.end()) {
- (*it)->values[0] = val;
- } else {
- ModelNode *n = new ModelNode;
- n->values << val;
- properties.insert(prop,n);
- }
- if (objectCache)
- objectCache->setValue(prop.toUtf8(), val);
- }
+ To use a list model from a worker script, pass the model to the script
+ through the onMessage() handler, make the list modifications, and call
+ sync() to save the changes to the model data.
- QDeclarativeListModel *modelCache;
- ModelObject *objectCache;
- bool isArray;
-};
+ Here is an example application that uses WorkerScript to append the
+ current time to a ListModel:
-QT_END_NAMESPACE
+ \snippet examples/declarative/listmodel-threaded/timedisplay.qml 0
-Q_DECLARE_METATYPE(ModelNode *)
+ The included file, \tt dataloader.js, looks like this:
-QT_BEGIN_NAMESPACE
+ \snippet examples/declarative/listmodel-threaded/dataloader.js 0
-void ModelNode::setObjectValue(const QScriptValue& valuemap) {
- QScriptValueIterator it(valuemap);
- while (it.hasNext()) {
- it.next();
- ModelNode *value = new ModelNode;
- QScriptValue v = it.value();
- if (v.isArray()) {
- value->isArray = true;
- value->setListValue(v);
- } else {
- value->values << v.toVariant();
- }
- properties.insert(it.name(),value);
- }
-}
-
-void ModelNode::setListValue(const QScriptValue& valuelist) {
- QScriptValueIterator it(valuelist);
- values.clear();
- while (it.hasNext()) {
- it.next();
- ModelNode *value = new ModelNode;
- QScriptValue v = it.value();
- if (v.isArray()) {
- value->isArray = true;
- value->setListValue(v);
- } else if (v.isObject()) {
- value->setObjectValue(v);
- } else {
- value->values << v.toVariant();
- }
- values.append(qVariantFromValue(value));
+ 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 list model.
- }
-}
+ \sa {qmlmodels}{Data Models}, WorkerScript
+*/
-ModelObject::ModelObject()
-: _mo(new QDeclarativeOpenMetaObject(this))
+QDeclarativeListModel::QDeclarativeListModel(QObject *parent)
+: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0), m_isWorkerCopy(false)
{
}
-QDeclarativeListModel::QDeclarativeListModel(QObject *parent)
-: QListModelInterface(parent), _rolesOk(false), _root(0)
+QDeclarativeListModel::QDeclarativeListModel(bool workerCopy, QObject *parent)
+: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0), m_isWorkerCopy(workerCopy)
{
+ if (workerCopy)
+ m_flat = new FlatListModel(this);
+ else
+ m_nested = new NestedListModel(this);
}
QDeclarativeListModel::~QDeclarativeListModel()
{
- delete _root;
+ delete m_nested;
+ delete m_flat;
}
-void QDeclarativeListModel::checkRoles() const
+bool QDeclarativeListModel::flatten()
{
- if (_rolesOk || !_root)
- return;
+ if (m_flat)
+ return true;
- for (int ii = 0; ii < _root->values.count(); ++ii) {
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(ii));
- if (node) {
- foreach (const QString &role, node->properties.keys())
- addRole(role);
- }
+ QList<int> roles = m_nested->roles();
+
+ QList<QHash<int, QVariant> > values;
+ bool hasNested = false;
+ for (int i=0; i<m_nested->count(); i++) {
+ values.append(m_nested->data(i, roles, &hasNested));
+ if (hasNested)
+ return false;
}
- _rolesOk = true;
+ FlatListModel *flat = new FlatListModel(this);
+ flat->m_values = values;
+
+ for (int i=0; i<roles.count(); i++) {
+ QString s = m_nested->toString(roles[i]);
+ flat->m_roles.insert(roles[i], s);
+ flat->m_strings.insert(s, roles[i]);
+ }
+
+ m_flat = flat;
+ delete m_nested;
+ m_nested = 0;
+ return true;
}
-void QDeclarativeListModel::addRole(const QString &role) const
+QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent()
{
- if (!roleStrings.contains(role))
- roleStrings << role;
+ if (m_agent)
+ return m_agent;
+
+ if (!flatten()) {
+ qmlInfo(this) << "List contains nested list values and cannot be used from a worker script";
+ return 0;
+ }
+
+ m_agent = new QDeclarativeListModelWorkerAgent(this);
+ return m_agent;
}
QList<int> QDeclarativeListModel::roles() const
{
- checkRoles();
- QList<int> rv;
- for (int ii = 0; ii < roleStrings.count(); ++ii)
- rv << ii;
- return rv;
+ return m_flat ? m_flat->roles() : m_nested->roles();
}
QString QDeclarativeListModel::toString(int role) const
{
- checkRoles();
- if (role < roleStrings.count())
- return roleStrings.at(role);
- else
- return QString();
-}
-
-QVariant QDeclarativeListModel::valueForNode(ModelNode *node) const
-{
- QObject *rv = 0;
-
- if (node->isArray) {
- // List
- rv = node->model(this);
- } else {
- if (!node->properties.isEmpty()) {
- // Object
- rv = node->object(this);
- } else if (node->values.count() == 0) {
- // Invalid
- return QVariant();
- } else if (node->values.count() == 1) {
- // Value
- QVariant &var = node->values[0];
- ModelNode *valueNode = qvariant_cast<ModelNode *>(var);
- if (valueNode) {
- if (!valueNode->properties.isEmpty())
- rv = valueNode->object(this);
- else
- rv = valueNode->model(this);
- } else {
- return var;
- }
- }
- }
-
- if (rv)
- return QVariant::fromValue(rv);
- else
- return QVariant();
+ return m_flat ? m_flat->toString(role) : m_nested->toString(role);
}
QHash<int,QVariant> QDeclarativeListModel::data(int index, const QList<int> &roles) const
{
- checkRoles();
- QHash<int, QVariant> rv;
if (index >= count() || index < 0)
- return rv;
-
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- if (!node)
- return rv;
-
- for (int ii = 0; ii < roles.count(); ++ii) {
- const QString &roleString = roleStrings.at(roles.at(ii));
+ return QHash<int, QVariant>();
- QHash<QString, ModelNode *>::ConstIterator iter =
- node->properties.find(roleString);
- if (iter != node->properties.end()) {
- ModelNode *row = *iter;
- rv.insert(roles.at(ii), valueForNode(row));
- }
- }
-
- return rv;
+ return m_flat ? m_flat->data(index, roles) : m_nested->data(index, roles);
}
QVariant QDeclarativeListModel::data(int index, int role) const
{
- checkRoles();
- QVariant rv;
if (index >= count() || index < 0)
- return rv;
-
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- if (!node)
- return rv;
-
- const QString &roleString = roleStrings.at(role);
-
- QHash<QString, ModelNode *>::ConstIterator iter =
- node->properties.find(roleString);
- if (iter != node->properties.end()) {
- ModelNode *row = *iter;
- rv = valueForNode(row);
- }
+ return QVariant();
- return rv;
+ return m_flat ? m_flat->data(index, role) : m_nested->data(index, role);
}
/*!
@@ -448,8 +339,7 @@ QVariant QDeclarativeListModel::data(int index, int role) const
*/
int QDeclarativeListModel::count() const
{
- if (!_root) return 0;
- return _root->values.count();
+ return m_flat ? m_flat->count() : m_nested->count();
}
/*!
@@ -463,12 +353,15 @@ int QDeclarativeListModel::count() const
void QDeclarativeListModel::clear()
{
int cleared = count();
- _rolesOk = false;
- delete _root;
- _root = 0;
- roleStrings.clear();
- emit itemsRemoved(0,cleared);
- emit countChanged(0);
+ if (m_flat)
+ m_flat->clear();
+ else
+ m_nested->clear();
+
+ if (!m_isWorkerCopy) {
+ emit itemsRemoved(0, cleared);
+ emit countChanged(0);
+ }
}
/*!
@@ -480,17 +373,18 @@ void QDeclarativeListModel::clear()
*/
void QDeclarativeListModel::remove(int index)
{
- if (!_root || index < 0 || index >= _root->values.count()) {
+ if (index < 0 || index >= count()) {
qmlInfo(this) << tr("remove: index %1 out of range").arg(index);
return;
}
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- _root->values.removeAt(index);
- if (node)
- delete node;
- emit itemsRemoved(index,1);
- emit countChanged(_root->values.count());
+ if (m_flat)
+ m_flat->remove(index);
+ else
+ m_nested->remove(index);
+
+ if (!m_isWorkerCopy)
+ emit countChanged(this->count());
}
/*!
@@ -514,20 +408,17 @@ void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap)
qmlInfo(this) << tr("insert: value is not an object");
return;
}
- if (!_root)
- _root = new ModelNode;
- if (index >= _root->values.count() || index<0) {
- if (index == _root->values.count())
- append(valuemap);
- else
- qmlInfo(this) << tr("insert: index %1 out of range").arg(index);
+
+ if (index < 0 || index > count()) {
+ qmlInfo(this) << tr("insert: index %1 out of range").arg(index);
return;
}
- ModelNode *mn = new ModelNode;
- mn->setObjectValue(valuemap);
- _root->values.insert(index,qVariantFromValue(mn));
- emit itemsInserted(index,1);
- emit countChanged(_root->values.count());
+
+ bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap);
+ if (ok && !m_isWorkerCopy) {
+ emit itemsInserted(index, 1);
+ emit countChanged(this->count());
+ }
}
/*!
@@ -552,9 +443,10 @@ void QDeclarativeListModel::move(int from, int to, int n)
qmlInfo(this) << tr("move: out of range");
return;
}
- int origfrom=from; // preserve actual move, so any animations are correct
- int origto=to;
- int orign=n;
+
+ int origfrom = from;
+ int origto = to;
+ int orign = n;
if (from > to) {
// Only move forwards - flip if backwards moving
int tfrom = from;
@@ -563,24 +455,14 @@ void QDeclarativeListModel::move(int from, int to, int n)
to = tto+n;
n = tfrom-tto;
}
- if (n==1) {
- _root->values.move(from,to);
- } else {
- QList<QVariant> replaced;
- int i=0;
- QVariantList::const_iterator it=_root->values.begin(); it += from+n;
- for (; i<to-from; ++i,++it)
- replaced.append(*it);
- i=0;
- it=_root->values.begin(); it += from;
- for (; i<n; ++i,++it)
- replaced.append(*it);
- QVariantList::const_iterator f=replaced.begin();
- QVariantList::iterator t=_root->values.begin(); t += from;
- for (; f != replaced.end(); ++f, ++t)
- *t = *f;
- }
- emit itemsMoved(origfrom,origto,orign);
+
+ if (m_flat)
+ m_flat->move(from, to, n);
+ else
+ m_nested->move(from, to, n);
+
+ if (!m_isWorkerCopy)
+ emit itemsMoved(origfrom, origto, orign);
}
/*!
@@ -601,13 +483,8 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap)
qmlInfo(this) << tr("append: value is not an object");
return;
}
- if (!_root)
- _root = new ModelNode;
- ModelNode *mn = new ModelNode;
- mn->setObjectValue(valuemap);
- _root->values << qVariantFromValue(mn);
- emit itemsInserted(count()-1,1);
- emit countChanged(_root->values.count());
+
+ insert(count(), valuemap);
}
/*!
@@ -641,15 +518,7 @@ QScriptValue QDeclarativeListModel::get(int index) const
return 0;
}
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- if (!node)
- return 0;
- QDeclarativeEngine *eng = qmlEngine(this);
- if (!eng) {
- qWarning("Cannot call QDeclarativeListModel::get() without a QDeclarativeEngine");
- return 0;
- }
- return QDeclarativeEnginePrivate::qmlScriptObject(node->object(this), eng);
+ return m_flat ? m_flat->get(index) : m_nested->get(index);
}
/*!
@@ -673,27 +542,22 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
qmlInfo(this) << tr("set: value is not an object");
return;
}
- if ( !_root || index > _root->values.count() || index < 0) {
+ if (count() == 0 || index > count() || index < 0) {
qmlInfo(this) << tr("set: index %1 out of range").arg(index);
return;
}
- if (index == _root->values.count())
+
+ if (index == count()) {
append(valuemap);
- else {
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ } else {
QList<int> roles;
- node->setObjectValue(valuemap);
- QScriptValueIterator it(valuemap);
- while (it.hasNext()) {
- it.next();
- int r = roleStrings.indexOf(it.name());
- if (r<0) {
- r = roleStrings.count();
- roleStrings << it.name();
- }
- roles.append(r);
- }
- emit itemsChanged(index,1,roles);
+ if (m_flat)
+ m_flat->set(index, valuemap, &roles);
+ else
+ m_nested->set(index, valuemap, &roles);
+
+ if (!m_isWorkerCopy)
+ emit itemsChanged(index, 1, roles);
}
}
@@ -712,22 +576,33 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
*/
void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value)
{
- if ( !_root || index >= _root->values.count() || index < 0) {
+ if (count() == 0 || index >= count() || index < 0) {
qmlInfo(this) << tr("set: index %1 out of range").arg(index);
return;
}
- ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- int r = roleStrings.indexOf(property);
- if (r<0) {
- r = roleStrings.count();
- roleStrings << property;
- }
+
QList<int> roles;
- roles.append(r);
+ if (m_flat)
+ m_flat->setProperty(index, property, value, &roles);
+ else
+ m_nested->setProperty(index, property, value, &roles);
- if (node)
- node->setProperty(property,value);
- emit itemsChanged(index,1,roles);
+ if (!m_isWorkerCopy)
+ emit itemsChanged(index, 1, roles);
+}
+
+/*!
+ \qmlmethod ListModel::sync()
+
+ Writes any unsaved changes to the list model after it has been modified
+ from a worker script.
+*/
+void QDeclarativeListModel::sync()
+{
+ // This is just a dummy method to make it look like sync() exists in
+ // ListModel (and not just QDeclarativeListModelWorkerAgent) and to let
+ // us document sync().
+ qmlInfo(this) << "List sync() can only be called from a WorkerScript";
}
bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data)
@@ -858,7 +733,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &
QDeclarativeListModel *rv = static_cast<QDeclarativeListModel *>(obj);
ModelNode *root = new ModelNode;
- rv->_root = root;
+ rv->m_nested->_root = root;
QStack<ModelNode *> nodes;
nodes << root;
@@ -943,7 +818,491 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s)
\sa ListModel
*/
-static void dump(ModelNode *node, int ind)
+FlatListModel::FlatListModel(QDeclarativeListModel *base)
+ : m_scriptEngine(0), m_listModel(base)
+{
+}
+
+FlatListModel::~FlatListModel()
+{
+}
+
+QHash<int,QVariant> FlatListModel::data(int index, const QList<int> &roles) const
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QHash<int, QVariant> row;
+ for (int i=0; i<roles.count(); i++) {
+ int role = roles[i];
+ if (m_values[index].contains(role))
+ row.insert(role, m_values[index][role]);
+ }
+ return row;
+}
+
+QVariant FlatListModel::data(int index, int role) const
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+ if (m_values[index].contains(role))
+ return m_values[index][role];
+ return QVariant();
+}
+
+QList<int> FlatListModel::roles() const
+{
+ return m_roles.keys();
+}
+
+QString FlatListModel::toString(int role) const
+{
+ if (m_roles.contains(role))
+ return m_roles[role];
+ return QString();
+}
+
+int FlatListModel::count() const
+{
+ return m_values.count();
+}
+
+void FlatListModel::clear()
+{
+ m_values.clear();
+}
+
+void FlatListModel::remove(int index)
+{
+ m_values.removeAt(index);
+}
+
+bool FlatListModel::append(const QScriptValue &value)
+{
+ return insert(m_values.count(), value);
+}
+
+bool FlatListModel::insert(int index, const QScriptValue &value)
+{
+ Q_ASSERT(index >= 0 && index <= m_values.count());
+
+ QHash<int, QVariant> row;
+ if (!addValue(value, &row, 0))
+ return false;
+
+ m_values.insert(index, row);
+ return true;
+}
+
+QScriptValue FlatListModel::get(int index) const
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QScriptEngine *scriptEngine = m_scriptEngine ? m_scriptEngine : QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(m_listModel));
+
+ if (!scriptEngine)
+ return 0;
+
+ QScriptValue rv = scriptEngine->newObject();
+
+ QHash<int, QVariant> row = m_values.at(index);
+ for (QHash<int, QVariant>::ConstIterator iter = row.begin(); iter != row.end(); ++iter)
+ rv.setProperty(m_roles.value(iter.key()), qScriptValueFromValue(scriptEngine, iter.value()));
+
+ return rv;
+}
+
+void FlatListModel::set(int index, const QScriptValue &value, QList<int> *roles)
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QHash<int, QVariant> row = m_values[index];
+ if (addValue(value, &row, roles))
+ m_values[index] = row;
+}
+
+void FlatListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
+ Q_ASSERT(index >= 0 && index < m_values.count());
+
+ QHash<QString, int>::Iterator iter = m_strings.find(property);
+ int role;
+ if (iter == m_strings.end()) {
+ role = m_roles.count();
+ m_roles.insert(role, property);
+ m_strings.insert(property, role);
+ } else {
+ role = iter.value();
+ }
+ roles->append(role);
+
+ m_values[index][role] = value;
+}
+
+void FlatListModel::move(int from, int to, int n)
+{
+ if (n == 1) {
+ m_values.move(from, to);
+ } else {
+ QList<QHash<int, QVariant> > replaced;
+ int i=0;
+ QList<QHash<int, QVariant> >::ConstIterator it=m_values.begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=m_values.begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ QList<QHash<int, QVariant> >::ConstIterator f=replaced.begin();
+ QList<QHash<int, QVariant> >::Iterator t=m_values.begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+}
+
+bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles)
+{
+ QScriptValueIterator it(value);
+ while (it.hasNext()) {
+ it.next();
+ if (it.value().isObject()) {
+ qmlInfo(m_listModel) << "Cannot add nested list values when modifying or after modification from a worker script";
+ return false;
+ }
+
+ QString name = it.name();
+ QVariant v = it.value().toVariant();
+
+ QHash<QString, int>::Iterator iter = m_strings.find(name);
+ if (iter == m_strings.end()) {
+ int role = m_roles.count();
+ m_roles.insert(role, name);
+ iter = m_strings.insert(name, role);
+ if (roles)
+ roles->append(role);
+ }
+ row->insert(*iter, v);
+ }
+ return true;
+}
+
+NestedListModel::NestedListModel(QDeclarativeListModel *base)
+ : _root(0), m_listModel(base), _rolesOk(false)
+{
+}
+
+NestedListModel::~NestedListModel()
+{
+ delete _root;
+}
+
+QVariant NestedListModel::valueForNode(ModelNode *node, bool *hasNested) const
+{
+ QObject *rv = 0;
+ if (hasNested)
+ *hasNested = false;
+
+ if (node->isArray) {
+ // List
+ rv = node->model(this);
+ if (hasNested)
+ *hasNested = true;
+ } else {
+ if (!node->properties.isEmpty()) {
+ // Object
+ rv = node->object(this);
+ } else if (node->values.count() == 0) {
+ // Invalid
+ return QVariant();
+ } else if (node->values.count() == 1) {
+ // Value
+ QVariant &var = node->values[0];
+ ModelNode *valueNode = qvariant_cast<ModelNode *>(var);
+ if (valueNode) {
+ if (!valueNode->properties.isEmpty())
+ rv = valueNode->object(this);
+ else
+ rv = valueNode->model(this);
+ } else {
+ return var;
+ }
+ }
+ }
+
+ if (rv) {
+ return QVariant::fromValue(rv);
+ } else {
+ return QVariant();
+ }
+}
+
+QHash<int,QVariant> NestedListModel::data(int index, const QList<int> &roles, bool *hasNested) const
+{
+ Q_ASSERT(_root && index >= 0 && index < _root->values.count());
+ checkRoles();
+ QHash<int, QVariant> rv;
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return rv;
+
+ for (int ii = 0; ii < roles.count(); ++ii) {
+ const QString &roleString = roleStrings.at(roles.at(ii));
+
+ QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString);
+ if (iter != node->properties.end()) {
+ ModelNode *row = *iter;
+ rv.insert(roles.at(ii), valueForNode(row, hasNested));
+ }
+ }
+
+ return rv;
+}
+
+QVariant NestedListModel::data(int index, int role) const
+{
+ Q_ASSERT(_root && index >= 0 && index < _root->values.count());
+ checkRoles();
+ QVariant rv;
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return rv;
+
+ const QString &roleString = roleStrings.at(role);
+
+ QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString);
+ if (iter != node->properties.end()) {
+ ModelNode *row = *iter;
+ rv = valueForNode(row);
+ }
+
+ return rv;
+}
+
+int NestedListModel::count() const
+{
+ if (!_root) return 0;
+ return _root->values.count();
+}
+
+void NestedListModel::clear()
+{
+ _rolesOk = false;
+ roleStrings.clear();
+
+ delete _root;
+ _root = 0;
+}
+
+void NestedListModel::remove(int index)
+{
+ if (!_root)
+ return;
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ _root->values.removeAt(index);
+ if (node)
+ delete node;
+}
+
+bool NestedListModel::insert(int index, const QScriptValue& valuemap)
+{
+ if (!_root)
+ _root = new ModelNode;
+
+ ModelNode *mn = new ModelNode;
+ mn->setObjectValue(valuemap);
+ _root->values.insert(index,qVariantFromValue(mn));
+ return true;
+}
+
+void NestedListModel::move(int from, int to, int n)
+{
+ if (n==1) {
+ _root->values.move(from,to);
+ } else {
+ QList<QVariant> replaced;
+ int i=0;
+ QVariantList::const_iterator it=_root->values.begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=_root->values.begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ QVariantList::const_iterator f=replaced.begin();
+ QVariantList::iterator t=_root->values.begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+}
+
+bool NestedListModel::append(const QScriptValue& valuemap)
+{
+ if (!_root)
+ _root = new ModelNode;
+ ModelNode *mn = new ModelNode;
+ mn->setObjectValue(valuemap);
+ _root->values << qVariantFromValue(mn);
+ return true;
+}
+
+QScriptValue NestedListModel::get(int index) const
+{
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return 0;
+ QDeclarativeEngine *eng = qmlEngine(m_listModel);
+ if (!eng) {
+ qWarning("Cannot call QDeclarativeListModel::get() without a QDeclarativeEngine");
+ return 0;
+ }
+ return QDeclarativeEnginePrivate::qmlScriptObject(node->object(this), eng);
+}
+
+void NestedListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+{
+ Q_ASSERT(index >=0 && index < count());
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ node->setObjectValue(valuemap);
+
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ int r = roleStrings.indexOf(it.name());
+ if (r < 0) {
+ r = roleStrings.count();
+ roleStrings << it.name();
+ }
+ roles->append(r);
+ }
+}
+
+void NestedListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
+ Q_ASSERT(index >=0 && index < count());
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ node->setProperty(property, value);
+
+ int r = roleStrings.indexOf(property);
+ if (r < 0) {
+ r = roleStrings.count();
+ roleStrings << property;
+ }
+ roles->append(r);
+}
+
+void NestedListModel::checkRoles() const
+{
+ if (_rolesOk || !_root)
+ return;
+
+ for (int i = 0; i<_root->values.count(); ++i) {
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i));
+ if (node) {
+ foreach (const QString &role, node->properties.keys()) {
+ if (!roleStrings.contains(role))
+ roleStrings.append(role);
+ }
+ }
+ }
+
+ _rolesOk = true;
+}
+
+QList<int> NestedListModel::roles() const
+{
+ checkRoles();
+ QList<int> rv;
+ for (int ii = 0; ii < roleStrings.count(); ++ii)
+ rv << ii;
+ return rv;
+}
+
+QString NestedListModel::toString(int role) const
+{
+ checkRoles();
+ if (role < roleStrings.count())
+ return roleStrings.at(role);
+ else
+ return QString();
+}
+
+
+ModelNode::ModelNode()
+: modelCache(0), objectCache(0), isArray(false)
+{
+}
+
+ModelNode::~ModelNode()
+{
+ ModelNode *node;
+
+ QList<ModelNode *> nodeValues = properties.values();
+ for (int ii = 0; ii < nodeValues.count(); ++ii) {
+ node = nodeValues[ii];
+ if (node) { delete node; node = 0; }
+ }
+
+ for (int ii = 0; ii < values.count(); ++ii) {
+ node = qvariant_cast<ModelNode *>(values.at(ii));
+ if (node) { delete node; node = 0; }
+ }
+
+ if (modelCache) { modelCache->m_nested->_root = 0/* ==this */; delete modelCache; modelCache = 0; }
+ if (objectCache) { delete objectCache; objectCache = 0; }
+}
+
+void ModelNode::setObjectValue(const QScriptValue& valuemap) {
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ ModelNode *value = new ModelNode;
+ QScriptValue v = it.value();
+ if (v.isArray()) {
+ value->isArray = true;
+ value->setListValue(v);
+ } else {
+ value->values << v.toVariant();
+ }
+ properties.insert(it.name(),value);
+ }
+}
+
+void ModelNode::setListValue(const QScriptValue& valuelist) {
+ QScriptValueIterator it(valuelist);
+ values.clear();
+ while (it.hasNext()) {
+ it.next();
+ ModelNode *value = new ModelNode;
+ QScriptValue v = it.value();
+ if (v.isArray()) {
+ value->isArray = true;
+ value->setListValue(v);
+ } else if (v.isObject()) {
+ value->setObjectValue(v);
+ } else {
+ value->values << v.toVariant();
+ }
+ values.append(qVariantFromValue(value));
+
+ }
+}
+
+void ModelNode::setProperty(const QString& prop, const QVariant& val) {
+ QHash<QString, ModelNode *>::const_iterator it = properties.find(prop);
+ if (it != properties.end()) {
+ (*it)->values[0] = val;
+ } else {
+ ModelNode *n = new ModelNode;
+ n->values << val;
+ properties.insert(prop,n);
+ }
+ if (objectCache)
+ objectCache->setValue(prop.toUtf8(), val);
+}
+
+void ModelNode::dump(ModelNode *node, int ind)
{
QByteArray indentBa(ind * 4, ' ');
const char *indent = indentBa.constData();
@@ -964,22 +1323,17 @@ static void dump(ModelNode *node, int ind)
}
}
-ModelNode::ModelNode()
-: modelCache(0), objectCache(0), isArray(false)
+ModelObject::ModelObject()
+: _mo(new QDeclarativeOpenMetaObject(this))
{
}
-ModelNode::~ModelNode()
+void ModelObject::setValue(const QByteArray &name, const QVariant &val)
{
- qDeleteAll(properties);
- for (int ii = 0; ii < values.count(); ++ii) {
- ModelNode *node = qvariant_cast<ModelNode *>(values.at(ii));
- if (node) { delete node; node = 0; }
- }
- if (modelCache) { modelCache->_root = 0/* ==this */; delete modelCache; modelCache = 0; }
- if (objectCache) { delete objectCache; }
+ _mo->setValue(name, val);
}
+
QT_END_NAMESPACE
#include <qdeclarativelistmodel.moc>
diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h
index 8eb6583..6a0426b 100644
--- a/src/declarative/util/qdeclarativelistmodel_p.h
+++ b/src/declarative/util/qdeclarativelistmodel_p.h
@@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class FlatListModel;
+class NestedListModel;
+class QDeclarativeListModelWorkerAgent;
struct ModelNode;
class Q_DECLARATIVE_EXPORT QDeclarativeListModel : public QListModelInterface
{
@@ -83,20 +86,26 @@ public:
Q_INVOKABLE void set(int index, const QScriptValue&);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ QDeclarativeListModelWorkerAgent *agent();
Q_SIGNALS:
void countChanged(int);
private:
- QVariant valueForNode(ModelNode *) const;
- mutable QStringList roleStrings;
friend class QDeclarativeListModelParser;
+ friend class QDeclarativeListModelWorkerAgent;
friend struct ModelNode;
- void checkRoles() const;
- void addRole(const QString &) const;
- mutable bool _rolesOk;
- ModelNode *_root;
+ QDeclarativeListModel(bool workerCopy, QObject *parent=0);
+ bool flatten();
+ bool modifyCheck();
+
+ QDeclarativeListModelWorkerAgent *m_agent;
+ NestedListModel *m_nested;
+ FlatListModel *m_flat;
+ bool m_isWorkerCopy;
};
// ### FIXME
diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h
new file mode 100644
index 0000000..8041561
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodel_p_p.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELISTMODEL_P_P_H
+#define QDECLARATIVELISTMODEL_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdeclarativelistmodel_p.h"
+
+#include "qdeclarative.h"
+#include "qdeclarativeengine_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeOpenMetaObject;
+class QScriptEngine;
+class QDeclarativeListModelWorkerAgent;
+struct ModelNode;
+
+class FlatListModel
+{
+public:
+ FlatListModel(QDeclarativeListModel *base);
+ ~FlatListModel();
+
+ QHash<int,QVariant> data(int index, const QList<int> &roles) const;
+ QVariant data(int index, int role) const;
+
+ QList<int> roles() const;
+ QString toString(int role) const;
+
+ int count() const;
+ void clear();
+ void remove(int index);
+ bool append(const QScriptValue&);
+ bool insert(int index, const QScriptValue&);
+ QScriptValue get(int index) const;
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
+ void move(int from, int to, int count);
+
+private:
+ friend class QDeclarativeListModelWorkerAgent;
+ friend class QDeclarativeListModel;
+
+ bool addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles);
+
+ QScriptEngine *m_scriptEngine;
+ QHash<int, QString> m_roles;
+ QHash<QString, int> m_strings;
+ QList<QHash<int, QVariant> > m_values;
+ QDeclarativeListModel *m_listModel;
+};
+
+class NestedListModel
+{
+public:
+ NestedListModel(QDeclarativeListModel *base);
+ ~NestedListModel();
+
+ QHash<int,QVariant> data(int index, const QList<int> &roles, bool *hasNested = 0) const;
+ QVariant data(int index, int role) const;
+
+ QList<int> roles() const;
+ QString toString(int role) const;
+
+ int count() const;
+ void clear();
+ void remove(int index);
+ bool append(const QScriptValue&);
+ bool insert(int index, const QScriptValue&);
+ QScriptValue get(int index) const;
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *role);
+ void move(int from, int to, int count);
+
+ QVariant valueForNode(ModelNode *, bool *hasNested = 0) const;
+ void checkRoles() const;
+
+ ModelNode *_root;
+ QDeclarativeListModel *m_listModel;
+
+private:
+ mutable QStringList roleStrings;
+ mutable bool _rolesOk;
+};
+
+
+class ModelObject : public QObject
+{
+ Q_OBJECT
+public:
+ ModelObject();
+ void setValue(const QByteArray &name, const QVariant &val);
+
+private:
+ QDeclarativeOpenMetaObject *_mo;
+};
+
+struct ModelNode
+{
+ ModelNode();
+ ~ModelNode();
+
+ QList<QVariant> values;
+ QHash<QString, ModelNode *> properties;
+
+ QDeclarativeListModel *model(const NestedListModel *model) {
+ if (!modelCache) {
+ modelCache = new QDeclarativeListModel;
+ QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(model->m_listModel));
+ modelCache->m_nested->_root = this; // ListModel defaults to nestable model
+ }
+ return modelCache;
+ }
+
+ ModelObject *object(const NestedListModel *model) {
+ if (!objectCache) {
+ objectCache = new ModelObject();
+ QHash<QString, ModelNode *>::iterator it;
+ for (it = properties.begin(); it != properties.end(); ++it) {
+ objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it));
+ }
+ }
+ return objectCache;
+ }
+
+
+ void setObjectValue(const QScriptValue& valuemap);
+ void setListValue(const QScriptValue& valuelist);
+ void setProperty(const QString& prop, const QVariant& val);
+ static void dump(ModelNode *node, int ind);
+
+ QDeclarativeListModel *modelCache;
+ ModelObject *objectCache;
+ bool isArray;
+};
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(ModelNode *)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELISTMODEL_P_P_H
+
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
new file mode 100644
index 0000000..ee43447
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
@@ -0,0 +1,245 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module 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 "qdeclarativelistmodelworkeragent_p.h"
+#include "qdeclarativelistmodel_p_p.h"
+#include "qdeclarativedeclarativedata_p.h"
+#include "qdeclarativeengine_p.h"
+#include "qdeclarativeinfo.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+void QDeclarativeListModelWorkerAgent::Data::clearChange()
+{
+ changes.clear();
+}
+
+void QDeclarativeListModelWorkerAgent::Data::insertChange(int index, int count)
+{
+ Change c = { Change::Inserted, index, count, 0 };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::removeChange(int index, int count)
+{
+ Change c = { Change::Removed, index, count, 0 };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::moveChange(int index, int count, int to)
+{
+ Change c = { Change::Moved, index, count, to };
+ changes << c;
+}
+
+void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count)
+{
+ Change c = { Change::Changed, index, count, 0 };
+ changes << c;
+}
+
+QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model)
+: m_engine(0), m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(true, this))
+{
+ m_copy->m_flat->m_roles = m_orig->m_flat->m_roles;
+ m_copy->m_flat->m_strings = m_orig->m_flat->m_strings;
+ m_copy->m_flat->m_values = m_orig->m_flat->m_values;
+}
+
+QDeclarativeListModelWorkerAgent::~QDeclarativeListModelWorkerAgent()
+{
+}
+
+void QDeclarativeListModelWorkerAgent::setScriptEngine(QScriptEngine *eng)
+{
+ m_engine = eng;
+ if (m_copy->m_flat)
+ m_copy->m_flat->m_scriptEngine = eng;
+}
+
+QScriptEngine *QDeclarativeListModelWorkerAgent::scriptEngine() const
+{
+ return m_engine;
+}
+
+void QDeclarativeListModelWorkerAgent::addref()
+{
+ m_ref.ref();
+}
+
+void QDeclarativeListModelWorkerAgent::release()
+{
+ bool del = !m_ref.deref();
+
+ if (del)
+ delete this;
+}
+
+int QDeclarativeListModelWorkerAgent::count() const
+{
+ return m_copy->count();
+}
+
+void QDeclarativeListModelWorkerAgent::clear()
+{
+ data.clearChange();
+ data.removeChange(0, m_copy->count());
+ m_copy->clear();
+}
+
+void QDeclarativeListModelWorkerAgent::remove(int index)
+{
+ int count = m_copy->count();
+ m_copy->remove(index);
+
+ if (m_copy->count() != count)
+ data.removeChange(index, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::append(const QScriptValue &value)
+{
+ int count = m_copy->count();
+ m_copy->append(value);
+
+ if (m_copy->count() != count)
+ data.insertChange(m_copy->count() - 1, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::insert(int index, const QScriptValue &value)
+{
+ int count = m_copy->count();
+ m_copy->insert(index, value);
+
+ if (m_copy->count() != count)
+ data.insertChange(index, 1);
+}
+
+QScriptValue QDeclarativeListModelWorkerAgent::get(int index) const
+{
+ if (index < 0 || index >= count())
+ return m_engine->undefinedValue();
+
+ return m_copy->get(index);
+}
+
+void QDeclarativeListModelWorkerAgent::set(int index, const QScriptValue &value)
+{
+ m_copy->set(index, value);
+ data.changedChange(index, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
+{
+ m_copy->setProperty(index, property, value);
+ data.changedChange(index, 1);
+}
+
+void QDeclarativeListModelWorkerAgent::move(int from, int to, int count)
+{
+ m_copy->move(from, to, count);
+ data.moveChange(from, to, count);
+}
+
+void QDeclarativeListModelWorkerAgent::sync()
+{
+ Sync *s = new Sync;
+ s->data = data;
+ s->list = m_copy;
+ data.changes.clear();
+ QCoreApplication::postEvent(this, s);
+}
+
+bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ Sync *s = static_cast<Sync *>(e);
+
+ const QList<Change> &changes = s->data.changes;
+
+ if (m_copy) {
+ bool cc = m_copy->count() != s->list->count();
+
+ FlatListModel *orig = m_orig->m_flat;
+ FlatListModel *copy = s->list->m_flat;
+ if (!orig || !copy) {
+ qWarning("QML List worker: cannot synchronize lists");
+ return QObject::event(e);
+ }
+ orig->m_roles = copy->m_roles;
+ orig->m_strings = copy->m_strings;
+ orig->m_values = copy->m_values;
+
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+ switch (change.type) {
+ case Change::Inserted:
+ emit m_orig->itemsInserted(change.index, change.count);
+ break;
+ case Change::Removed:
+ emit m_orig->itemsRemoved(change.index, change.count);
+ break;
+ case Change::Moved:
+ emit m_orig->itemsMoved(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ emit m_orig->itemsMoved(change.index, change.to, change.count);
+ break;
+ }
+ }
+
+ if (cc)
+ emit m_orig->countChanged(m_copy->count());
+
+ //qDebug() << "------sync():" << m_copy->count() << s->list->count() << m_orig->count();
+ }
+ }
+
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
new file mode 100644
index 0000000..b6a643b
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module 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$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELISTMODELWORKERAGENT_P_H
+#define QDECLARATIVELISTMODELWORKERAGENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdeclarative.h"
+
+#include <QtScript/qscriptvalue.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativeListModel;
+
+// Currently this will leak as no-one releases it in the worker thread
+class QDeclarativeListModelWorkerAgent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count)
+
+public:
+ QDeclarativeListModelWorkerAgent(QDeclarativeListModel *);
+ ~QDeclarativeListModelWorkerAgent();
+
+ void setScriptEngine(QScriptEngine *eng);
+ QScriptEngine *scriptEngine() const;
+
+ void addref();
+ void release();
+
+ int count() const;
+
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QScriptValue &);
+ 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 setProperty(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+ Q_INVOKABLE void sync();
+
+ struct VariantRef
+ {
+ VariantRef() : a(0) {}
+ VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
+ VariantRef(QDeclarativeListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
+ ~VariantRef() { if (a) a->release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ if (o.a) o.a->addref();
+ if (a) a->release(); a = o.a;
+ return *this;
+ }
+
+ QDeclarativeListModelWorkerAgent *a;
+ };
+protected:
+ virtual bool event(QEvent *);
+
+private:
+ friend class QDeclarativeWorkerScriptEnginePrivate;
+ QScriptEngine *m_engine;
+
+ struct Change {
+ enum { Inserted, Removed, Moved, Changed } type;
+ int index; // Inserted/Removed/Moved/Changed
+ int count; // Inserted/Removed/Moved/Changed
+ int to; // Moved
+ };
+
+ struct Data {
+ QList<Change> changes;
+
+ void clearChange();
+ void insertChange(int index, int count);
+ void removeChange(int index, int count);
+ void moveChange(int index, int count, int to);
+ void changedChange(int index, int count);
+ };
+ Data data;
+
+ struct Sync : public QEvent {
+ Sync() : QEvent(QEvent::User) {}
+ Data data;
+ QDeclarativeListModel *list;
+ };
+
+ QAtomicInt m_ref;
+ QDeclarativeListModel *m_orig;
+ QDeclarativeListModel *m_copy;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDeclarativeListModelWorkerAgent::VariantRef);
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEWORKERSCRIPT_P_H
+
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
index 26edecc..041aa13 100644
--- a/src/declarative/util/util.pri
+++ b/src/declarative/util/util.pri
@@ -27,7 +27,8 @@ SOURCES += \
$$PWD/qdeclarativepixmapcache.cpp \
$$PWD/qdeclarativebehavior.cpp \
$$PWD/qdeclarativefontloader.cpp \
- $$PWD/qdeclarativestyledtext.cpp
+ $$PWD/qdeclarativestyledtext.cpp \
+ $$PWD/qdeclarativelistmodelworkeragent.cpp
HEADERS += \
$$PWD/qdeclarativeutilmodule_p.h\
@@ -59,7 +60,9 @@ HEADERS += \
$$PWD/qdeclarativepixmapcache_p.h \
$$PWD/qdeclarativebehavior_p.h \
$$PWD/qdeclarativefontloader_p.h \
- $$PWD/qdeclarativestyledtext_p.h
+ $$PWD/qdeclarativestyledtext_p.h \
+ $$PWD/qdeclarativelistmodelworkeragent_p.h \
+ $$PWD/qdeclarativelistmodelworkeragent_p_p.h
contains(QT_CONFIG, xmlpatterns) {
QT+=xmlpatterns