diff options
author | Martin Jones <martin.jones@nokia.com> | 2010-03-16 05:50:15 (GMT) |
---|---|---|
committer | Martin Jones <martin.jones@nokia.com> | 2010-03-16 05:50:15 (GMT) |
commit | 1c1465587ed116695171a73deffa1dc0729856d0 (patch) | |
tree | 9d6734313df1ef0fce7ca32b3dae39cbd9da915a /src | |
parent | a32cd00668076674b6968b821d4b7377c95ddee9 (diff) | |
parent | fcfc3a68a525c32d4550068d7cf47bb3a5816da6 (diff) | |
download | Qt-1c1465587ed116695171a73deffa1dc0729856d0.zip Qt-1c1465587ed116695171a73deffa1dc0729856d0.tar.gz Qt-1c1465587ed116695171a73deffa1dc0729856d0.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-qml into 4.7
Diffstat (limited to 'src')
-rw-r--r-- | src/declarative/qml/qdeclarativeengine.cpp | 1 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeworkerscript.cpp | 647 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeworkerscript_p.h | 41 | ||||
-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 |
9 files changed, 1290 insertions, 980 deletions
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index a3f8250..e84e267 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -149,7 +149,6 @@ void QDeclarativeEnginePrivate::defineModule() qmlRegisterType<QDeclarativeComponent>("Qt",4,6,"Component"); qmlRegisterType<QObject>("Qt",4,6,"QtObject"); qmlRegisterType<QDeclarativeWorkerScript>("Qt",4,6,"WorkerScript"); - qmlRegisterType<QDeclarativeWorkerListModel>("Qt",4,6,"WorkerListModel"); qmlRegisterType<QDeclarativeBinding>(); } diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index 784353a..10c0b54 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -40,7 +40,8 @@ ****************************************************************************/ #include "qdeclarativeworkerscript_p.h" - +#include "qdeclarativelistmodel_p.h" +#include "qdeclarativelistmodelworkeragent_p.h" #include "qdeclarativeengine_p.h" #include <QtCore/qcoreevent.h> @@ -104,6 +105,7 @@ private: class QDeclarativeWorkerScriptEnginePrivate : public QObject { + Q_OBJECT public: QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng); @@ -165,87 +167,6 @@ private: void processLoad(int, const QUrl &); }; -// Currently this will leak as no-one releases it in the worker thread -class QDeclarativeWorkerListModelAgent : public QObject -{ - Q_OBJECT - Q_PROPERTY(int count READ count) - -public: - QDeclarativeWorkerListModelAgent(QDeclarativeWorkerListModel *); - ~QDeclarativeWorkerListModelAgent(); - - 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 sync(); - - struct VariantRef - { - VariantRef() : a(0) {} - VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); } - VariantRef(QDeclarativeWorkerListModelAgent *_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; - } - - QDeclarativeWorkerListModelAgent *a; - }; -protected: - virtual bool event(QEvent *); - -private: - friend class QDeclarativeWorkerScriptEnginePrivate; - friend class QDeclarativeWorkerListModel; - 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 { - QHash<int, QString> roles; - QHash<QString, int> strings; - QList<QHash<int, QVariant> > values; - QList<Change> changes; - - void clearChange(); - void insertChange(int index, int count); - void removeChange(int index, int count); - void changedChange(int index, int count); - }; - Data data; - - struct Sync : public QEvent { - Sync() : QEvent(QEvent::User) {} - Data data; - }; - - QAtomicInt m_ref; - QDeclarativeWorkerListModel *m_model; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QDeclarativeWorkerListModelAgent::VariantRef); - -QT_BEGIN_NAMESPACE - QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine) : workerEngine(0), qmlengine(engine), m_nextId(0) { @@ -390,10 +311,15 @@ QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScri return QVariant(list); } else if (value.isQObject()) { - QDeclarativeWorkerListModel *lm = qobject_cast<QDeclarativeWorkerListModel *>(value.toQObject()); + QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject()); if (lm) { - QDeclarativeWorkerListModelAgent::VariantRef v(lm->agent()); - return qVariantFromValue(v); + QDeclarativeListModelWorkerAgent *agent = lm->agent(); + if (agent) { + QDeclarativeListModelWorkerAgent::VariantRef v(agent); + return qVariantFromValue(v); + } else { + return QVariant(); + } } else { // No other QObject's are allowed to be sent return QVariant(); @@ -423,11 +349,11 @@ QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const Q return QScriptValue(value.toString()); } else if (value.userType() == QMetaType::QReal) { return QScriptValue(value.toReal()); - } else if (value.userType() == qMetaTypeId<QDeclarativeWorkerListModelAgent::VariantRef>()) { - QDeclarativeWorkerListModelAgent::VariantRef vr = qvariant_cast<QDeclarativeWorkerListModelAgent::VariantRef>(value); - if (vr.a->m_engine == 0) - vr.a->m_engine = engine; - else if (vr.a->m_engine != engine) + } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) { + QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value); + if (vr.a->scriptEngine() == 0) + vr.a->setScriptEngine(engine); + else if (vr.a->scriptEngine() != engine) return engine->nullValue(); QScriptValue o = engine->newQObject(vr.a); o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc @@ -619,8 +545,6 @@ void QDeclarativeWorkerScriptEngine::run() called, triggering the \tt WorkerScript.onMessage() handler in \tt source.js. This in turn sends a reply message that is then received by the \tt onMessage() handler of \tt myWorker. - - \sa WorkerListModel */ QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent) : QObject(parent), m_engine(0), m_scriptId(-1) @@ -714,544 +638,7 @@ bool QDeclarativeWorkerScript::event(QEvent *event) } } -void QDeclarativeWorkerListModelAgent::Data::clearChange() -{ - changes.clear(); -} - -void QDeclarativeWorkerListModelAgent::Data::insertChange(int index, int count) -{ - Change c = { Change::Inserted, index, count, 0 }; - changes << c; -} - -void QDeclarativeWorkerListModelAgent::Data::removeChange(int index, int count) -{ - Change c = { Change::Removed, index, count, 0 }; - changes << c; -} - -void QDeclarativeWorkerListModelAgent::Data::changedChange(int index, int count) -{ - Change c = { Change::Changed, index, count, 0 }; - changes << c; -} - -QDeclarativeWorkerListModelAgent::QDeclarativeWorkerListModelAgent(QDeclarativeWorkerListModel *m) -: m_engine(0), m_ref(1), m_model(m) -{ - data.roles = m_model->m_roles; - data.strings = m_model->m_strings; - data.values = m_model->m_values; -} - -QDeclarativeWorkerListModelAgent::~QDeclarativeWorkerListModelAgent() -{ -} - -void QDeclarativeWorkerListModelAgent::addref() -{ - m_ref.ref(); -} - -void QDeclarativeWorkerListModelAgent::release() -{ - bool del = !m_ref.deref(); - - if (del) - delete this; -} - -int QDeclarativeWorkerListModelAgent::count() const -{ - return data.values.count(); -} - -void QDeclarativeWorkerListModelAgent::clear() -{ - data.clearChange(); - data.removeChange(0, data.values.count()); - data.values.clear(); -} - -void QDeclarativeWorkerListModelAgent::remove(int index) -{ - if (data.values.count() <= index) - return; - - data.values.removeAt(index); - data.removeChange(index, 1); -} - -void QDeclarativeWorkerListModelAgent::append(const QScriptValue &value) -{ - QHash<int, QVariant> row; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - QString name = it.name(); - QVariant v = it.value().toVariant(); - - QHash<QString, int>::Iterator iter = data.strings.find(name); - if (iter == data.strings.end()) { - int role = data.roles.count(); - data.roles.insert(role, name); - iter = data.strings.insert(name, role); - } - row.insert(*iter, v); - } - - data.values.append(row); - data.insertChange(data.values.count() - 1, 1); -} - -void QDeclarativeWorkerListModelAgent::insert(int index, const QScriptValue &value) -{ - if (index > data.values.count()) - return; - - QHash<int, QVariant> row; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - QString name = it.name(); - QVariant v = it.value().toVariant(); - - QHash<QString, int>::Iterator iter = data.strings.find(name); - if (iter == data.strings.end()) { - int role = data.roles.count(); - data.roles.insert(role, name); - iter = data.strings.insert(name, role); - } - row.insert(*iter, v); - } - - data.values.insert(index, row); - data.insertChange(index, 1); -} - -void QDeclarativeWorkerListModelAgent::set(int index, const QScriptValue &value) -{ - if (data.values.count() <= index) - return; - - QHash<int, QVariant> row; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - QString name = it.name(); - QVariant v = it.value().toVariant(); - - QHash<QString, int>::Iterator iter = data.strings.find(name); - if (iter == data.strings.end()) { - int role = data.roles.count(); - data.roles.insert(role, name); - iter = data.strings.insert(name, role); - } - row.insert(*iter, v); - } - - if (data.values.at(index) != row) { - data.values[index] = row; - data.changedChange(index, 1); - } -} - -QScriptValue QDeclarativeWorkerListModelAgent::get(int index) const -{ - if (data.values.count() <= index) - return m_engine->undefinedValue(); - - QScriptValue rv = m_engine->newObject(); - - QHash<int, QVariant> row = data.values.at(index); - for (QHash<int, QVariant>::ConstIterator iter = row.begin(); iter != row.end(); ++iter) - rv.setProperty(data.roles.value(iter.key()), qScriptValueFromValue(m_engine, iter.value())); - - return rv; -} - -void QDeclarativeWorkerListModelAgent::sync() -{ - Sync *s = new Sync; - s->data = data; - data.changes.clear(); - QCoreApplication::postEvent(this, s); -} - -bool QDeclarativeWorkerListModelAgent::event(QEvent *e) -{ - if (e->type() == QEvent::User) { - Sync *s = static_cast<Sync *>(e); - - const QList<Change> &changes = s->data.changes; - - if (m_model) { - bool cc = m_model->m_values.count() != s->data.values.count(); - - m_model->m_roles = s->data.roles; - m_model->m_strings = s->data.strings; - m_model->m_values = s->data.values; - - for (int ii = 0; ii < changes.count(); ++ii) { - const Change &change = changes.at(ii); - switch (change.type) { - case Change::Inserted: - emit m_model->itemsInserted(change.index, change.count); - break; - case Change::Removed: - emit m_model->itemsRemoved(change.index, change.count); - break; - case Change::Moved: - emit m_model->itemsMoved(change.index, change.to, change.count); - break; - case Change::Changed: - emit m_model->itemsMoved(change.index, change.to, change.count); - break; - } - } - - if (cc) - emit m_model->countChanged(); - } - } - - return QObject::event(e); -} - -/*! - \qmlclass WorkerListModel QDeclarativeWorkerListModel - \brief The WorkerListModel element provides a threaded list model. - - Use WorkerListModel together with WorkerScript to define a list model - that is controlled by a separate thread. This is useful if list modification - operations are synchronous and take some time: using WorkerListModel - moves these operations to a different thread and avoids blocking of the - main GUI thread. - - The thread that creates the WorkerListModel can modify the model for any - initial set-up requirements. However, once the model has been modified by - the associated WorkerScript, the model can only be modified by that worker - script and becomes read-only to all other threads. - - Here is an example application that uses WorkerScript to append the - current time to a WorkerListModel: - - \snippet examples/declarative/workerlistmodel/timedisplay.qml 0 - - The included file, \tt dataloader.js, looks like this: - - \snippet examples/declarative/workerlistmodel/dataloader.js 0 - - The application's \tt Timer object periodically sends a message to the - worker script by calling \tt WorkerScript::sendMessage(). When this message - is received, \tt WorkerScript.onMessage() is invoked in - \tt dataloader.js, which appends the current time to the worker list - model. - - Note that unlike ListModel, WorkerListModel does not have \tt move() and - \tt setProperty() methods. - - \sa WorkerScript, ListModel -*/ -QDeclarativeWorkerListModel::QDeclarativeWorkerListModel(QObject *parent) -: QListModelInterface(parent), m_agent(0) -{ -} - -QDeclarativeWorkerListModel::~QDeclarativeWorkerListModel() -{ - if (m_agent) { - m_agent->m_model = 0; - m_agent->release(); - } -} - -/*! - \qmlmethod WorkerListModel::clear() - - Deletes all content from the model. The properties are cleared such that - different properties may be set on subsequent additions. - - \sa append() remove() -*/ -void QDeclarativeWorkerListModel::clear() -{ - if (m_agent) { - qmlInfo(this) << "List can only be modified from a WorkerScript"; - return; - } - - int count = m_values.count(); - m_values.clear(); - if (count) { - emit itemsRemoved(0, count); - emit countChanged(); - } -} - -/*! - \qmlmethod WorkerListModel::remove(int index) - - Deletes the content at \a index from the model. - - \sa clear() -*/ -void QDeclarativeWorkerListModel::remove(int index) -{ - if (m_agent) { - qmlInfo(this) << "List can only be modified from a WorkerScript"; - return; - } - - if (m_values.count() <= index) - return; - - m_values.removeAt(index); - emit itemsRemoved(index, 1); - emit countChanged(); -} - -/*! - \qmlmethod WorkerListModel::append(jsobject dict) - - Adds a new item to the end of the list model, with the - values in \a dict. - - \code - FruitModel.append({"cost": 5.95, "name":"Pizza"}) - \endcode - - \sa set() remove() -*/ -void QDeclarativeWorkerListModel::append(const QScriptValue &value) -{ - if (m_agent) { - qmlInfo(this) << "List can only be modified from a WorkerScript"; - return; - } - - QHash<int, QVariant> data; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - 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); - } - data.insert(*iter, v); - } - - m_values.append(data); - - emit itemsInserted(m_values.count() - 1, 1); - emit countChanged(); -} - -/*! - \qmlmethod WorkerListModel::insert(int index, jsobject dict) - - Adds a new item to the list model at position \a index, with the - values in \a dict. - - \code - FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) - \endcode - - The \a index must be to an existing item in the list, or one past - the end of the list (equivalent to append). - - \sa set() append() -*/ -void QDeclarativeWorkerListModel::insert(int index, const QScriptValue &value) -{ - if (m_agent) { - qmlInfo(this) << "List can only be modified from a WorkerScript"; - return; - } - - if (index > m_values.count()) - return; - - QHash<int, QVariant> data; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - 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); - } - data.insert(*iter, v); - } - - m_values.insert(index, data); - emit itemsInserted(index, 1); - emit countChanged(); -} - -/*! - \qmlmethod object ListModel::get(int index) - - Returns the item at \a index in the list model. - - \code - FruitModel.append({"cost": 5.95, "name":"Jackfruit"}) - FruitModel.get(0).cost - \endcode - - The \a index must be an element in the list. - - Note that properties of the returned object that are themselves objects - will also be models, and this get() method is used to access elements: - - \code - FruitModel.append(..., "attributes": - [{"name":"spikes","value":"7mm"}, - {"name":"color","value":"green"}]); - FruitModel.get(0).attributes.get(1).value; // == "green" - \endcode - - \sa append() -*/ -QScriptValue QDeclarativeWorkerListModel::get(int index) const -{ - QDeclarativeEngine *engine = qmlEngine(this); - if (!engine || m_values.count() <= index) - return QScriptValue(); - - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - QScriptValue rv = scriptEngine->newObject(); - - QHash<int, QVariant> data = m_values.at(index); - for (QHash<int, QVariant>::ConstIterator iter = data.begin(); iter != data.end(); ++iter) - rv.setProperty(m_roles.value(iter.key()), qScriptValueFromValue(scriptEngine, iter.value())); - - return rv; -} - -/*! - \qmlmethod WorkerListModel::set(int index, jsobject dict) - - Changes the item at \a index in the list model with the - values in \a dict. Properties not appearing in \a valuemap - are left unchanged. - - \code - FruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) - \endcode - - The \a index must be an element in the list. - - \sa append() -*/ -void QDeclarativeWorkerListModel::set(int index, const QScriptValue &value) -{ - if (m_agent) { - qmlInfo(this) << "List can only be modified from a WorkerScript"; - return; - } - - if (m_values.count() <= index) - return; - - QHash<int, QVariant> data; - - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - 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); - } - data.insert(*iter, v); - } - - if (m_values.at(index) != data) { - m_values[index] = data; - emit itemsChanged(index, 1, m_roles.keys()); - } -} - -/*! - \qmlmethod WorkerListModel::sync() - - Writes any unsaved changes to the list model. This must be called after - changes have been made to the list model in the worker script. - - Note that this method can only be called from the associated worker script. -*/ -void QDeclarativeWorkerListModel::sync() -{ - // This is really a dummy method to make it look like sync() exists in - // WorkerListModel (and not QDeclarativeWorkerListModelAgent) and to let - // us document sync(). - qmlInfo(this) << "sync() can only be called from a WorkerScript"; -} - -QDeclarativeWorkerListModelAgent *QDeclarativeWorkerListModel::agent() -{ - if (!m_agent) - m_agent = new QDeclarativeWorkerListModelAgent(this); - - return m_agent; -} - -QList<int> QDeclarativeWorkerListModel::roles() const -{ - return m_roles.keys(); -} - -QString QDeclarativeWorkerListModel::toString(int role) const -{ - return m_roles.value(role); -} - -/*! - \qmlproperty int ListModel::count - The number of data entries in the model. -*/ -int QDeclarativeWorkerListModel::count() const -{ - return m_values.count(); -} - -QHash<int,QVariant> QDeclarativeWorkerListModel::data(int index, const QList<int> &) const -{ - if (m_values.count() <= index) - return QHash<int, QVariant>(); - else - return m_values.at(index); -} - -QVariant QDeclarativeWorkerListModel::data(int index, int role) const -{ - if (m_values.count() <= index) - return QVariant(); - else - return m_values.at(index).value(role); -} - QT_END_NAMESPACE -#include "qdeclarativeworkerscript.moc" +#include <qdeclarativeworkerscript.moc> diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h index 912eac9..6cce799 100644 --- a/src/declarative/qml/qdeclarativeworkerscript_p.h +++ b/src/declarative/qml/qdeclarativeworkerscript_p.h @@ -55,7 +55,6 @@ #include "qdeclarative.h" #include "qdeclarativeparserstatus.h" -#include <private/qlistmodelinterface_p.h> #include <QtCore/qthread.h> #include <QtScript/qscriptvalue.h> @@ -118,49 +117,9 @@ private: QUrl m_source; }; -class QDeclarativeWorkerListModelAgent; -class Q_DECLARATIVE_EXPORT QDeclarativeWorkerListModel : public QListModelInterface -{ - Q_OBJECT - Q_PROPERTY(int count READ count NOTIFY countChanged) - -public: - QDeclarativeWorkerListModel(QObject * = 0); - virtual ~QDeclarativeWorkerListModel(); - - 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 sync(); - - QDeclarativeWorkerListModelAgent *agent(); - - virtual QList<int> roles() const; - virtual QString toString(int role) const; - virtual int count() const; - virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; - virtual QVariant data(int index, int role) const; - -Q_SIGNALS: - void countChanged(); - -private: - friend class QDeclarativeWorkerListModelAgent; - - QHash<int, QString> m_roles; - QHash<QString, int> m_strings; - QList<QHash<int, QVariant> > m_values; - - QDeclarativeWorkerListModelAgent *m_agent; -}; - QT_END_NAMESPACE QML_DECLARE_TYPE(QDeclarativeWorkerScript); -QML_DECLARE_TYPE(QDeclarativeWorkerListModel); QT_END_HEADER diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index e3f26d7..d612ba8 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(); + \section2 Using threaded list models with WorkerScript - void setValue(const QByteArray &name, const QVariant &val) - { - _mo->setValue(name, val); - } + ListModel can be used together with WorkerScript access a list model + 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. -private: - QDeclarativeOpenMetaObject *_mo; -}; + Here is an example that uses WorkerScript to periodically append the + current time to a list model: -struct ModelNode -{ - ModelNode(); - ~ModelNode(); + \snippet examples/declarative/listmodel-threaded/timedisplay.qml 0 - QList<QVariant> values; - QHash<QString, ModelNode *> properties; + The included file, \tt dataloader.js, looks like this: - QDeclarativeListModel *model(const QDeclarativeListModel *parent) { - if (!modelCache) { - modelCache = new QDeclarativeListModel; - QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(parent)); + \snippet examples/declarative/listmodel-threaded/dataloader.js 0 - modelCache->_root = this; - } - return modelCache; - } + 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. - 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; - } - - void setObjectValue(const QScriptValue& valuemap); - void setListValue(const QScriptValue& valuelist); + Note the call to sync() from the \c WorkerScript.onMessage() handler. + Without this call, the changes made to the list are not reflected in the + list model in the main thread. - 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); - } + \section3 Limitations - QDeclarativeListModel *modelCache; - ModelObject *objectCache; - bool isArray; -}; + If a list model is to be accessed from a WorkerScript, it \bold cannot + contain nested list data. So, the following model cannot be used from a WorkerScript + because of the list contained in the "attributes" property: -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(ModelNode *) - -QT_BEGIN_NAMESPACE - -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(); + \code + ListModel { + id: fruitModel + ListElement { + name: "Apple" + cost: 2.45 + attributes: [ + ListElement { description: "Core" }, + ListElement { description: "Deciduous" } + ] } - properties.insert(it.name(),value); } -} + \endcode -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)); + In addition, the WorkerScript cannot add any nested list data to the 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 |