diff options
author | Bea Lam <bea.lam@nokia.com> | 2010-03-16 01:16:13 (GMT) |
---|---|---|
committer | Bea Lam <bea.lam@nokia.com> | 2010-03-16 01:16:13 (GMT) |
commit | 081fafe395d52ae42b57c36d1279e6ac05ae2cde (patch) | |
tree | bf1fa2e0478ed0ea89f5d03aa54555d724017d1b /src/declarative/util | |
parent | db0c932bf816b76547798ec62336e25b453d29b8 (diff) | |
download | Qt-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.cpp | 954 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodel_p.h | 21 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodel_p_p.h | 199 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodelworkeragent.cpp | 245 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativelistmodelworkeragent_p.h | 155 | ||||
-rw-r--r-- | src/declarative/util/util.pri | 7 |
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 |