summaryrefslogtreecommitdiffstats
path: root/src/declarative/util
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2010-09-21 08:06:18 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2010-09-21 08:06:18 (GMT)
commita4d1be727573a7a87c523a2ef28074c77d16f165 (patch)
treed4f8f218c41771ca17c7ab324390485af868fa8e /src/declarative/util
parentcd2fd21578a80bc5ac121c0419ee00b1799d0a60 (diff)
parent660ec910ef60513b511e2292255e53701dbb239b (diff)
downloadQt-a4d1be727573a7a87c523a2ef28074c77d16f165.zip
Qt-a4d1be727573a7a87c523a2ef28074c77d16f165.tar.gz
Qt-a4d1be727573a7a87c523a2ef28074c77d16f165.tar.bz2
Merge remote branch 'origin/4.7' into qt-master-from-4.7
Conflicts: src/corelib/kernel/qobject.h src/declarative/graphicsitems/qdeclarativeflickable.cpp src/declarative/graphicsitems/qdeclarativeflickable_p_p.h src/declarative/util/qdeclarativelistmodel.cpp
Diffstat (limited to 'src/declarative/util')
-rw-r--r--src/declarative/util/qdeclarativeanimation.cpp5
-rw-r--r--src/declarative/util/qdeclarativefontloader.cpp197
-rw-r--r--src/declarative/util/qdeclarativefontloader_p.h2
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp536
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p.h12
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p_p.h134
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp33
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent_p.h4
-rw-r--r--src/declarative/util/qdeclarativepixmapcache_p.h2
-rw-r--r--src/declarative/util/qdeclarativepropertychanges.cpp275
-rw-r--r--src/declarative/util/qdeclarativepropertychanges_p.h16
-rw-r--r--src/declarative/util/qdeclarativestate.cpp238
-rw-r--r--src/declarative/util/qdeclarativestate_p.h21
-rw-r--r--src/declarative/util/qdeclarativestate_p_p.h135
-rw-r--r--src/declarative/util/qdeclarativestateoperations.cpp66
-rw-r--r--src/declarative/util/qdeclarativetransitionmanager.cpp4
-rw-r--r--src/declarative/util/qdeclarativexmllistmodel.cpp8
17 files changed, 1417 insertions, 271 deletions
diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp
index 6637282..3a96f98 100644
--- a/src/declarative/util/qdeclarativeanimation.cpp
+++ b/src/declarative/util/qdeclarativeanimation.cpp
@@ -2699,14 +2699,15 @@ void QDeclarativeParentAnimation::transition(QDeclarativeStateActions &actions,
qreal scale = 1;
qreal rotation = 0;
- if (ok && transform.type() != QTransform::TxRotate) {
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
if (transform.m11() == transform.m22())
scale = transform.m11();
else {
qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
ok = false;
}
- } else if (ok && transform.type() == QTransform::TxRotate) {
+ } else if (ok && isRotate) {
if (transform.m11() == transform.m22())
scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
else {
diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp
index 1755855..6879494 100644
--- a/src/declarative/util/qdeclarativefontloader.cpp
+++ b/src/declarative/util/qdeclarativefontloader.cpp
@@ -58,23 +58,91 @@
QT_BEGIN_NAMESPACE
+#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
+
+class QDeclarativeFontObject : public QObject
+{
+Q_OBJECT
+
+public:
+ QDeclarativeFontObject(int _id);
+
+ void download(const QUrl &url, QNetworkAccessManager *manager);
+
+Q_SIGNALS:
+ void fontDownloaded(const QString&, QDeclarativeFontLoader::Status);
+
+private Q_SLOTS:
+ void replyFinished();
+
+public:
+ int id;
+
+private:
+ QNetworkReply *reply;
+ int redirectCount;
+
+ Q_DISABLE_COPY(QDeclarativeFontObject)
+};
+
+QDeclarativeFontObject::QDeclarativeFontObject(int _id = -1)
+ : QObject(0), id(_id), reply(0), redirectCount(0) {}
+
+
+void QDeclarativeFontObject::download(const QUrl &url, QNetworkAccessManager *manager)
+{
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ reply = manager->get(req);
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+}
+
+void QDeclarativeFontObject::replyFinished()
+{
+ if (reply) {
+ redirectCount++;
+ if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkAccessManager *manager = reply->manager();
+ reply->deleteLater();
+ reply = 0;
+ download(url, manager);
+ return;
+ }
+ }
+ redirectCount = 0;
+
+ if (!reply->error()) {
+ id = QFontDatabase::addApplicationFontFromData(reply->readAll());
+ if (id != -1)
+ emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarativeFontLoader::Ready);
+ else
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ } else {
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ }
+ reply->deleteLater();
+ reply = 0;
+ }
+}
+
+
class QDeclarativeFontLoaderPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDeclarativeFontLoader)
public:
- QDeclarativeFontLoaderPrivate() : reply(0), status(QDeclarativeFontLoader::Null), redirectCount(0) {}
-
- void addFontToDatabase(const QByteArray &);
+ QDeclarativeFontLoaderPrivate() : status(QDeclarativeFontLoader::Null) {}
QUrl url;
QString name;
- QNetworkReply *reply;
QDeclarativeFontLoader::Status status;
- int redirectCount;
+ static QHash<QUrl, QDeclarativeFontObject*> fonts;
};
-
+QHash<QUrl, QDeclarativeFontObject*> QDeclarativeFontLoaderPrivate::fonts;
/*!
\qmlclass FontLoader QDeclarativeFontLoader
@@ -127,30 +195,61 @@ void QDeclarativeFontLoader::setSource(const QUrl &url)
if (url == d->url)
return;
d->url = qmlContext(this)->resolvedUrl(url);
-
- d->status = Loading;
- emit statusChanged();
emit sourceChanged();
+
#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
- QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
- if (!lf.isEmpty()) {
- int id = QFontDatabase::addApplicationFont(lf);
- if (id != -1) {
- d->name = QFontDatabase::applicationFontFamilies(id).at(0);
- emit nameChanged();
- d->status = QDeclarativeFontLoader::Ready;
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!localFile.isEmpty()) {
+ if (!d->fonts.contains(d->url)) {
+ int id = QFontDatabase::addApplicationFont(localFile);
+ if (id != -1) {
+ updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready);
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject(id);
+ d->fonts[d->url] = fo;
+ } else {
+ updateFontInfo(QString(), Error);
+ }
} else {
- d->status = QDeclarativeFontLoader::Error;
- qmlInfo(this) << "Cannot load font: \"" << url.toString() << "\"";
+ updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready);
}
- emit statusChanged();
} else
#endif
{
- QNetworkRequest req(d->url);
- req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
- d->reply = qmlEngine(this)->networkAccessManager()->get(req);
- QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ if (!d->fonts.contains(d->url)) {
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject;
+ d->fonts[d->url] = fo;
+ fo->download(d->url, qmlEngine(this)->networkAccessManager());
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString, QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString, QDeclarativeFontLoader::Status)));
+ } else {
+ QDeclarativeFontObject *fo = d->fonts[d->url];
+ if (fo->id == -1) {
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString, QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString, QDeclarativeFontLoader::Status)));
+ }
+ else
+ updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready);
+ }
+ }
+}
+
+void QDeclarativeFontLoader::updateFontInfo(const QString& name, QDeclarativeFontLoader::Status status)
+{
+ Q_D(QDeclarativeFontLoader);
+
+ if (name != d->name) {
+ d->name = name;
+ emit nameChanged();
+ }
+ if (status != d->status) {
+ if (status == Error)
+ qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\"";
+ d->status = status;
+ emit statusChanged();
}
}
@@ -177,7 +276,7 @@ QString QDeclarativeFontLoader::name() const
void QDeclarativeFontLoader::setName(const QString &name)
{
Q_D(QDeclarativeFontLoader);
- if (d->name == name )
+ if (d->name == name)
return;
d->name = name;
emit nameChanged();
@@ -223,52 +322,6 @@ QDeclarativeFontLoader::Status QDeclarativeFontLoader::status() const
return d->status;
}
-#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
-
-void QDeclarativeFontLoader::replyFinished()
-{
- Q_D(QDeclarativeFontLoader);
- if (d->reply) {
- d->redirectCount++;
- if (d->redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
- QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- QUrl url = d->reply->url().resolved(redirect.toUrl());
- d->reply->deleteLater();
- d->reply = 0;
- setSource(url);
- return;
- }
- }
- d->redirectCount=0;
-
- if (!d->reply->error()) {
- QByteArray ba = d->reply->readAll();
- d->addFontToDatabase(ba);
- } else {
- d->status = Error;
- qmlInfo(this) << "Cannot load font: \"" << d->reply->url().toString() << "\"";
- emit statusChanged();
- }
- d->reply->deleteLater();
- d->reply = 0;
- }
-}
-
-void QDeclarativeFontLoaderPrivate::addFontToDatabase(const QByteArray &ba)
-{
- Q_Q(QDeclarativeFontLoader);
-
- int id = QFontDatabase::addApplicationFontFromData(ba);
- if (id != -1) {
- name = QFontDatabase::applicationFontFamilies(id).at(0);
- emit q->nameChanged();
- status = QDeclarativeFontLoader::Ready;
- } else {
- status = QDeclarativeFontLoader::Error;
- qmlInfo(q) << "Cannot load font: \"" << url.toString() << "\"";
- }
- emit q->statusChanged();
-}
-
QT_END_NAMESPACE
+
+#include <qdeclarativefontloader.moc>
diff --git a/src/declarative/util/qdeclarativefontloader_p.h b/src/declarative/util/qdeclarativefontloader_p.h
index 0344d99..bebd5a0 100644
--- a/src/declarative/util/qdeclarativefontloader_p.h
+++ b/src/declarative/util/qdeclarativefontloader_p.h
@@ -79,7 +79,7 @@ public:
Status status() const;
private Q_SLOTS:
- void replyFinished();
+ void updateFontInfo(const QString&, QDeclarativeFontLoader::Status);
Q_SIGNALS:
void sourceChanged();
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
index c7d5024..5ce95e9 100644
--- a/src/declarative/util/qdeclarativelistmodel.cpp
+++ b/src/declarative/util/qdeclarativelistmodel.cpp
@@ -58,6 +58,28 @@ Q_DECLARE_METATYPE(QListModelInterface *)
QT_BEGIN_NAMESPACE
+template<typename T>
+void qdeclarativelistmodel_move(int from, int to, int n, T *items)
+{
+ if (n == 1) {
+ items->move(from, to);
+ } else {
+ T replaced;
+ int i=0;
+ typename T::ConstIterator it=items->begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=items->begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ typename T::ConstIterator f=replaced.begin();
+ typename T::Iterator t=items->begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+}
+
QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListModelData::instructions() const
{
return (QDeclarativeListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData));
@@ -69,49 +91,67 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM
\since 4.7
\brief The ListModel element defines a free-form list data source.
- The ListModel is a simple hierarchy of elements containing data roles. The contents can
- be defined dynamically, or explicitly in QML:
+ The ListModel is a simple container of ListElement definitions, each containing data roles.
+ The contents can be defined dynamically, or explicitly in QML.
- For example:
+ The number of elements in the model can be obtained from its \l count property.
+ A number of familiar methods are also provided to manipulate the contents of the
+ model, including append(), insert(), move(), remove() and set(). These methods
+ accept dictionaries as their arguments; these are translated to ListElement objects
+ by the model.
- \snippet doc/src/snippets/declarative/listmodel.qml 0
+ Elements can be manipulated via the model using the setProperty() method, which
+ allows the roles of the specified element to be set and changed.
- Roles (properties) must begin with a lower-case letter. The above example defines a
- ListModel containing three elements, with the roles "name" and "cost".
+ \section1 Example Usage
- Values must be simple constants - either strings (quoted and optionally within a call to QT_TR_NOOP),
- bools (true, false), numbers, or enum values (like Text.AlignHCenter).
+ The following example shows a ListModel containing three elements, with the roles
+ "name" and "cost".
+
+ \beginfloatright
+ \inlineimage listmodel.png
+ \endfloat
+
+ \snippet doc/src/snippets/declarative/listmodel.qml 0
- The defined model can be used in views such as ListView:
+ \clearfloat
+ Roles (properties) in each element must begin with a lower-case letter and
+ should be common to all elements in a model. The ListElement documentation
+ provides more guidelines for how elements should be defined.
+
+ Since the example model contains an \c id property, it can be referenced
+ by views, such as the ListView in this example:
\snippet doc/src/snippets/declarative/listmodel-simple.qml 0
\dots 8
\snippet doc/src/snippets/declarative/listmodel-simple.qml 1
- \image listmodel.png
- It is possible for roles to contain list data. In the example below we create a list of fruit attributes:
+ It is possible for roles to contain list data. In the following example we
+ create a list of fruit attributes:
\snippet doc/src/snippets/declarative/listmodel-nested.qml model
- The delegate below displays all the fruit attributes:
+ The delegate displays all the fruit attributes:
- \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate
- \image listmodel-nested.png
+ \beginfloatright
+ \inlineimage listmodel-nested.png
+ \endfloat
+ \snippet doc/src/snippets/declarative/listmodel-nested.qml delegate
- \section2 Modifying list models
+ \clearfloat
+ \section1 Modifying List Models
The content of a ListModel may be created and modified using the clear(),
append(), set() and setProperty() methods. For example:
-
- \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate
- Note that when creating content dynamically the set of available properties cannot be changed
- once set. Whatever properties are first added to the model are the
- only permitted properties in the model.
+ \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate
+ Note that when creating content dynamically the set of available properties
+ cannot be changed once set. Whatever properties are first added to the model
+ are the only permitted properties in the model.
- \section2 Using threaded list models with WorkerScript
+ \section1 Using Threaded List Models with WorkerScript
ListModel can be used together with WorkerScript access a list model
from multiple threads. This is useful if list modifications are
@@ -127,19 +167,19 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM
\snippet examples/declarative/threading/threadedlistmodel/dataloader.js 0
-working-with-data
- worker script by calling \l WorkerScript::sendMessage(). When this message
- is received, \l {WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in
- \tt dataloader.js, which appends the current time to the list model.
+ The timer in the main example sends messages to the worker script by calling
+ \l WorkerScript::sendMessage(). When this message is received,
+ \l{WorkerScript::onMessage}{WorkerScript.onMessage()} is invoked in \c dataloader.js,
+ which appends the current time to the list model.
- Note the call to sync() from the \l {WorkerScript::onMessage}{WorkerScript.onMessage()} handler.
- You must call sync() or else the changes made to the list from the external
+ Note the call to sync() from the \l{WorkerScript::onMessage}{WorkerScript.onMessage()}
+ handler. You must call sync() or else the changes made to the list from the external
thread will not be reflected in the list model in the main thread.
- \section3 Limitations
+ \section1 Restrictions
- If a list model is to be accessed from a WorkerScript, it \bold cannot
- contain list data. So, the following model cannot be used from a WorkerScript
+ If a list model is to be accessed from a WorkerScript, it cannot
+ contain list-type data. So, the following model cannot be used from a WorkerScript
because of the list contained in the "attributes" property:
\code
@@ -156,7 +196,7 @@ working-with-data
}
\endcode
- In addition, the WorkerScript cannot add any list data to the model.
+ In addition, the WorkerScript cannot add list-type data to the model.
\sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative
*/
@@ -177,17 +217,25 @@ working-with-data
*/
QDeclarativeListModel::QDeclarativeListModel(QObject *parent)
-: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0), m_isWorkerCopy(false)
+: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0)
{
}
-QDeclarativeListModel::QDeclarativeListModel(bool workerCopy, QObject *parent)
-: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0), m_isWorkerCopy(workerCopy)
+QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent)
+: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0)
{
- if (workerCopy)
- m_flat = new FlatListModel(this);
- else
- m_nested = new NestedListModel(this);
+ m_flat = new FlatListModel(this);
+ m_flat->m_parentAgent = parent;
+
+ if (orig->m_flat) {
+ m_flat->m_roles = orig->m_flat->m_roles;
+ m_flat->m_strings = orig->m_flat->m_strings;
+ m_flat->m_values = orig->m_flat->m_values;
+
+ m_flat->m_nodeData.reserve(m_flat->m_values.count());
+ for (int i=0; i<m_flat->m_values.count(); i++)
+ m_flat->m_nodeData << 0;
+ }
}
QDeclarativeListModel::~QDeclarativeListModel()
@@ -223,19 +271,28 @@ bool QDeclarativeListModel::flatten()
flat->m_strings.insert(s, roles[i]);
}
+ flat->m_nodeData.reserve(flat->m_values.count());
+ for (int i=0; i<flat->m_values.count(); i++)
+ flat->m_nodeData << 0;
+
m_flat = flat;
delete m_nested;
m_nested = 0;
return true;
}
+bool QDeclarativeListModel::inWorkerThread() const
+{
+ return m_flat && m_flat->m_parentAgent;
+}
+
QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent()
{
if (m_agent)
return m_agent;
if (!flatten()) {
- qmlInfo(this) << "List contains nested list values and cannot be used from a worker script";
+ qmlInfo(this) << "List contains list-type data and cannot be used from a worker script";
return 0;
}
@@ -293,12 +350,43 @@ void QDeclarativeListModel::clear()
else
m_nested->clear();
- if (!m_isWorkerCopy) {
+ if (!inWorkerThread()) {
emit itemsRemoved(0, cleared);
emit countChanged();
}
}
+QDeclarativeListModel *ModelNode::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
+
+ for (int i=0; i<values.count(); ++i) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(values.at(i));
+ if (subNode)
+ subNode->m_model = modelCache->m_nested;
+ }
+ }
+ return modelCache;
+}
+
+ModelObject *ModelNode::object(const NestedListModel *model)
+{
+ if (!objectCache) {
+ objectCache = new ModelObject(this,
+ const_cast<NestedListModel*>(model),
+ QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(model->m_listModel)));
+ QHash<QString, ModelNode *>::iterator it;
+ for (it = properties.begin(); it != properties.end(); ++it) {
+ objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it));
+ }
+ objectCache->setNodeUpdatesEnabled(true);
+ }
+ return objectCache;
+}
+
/*!
\qmlmethod ListModel::remove(int index)
@@ -318,7 +406,7 @@ void QDeclarativeListModel::remove(int index)
else
m_nested->remove(index);
- if (!m_isWorkerCopy) {
+ if (!inWorkerThread()) {
emit itemsRemoved(index, 1);
emit countChanged();
}
@@ -352,7 +440,7 @@ void QDeclarativeListModel::insert(int index, const QScriptValue& valuemap)
}
bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap);
- if (ok && !m_isWorkerCopy) {
+ if (ok && !inWorkerThread()) {
emit itemsInserted(index, 1);
emit countChanged();
}
@@ -376,7 +464,7 @@ void QDeclarativeListModel::move(int from, int to, int n)
{
if (n==0 || from==to)
return;
- if (from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0) {
+ if (!canMove(from, to, n)) {
qmlInfo(this) << tr("move: out of range");
return;
}
@@ -398,7 +486,7 @@ void QDeclarativeListModel::move(int from, int to, int n)
else
m_nested->move(from, to, n);
- if (!m_isWorkerCopy)
+ if (!inWorkerThread())
emit itemsMoved(origfrom, origto, orign);
}
@@ -427,11 +515,15 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap)
/*!
\qmlmethod object ListModel::get(int index)
- Returns the item at \a index in the list model.
+ Returns the item at \a index in the list model. This allows the item
+ data to be accessed or modified from JavaScript:
\code
- fruitModel.append({"cost": 5.95, "name":"Jackfruit"})
- fruitModel.get(0).cost
+ Component.onCompleted: {
+ fruitModel.append({"cost": 5.95, "name":"Jackfruit"});
+ console.log(fruitModel.get(0).cost);
+ fruitModel.get(0).cost = 10.95;
+ }
\endcode
The \a index must be an element in the list.
@@ -446,6 +538,9 @@ void QDeclarativeListModel::append(const QScriptValue& valuemap)
fruitModel.get(0).attributes.get(1).value; // == "green"
\endcode
+ \warning The returned object is not guaranteed to remain valid. It
+ should not be used in \l{Property Binding}{property bindings}.
+
\sa append()
*/
QScriptValue QDeclarativeListModel::get(int index) const
@@ -489,7 +584,7 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
else
m_nested->set(index, valuemap, &roles);
- if (!m_isWorkerCopy)
+ if (!inWorkerThread())
emit itemsChanged(index, 1, roles);
}
}
@@ -520,7 +615,7 @@ void QDeclarativeListModel::setProperty(int index, const QString& property, cons
else
m_nested->setProperty(index, property, value, &roles);
- if (!m_isWorkerCopy)
+ if (!inWorkerThread())
emit itemsChanged(index, 1, roles);
}
@@ -687,7 +782,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &
{
QDeclarativeListModel *rv = static_cast<QDeclarativeListModel *>(obj);
- ModelNode *root = new ModelNode;
+ ModelNode *root = new ModelNode(rv->m_nested);
rv->m_nested->_root = root;
QStack<ModelNode *> nodes;
nodes << root;
@@ -704,7 +799,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &
case ListInstruction::Push:
{
ModelNode *n = nodes.top();
- ModelNode *n2 = new ModelNode;
+ ModelNode *n2 = new ModelNode(rv->m_nested);
n->values << QVariant::fromValue(n2);
nodes.push(n2);
if (processingSet)
@@ -743,7 +838,7 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &
case ListInstruction::Set:
{
ModelNode *n = nodes.top();
- ModelNode *n2 = new ModelNode;
+ ModelNode *n2 = new ModelNode(rv->m_nested);
n->properties.insert(QString::fromUtf8(data + instr.dataIdx), n2);
nodes.push(n2);
processingSet = true;
@@ -751,6 +846,13 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray &
break;
}
}
+
+ ModelNode *rootNode = rv->m_nested->_root;
+ for (int i=0; i<rootNode->values.count(); ++i) {
+ ModelNode *node = qvariant_cast<ModelNode *>(rootNode->values[i]);
+ node->listIndex = i;
+ node->updateListIndexes();
+ }
}
bool QDeclarativeListModelParser::definesEmptyList(const QString &s)
@@ -765,22 +867,57 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s)
return false;
}
+
/*!
\qmlclass ListElement QDeclarativeListElement
\ingroup qml-working-with-data
\since 4.7
\brief The ListElement element defines a data item in a ListModel.
+ List elements are defined inside ListModel definitions, and represent items in a
+ list that will be displayed using ListView or \l Repeater items.
+
+ List elements are defined like other QML elements except that they contain
+ a collection of \e role definitions instead of properties. Using the same
+ syntax as property definitions, roles both define how the data is accessed
+ and include the data itself.
+
+ The names used for roles must begin with a lower-case letter and should be
+ common to all elements in a given model. Values must be simple constants; either
+ strings (quoted and optionally within a call to QT_TR_NOOP), boolean values
+ (true, false), numbers, or enumeration values (such as AlignText.AlignHCenter).
+
+ \section1 Referencing Roles
+
+ The role names are used by delegates to obtain data from list elements.
+ Each role name is accessible in the delegate's scope, and refers to the
+ corresponding role in the current element. Where a role name would be
+ ambiguous to use, it can be accessed via the \l{ListView::}{model}
+ property (e.g., \c{model.cost} instead of \c{cost}).
+
+ \section1 Example Usage
+
+ The following model defines a series of list elements, each of which
+ contain "name" and "cost" roles and their associated values.
+
+ \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml model
+
+ The delegate obtains the name and cost for each element by simply referring
+ to \c name and \c cost:
+
+ \snippet doc/src/snippets/declarative/qml-data-models/listelements.qml view
+
\sa ListModel
*/
FlatListModel::FlatListModel(QDeclarativeListModel *base)
- : m_scriptEngine(0), m_listModel(base)
+ : m_scriptEngine(0), m_listModel(base), m_scriptClass(0), m_parentAgent(0)
{
}
FlatListModel::~FlatListModel()
{
+ qDeleteAll(m_nodeData);
}
QHash<int,QVariant> FlatListModel::data(int index, const QList<int> &roles) const
@@ -824,11 +961,15 @@ int FlatListModel::count() const
void FlatListModel::clear()
{
m_values.clear();
+
+ qDeleteAll(m_nodeData);
+ m_nodeData.clear();
}
void FlatListModel::remove(int index)
{
m_values.removeAt(index);
+ removedNode(index);
}
bool FlatListModel::append(const QScriptValue &value)
@@ -845,6 +986,8 @@ bool FlatListModel::insert(int index, const QScriptValue &value)
return false;
m_values.insert(index, row);
+ insertedNode(index);
+
return true;
}
@@ -858,13 +1001,17 @@ QScriptValue FlatListModel::get(int index) const
if (index < 0 || index >= m_values.count())
return scriptEngine->undefinedValue();
- QScriptValue rv = scriptEngine->newObject();
+ FlatListModel *that = const_cast<FlatListModel*>(this);
+ if (!m_scriptClass)
+ that->m_scriptClass = new FlatListScriptClass(that, scriptEngine);
- 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()), scriptEngine->toScriptValue(iter.value()));
+ FlatNodeData *data = m_nodeData.value(index);
+ if (!data) {
+ data = new FlatNodeData(index);
+ that->m_nodeData.replace(index, data);
+ }
- return rv;
+ return QScriptDeclarativeClass::newObject(scriptEngine, m_scriptClass, new FlatNodeObjectData(data));
}
void FlatListModel::set(int index, const QScriptValue &value, QList<int> *roles)
@@ -896,23 +1043,8 @@ void FlatListModel::setProperty(int index, const QString& property, const QVaria
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;
- }
+ qdeclarativelistmodel_move<QList<QHash<int, QVariant> > >(from, to, n, &m_values);
+ moveNodes(from, to, n);
}
bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles)
@@ -922,7 +1054,7 @@ bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *ro
it.next();
QScriptValue value = it.value();
if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) {
- qmlInfo(m_listModel) << "Cannot add nested list values when modifying or after modification from a worker script";
+ qmlInfo(m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
return false;
}
@@ -942,6 +1074,139 @@ bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *ro
return true;
}
+void FlatListModel::insertedNode(int index)
+{
+ if (index >= 0 && index <= m_values.count()) {
+ m_nodeData.insert(index, 0);
+
+ for (int i=index + 1; i<m_nodeData.count(); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+ }
+}
+
+void FlatListModel::removedNode(int index)
+{
+ if (index >= 0 && index < m_nodeData.count()) {
+ delete m_nodeData.takeAt(index);
+
+ for (int i=index; i<m_nodeData.count(); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+ }
+}
+
+void FlatListModel::moveNodes(int from, int to, int n)
+{
+ if (!m_listModel->canMove(from, to, n))
+ return;
+
+ qdeclarativelistmodel_move<QList<FlatNodeData *> >(from, to, n, &m_nodeData);
+
+ for (int i=from; i<from + (to-from); i++) {
+ if (m_nodeData[i])
+ m_nodeData[i]->index = i;
+ }
+}
+
+
+
+FlatNodeData::~FlatNodeData()
+{
+ for (QSet<FlatNodeObjectData *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) {
+ FlatNodeObjectData *data = *iter;
+ data->nodeData = 0;
+ }
+}
+
+void FlatNodeData::addData(FlatNodeObjectData *data)
+{
+ objects.insert(data);
+}
+
+void FlatNodeData::removeData(FlatNodeObjectData *data)
+{
+ objects.remove(data);
+}
+
+
+FlatListScriptClass::FlatListScriptClass(FlatListModel *model, QScriptEngine *seng)
+ : QScriptDeclarativeClass(seng),
+ m_model(model)
+{
+}
+
+QScriptDeclarativeClass::Value FlatListScriptClass::property(Object *obj, const Identifier &name)
+{
+ FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj);
+ if (!objData->nodeData) // item at this index has been deleted
+ return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue());
+
+ int index = objData->nodeData->index;
+ QString propName = toString(name);
+ int role = m_model->m_strings.value(propName, -1);
+
+ if (role >= 0 && index >=0 ) {
+ const QHash<int, QVariant> &row = m_model->m_values[index];
+ QScriptValue sv = engine()->toScriptValue<QVariant>(row[role]);
+ return QScriptDeclarativeClass::Value(engine(), sv);
+ }
+
+ return QScriptDeclarativeClass::Value(engine(), engine()->undefinedValue());
+}
+
+void FlatListScriptClass::setProperty(Object *obj, const Identifier &name, const QScriptValue &value)
+{
+ if (!value.isVariant() && !value.isRegExp() && !value.isDate() && value.isObject()) {
+ qmlInfo(m_model->m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script";
+ return;
+ }
+
+ FlatNodeObjectData *objData = static_cast<FlatNodeObjectData*>(obj);
+ if (!objData->nodeData) // item at this index has been deleted
+ return;
+
+ int index = objData->nodeData->index;
+ QString propName = toString(name);
+
+ int role = m_model->m_strings.value(propName, -1);
+ if (role >= 0 && index >= 0) {
+ QHash<int, QVariant> &row = m_model->m_values[index];
+ row[role] = value.toVariant();
+
+ if (m_model->m_parentAgent) {
+ // This is the list in the worker thread, so tell the agent to
+ // emit itemsChanged() later
+ m_model->m_parentAgent->changedData(index, 1);
+ } else {
+ // This is the list in the main thread, so emit itemsChanged()
+ QList<int> roles;
+ roles << role;
+ emit m_model->m_listModel->itemsChanged(index, 1, roles);
+ }
+ }
+}
+
+QScriptClass::QueryFlags FlatListScriptClass::queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags)
+{
+ return (QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess);
+}
+
+bool FlatListScriptClass::compare(Object *obj1, Object *obj2)
+{
+ FlatNodeObjectData *data1 = static_cast<FlatNodeObjectData*>(obj1);
+ FlatNodeObjectData *data2 = static_cast<FlatNodeObjectData*>(obj2);
+
+ if (!data1->nodeData || !data2->nodeData)
+ return false;
+
+ return data1->nodeData->index == data2->nodeData->index;
+}
+
+
+
NestedListModel::NestedListModel(QDeclarativeListModel *base)
: _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false)
{
@@ -1067,11 +1332,12 @@ void NestedListModel::remove(int index)
bool NestedListModel::insert(int index, const QScriptValue& valuemap)
{
if (!_root) {
- _root = new ModelNode;
+ _root = new ModelNode(this);
m_ownsRoot = true;
}
- ModelNode *mn = new ModelNode;
+ ModelNode *mn = new ModelNode(this);
+ mn->listIndex = index;
mn->setObjectValue(valuemap);
_root->values.insert(index,QVariant::fromValue(mn));
return true;
@@ -1079,34 +1345,19 @@ bool NestedListModel::insert(int index, const QScriptValue& valuemap)
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;
- }
+ if (!_root)
+ return;
+ qdeclarativelistmodel_move<QVariantList>(from, to, n, &_root->values);
}
bool NestedListModel::append(const QScriptValue& valuemap)
{
if (!_root) {
- _root = new ModelNode;
+ _root = new ModelNode(this);
m_ownsRoot = true;
}
- ModelNode *mn = new ModelNode;
- mn->setObjectValue(valuemap);
- _root->values << QVariant::fromValue(mn);
+
+ insert(count(), valuemap);
return true;
}
@@ -1201,8 +1452,8 @@ QString NestedListModel::toString(int role) const
}
-ModelNode::ModelNode()
-: modelCache(0), objectCache(0), isArray(false)
+ModelNode::ModelNode(NestedListModel *model)
+: modelCache(0), objectCache(0), isArray(false), m_model(model), listIndex(-1)
{
}
@@ -1226,18 +1477,18 @@ void ModelNode::clear()
properties.clear();
}
-void ModelNode::setObjectValue(const QScriptValue& valuemap) {
+void ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache) {
QScriptValueIterator it(valuemap);
while (it.hasNext()) {
it.next();
- ModelNode *value = new ModelNode;
+ ModelNode *value = new ModelNode(m_model);
QScriptValue v = it.value();
if (v.isArray()) {
value->isArray = true;
value->setListValue(v);
} else {
value->values << v.toVariant();
- if (objectCache)
+ if (writeToCache && objectCache)
objectCache->setValue(it.name().toUtf8(), value->values.last());
}
if (properties.contains(it.name()))
@@ -1250,14 +1501,16 @@ void ModelNode::setListValue(const QScriptValue& valuelist) {
values.clear();
int size = valuelist.property(QLatin1String("length")).toInt32();
for (int i=0; i<size; i++) {
- ModelNode *value = new ModelNode;
+ ModelNode *value = new ModelNode(m_model);
QScriptValue v = valuelist.property(i);
if (v.isArray()) {
value->isArray = true;
value->setListValue(v);
} else if (v.isObject()) {
+ value->listIndex = i;
value->setObjectValue(v);
} else {
+ value->listIndex = i;
value->values << v.toVariant();
}
values.append(QVariant::fromValue(value));
@@ -1269,7 +1522,7 @@ void ModelNode::setProperty(const QString& prop, const QVariant& val) {
if (it != properties.end()) {
(*it)->values[0] = val;
} else {
- ModelNode *n = new ModelNode;
+ ModelNode *n = new ModelNode(m_model);
n->values << val;
properties.insert(prop,n);
}
@@ -1277,6 +1530,40 @@ void ModelNode::setProperty(const QString& prop, const QVariant& val) {
objectCache->setValue(prop.toUtf8(), val);
}
+void ModelNode::updateListIndexes()
+{
+ for (QHash<QString, ModelNode *>::ConstIterator iter = properties.begin(); iter != properties.end(); ++iter) {
+ ModelNode *node = iter.value();
+ if (node->isArray) {
+ for (int i=0; i<node->values.count(); ++i) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(i));
+ if (subNode)
+ subNode->listIndex = i;
+ }
+ }
+ node->updateListIndexes();
+ }
+}
+
+/*
+ Need to call this to emit itemsChanged() for modifications outside of set()
+ and setProperty(), i.e. if an item returned from get() is modified
+*/
+void ModelNode::changedProperty(const QString &name) const
+{
+ if (listIndex < 0)
+ return;
+
+ m_model->checkRoles();
+ QList<int> roles;
+ int role = m_model->roleStrings.indexOf(name);
+ if (role < 0)
+ roles = m_model->roles();
+ else
+ roles << role;
+ emit m_model->m_listModel->itemsChanged(listIndex, 1, roles);
+}
+
void ModelNode::dump(ModelNode *node, int ind)
{
QByteArray indentBa(ind * 4, ' ');
@@ -1298,16 +1585,47 @@ void ModelNode::dump(ModelNode *node, int ind)
}
}
-ModelObject::ModelObject()
-: _mo(new QDeclarativeOpenMetaObject(this))
+ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng)
+ : m_model(model),
+ m_node(node),
+ m_meta(new ModelNodeMetaObject(seng, this))
{
}
void ModelObject::setValue(const QByteArray &name, const QVariant &val)
{
- _mo->setValue(name, val);
+ m_meta->setValue(name, val);
setProperty(name.constData(), val);
}
+void ModelObject::setNodeUpdatesEnabled(bool enable)
+{
+ m_meta->m_enabled = enable;
+}
+
+
+ModelNodeMetaObject::ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object)
+ : QDeclarativeOpenMetaObject(object),
+ m_enabled(false),
+ m_seng(seng),
+ m_obj(object)
+{
+}
+
+void ModelNodeMetaObject::propertyWritten(int index)
+{
+ if (!m_enabled)
+ return;
+
+ QString propName = QString::fromUtf8(name(index));
+ QVariant value = operator[](index);
+
+ QScriptValue sv = m_seng->newObject();
+ sv.setProperty(propName, m_seng->newVariant(value));
+ m_obj->m_node->setObjectValue(sv, false);
+
+ m_obj->m_node->changedProperty(propName);
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h
index 6aff9c6..fe42ef6 100644
--- a/src/declarative/util/qdeclarativelistmodel_p.h
+++ b/src/declarative/util/qdeclarativelistmodel_p.h
@@ -63,6 +63,7 @@ class FlatListModel;
class NestedListModel;
class QDeclarativeListModelWorkerAgent;
struct ModelNode;
+class FlatListScriptClass;
class Q_DECLARATIVE_EXPORT QDeclarativeListModel : public QListModelInterface
{
Q_OBJECT
@@ -96,16 +97,21 @@ Q_SIGNALS:
private:
friend class QDeclarativeListModelParser;
friend class QDeclarativeListModelWorkerAgent;
+ friend class FlatListModel;
+ friend class FlatListScriptClass;
friend struct ModelNode;
- QDeclarativeListModel(bool workerCopy, QObject *parent=0);
+ // Constructs a flat list model for a worker agent
+ QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent);
+
bool flatten();
- bool modifyCheck();
+ bool inWorkerThread() const;
+
+ inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
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
index 8231414..d2d40ee 100644
--- a/src/declarative/util/qdeclarativelistmodel_p_p.h
+++ b/src/declarative/util/qdeclarativelistmodel_p_p.h
@@ -54,9 +54,11 @@
//
#include "private/qdeclarativelistmodel_p.h"
-
-#include "qdeclarative.h"
#include "private/qdeclarativeengine_p.h"
+#include "private/qdeclarativeopenmetaobject_p.h"
+#include "qdeclarative.h"
+
+#include <private/qscriptdeclarativeclass_p.h>
QT_BEGIN_HEADER
@@ -68,6 +70,8 @@ class QDeclarativeOpenMetaObject;
class QScriptEngine;
class QDeclarativeListModelWorkerAgent;
struct ModelNode;
+class FlatListScriptClass;
+class FlatNodeData;
class FlatListModel
{
@@ -94,16 +98,82 @@ public:
private:
friend class QDeclarativeListModelWorkerAgent;
friend class QDeclarativeListModel;
+ friend class FlatListScriptClass;
+ friend class FlatNodeData;
bool addValue(const QScriptValue &value, QHash<int, QVariant> *row, QList<int> *roles);
+ void insertedNode(int index);
+ void removedNode(int index);
+ void moveNodes(int from, int to, int n);
QScriptEngine *m_scriptEngine;
QHash<int, QString> m_roles;
QHash<QString, int> m_strings;
QList<QHash<int, QVariant> > m_values;
QDeclarativeListModel *m_listModel;
+
+ FlatListScriptClass *m_scriptClass;
+ QList<FlatNodeData *> m_nodeData;
+ QDeclarativeListModelWorkerAgent *m_parentAgent;
+};
+
+
+/*
+ Created when get() is called on a FlatListModel. This allows changes to the
+ object returned by get() to be tracked, and passed onto the model.
+*/
+class FlatListScriptClass : public QScriptDeclarativeClass
+{
+public:
+ FlatListScriptClass(FlatListModel *model, QScriptEngine *seng);
+
+ Value property(Object *, const Identifier &);
+ void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags);
+ bool compare(Object *, Object *);
+
+private:
+ FlatListModel *m_model;
+};
+
+/*
+ FlatNodeData and FlatNodeObjectData allow objects returned by get() to still
+ point to the correct list index if move(), insert() or remove() are called.
+*/
+struct FlatNodeObjectData;
+class FlatNodeData
+{
+public:
+ FlatNodeData(int i)
+ : index(i) {}
+
+ ~FlatNodeData();
+
+ void addData(FlatNodeObjectData *data);
+ void removeData(FlatNodeObjectData *data);
+
+ int index;
+
+private:
+ QSet<FlatNodeObjectData*> objects;
+};
+
+struct FlatNodeObjectData : public QScriptDeclarativeClass::Object
+{
+ FlatNodeObjectData(FlatNodeData *data) : nodeData(data) {
+ nodeData->addData(this);
+ }
+
+ ~FlatNodeObjectData() {
+ if (nodeData)
+ nodeData->removeData(this);
+ }
+
+ FlatNodeData *nodeData;
};
+
+
class NestedListModel
{
public:
@@ -134,25 +204,50 @@ public:
QDeclarativeListModel *m_listModel;
private:
+ friend struct ModelNode;
mutable QStringList roleStrings;
mutable bool _rolesOk;
};
+class ModelNodeMetaObject;
class ModelObject : public QObject
{
Q_OBJECT
public:
- ModelObject();
+ ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine *seng);
void setValue(const QByteArray &name, const QVariant &val);
+ void setNodeUpdatesEnabled(bool enable);
+
+ NestedListModel *m_model;
+ ModelNode *m_node;
private:
- QDeclarativeOpenMetaObject *_mo;
+ ModelNodeMetaObject *m_meta;
};
+class ModelNodeMetaObject : public QDeclarativeOpenMetaObject
+{
+public:
+ ModelNodeMetaObject(QScriptEngine *seng, ModelObject *object);
+
+ bool m_enabled;
+
+protected:
+ void propertyWritten(int index);
+
+private:
+ QScriptEngine *m_seng;
+ ModelObject *m_obj;
+};
+
+
+/*
+ A ModelNode is created for each item in a NestedListModel.
+*/
struct ModelNode
{
- ModelNode();
+ ModelNode(NestedListModel *model);
~ModelNode();
QList<QVariant> values;
@@ -160,35 +255,22 @@ struct ModelNode
void clear();
- 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;
- }
+ QDeclarativeListModel *model(const NestedListModel *model);
+ ModelObject *object(const NestedListModel *model);
-
- void setObjectValue(const QScriptValue& valuemap);
+ void setObjectValue(const QScriptValue& valuemap, bool writeToCache = true);
void setListValue(const QScriptValue& valuelist);
void setProperty(const QString& prop, const QVariant& val);
+ void changedProperty(const QString &name) const;
+ void updateListIndexes();
static void dump(ModelNode *node, int ind);
QDeclarativeListModel *modelCache;
ModelObject *objectCache;
bool isArray;
+
+ NestedListModel *m_model;
+ int listIndex; // only used for top-level nodes within a list
};
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
index d9df169..6804d4a 100644
--- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
@@ -83,11 +83,11 @@ void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count)
}
QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model)
-: m_engine(0), m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(true, this))
+ : m_engine(0),
+ m_ref(1),
+ m_orig(model),
+ m_copy(new QDeclarativeListModel(model, 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()
@@ -194,6 +194,11 @@ void QDeclarativeListModelWorkerAgent::sync()
mutex.unlock();
}
+void QDeclarativeListModelWorkerAgent::changedData(int index, int count)
+{
+ data.changedChange(index, count);
+}
+
bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
{
if (e->type() == QEvent::User) {
@@ -216,6 +221,24 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
orig->m_strings = copy->m_strings;
orig->m_values = copy->m_values;
+ // update the orig->m_nodeData list
+ for (int ii = 0; ii < changes.count(); ++ii) {
+ const Change &change = changes.at(ii);
+ switch (change.type) {
+ case Change::Inserted:
+ orig->insertedNode(change.index);
+ break;
+ case Change::Removed:
+ orig->removedNode(change.index);
+ break;
+ case Change::Moved:
+ orig->moveNodes(change.index, change.to, change.count);
+ break;
+ case Change::Changed:
+ break;
+ }
+ }
+
syncDone.wakeAll();
locker.unlock();
@@ -232,7 +255,7 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
emit m_orig->itemsMoved(change.index, change.to, change.count);
break;
case Change::Changed:
- emit m_orig->itemsChanged(change.index, change.to, orig->m_roles.keys());
+ emit m_orig->itemsChanged(change.index, change.count, orig->m_roles.keys());
break;
}
}
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
index 01da374..10c3bca 100644
--- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
@@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QDeclarativeListModel;
+class FlatListScriptClass;
class QDeclarativeListModelWorkerAgent : public QObject
{
@@ -115,6 +116,7 @@ protected:
private:
friend class QDeclarativeWorkerScriptEnginePrivate;
+ friend class FlatListScriptClass;
QScriptEngine *m_engine;
struct Change {
@@ -141,6 +143,8 @@ private:
QDeclarativeListModel *list;
};
+ void changedData(int index, int count);
+
QAtomicInt m_ref;
QDeclarativeListModel *m_orig;
QDeclarativeListModel *m_copy;
diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h
index b4d88bd..2e83cc4 100644
--- a/src/declarative/util/qdeclarativepixmapcache_p.h
+++ b/src/declarative/util/qdeclarativepixmapcache_p.h
@@ -98,7 +98,7 @@ public:
bool connectDownloadProgress(QObject *, int);
private:
- Q_DISABLE_COPY(QDeclarativePixmap);
+ Q_DISABLE_COPY(QDeclarativePixmap)
QDeclarativePixmapData *d;
};
diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp
index e897458..8d01b80 100644
--- a/src/declarative/util/qdeclarativepropertychanges.cpp
+++ b/src/declarative/util/qdeclarativepropertychanges.cpp
@@ -52,6 +52,7 @@
#include <qdeclarativeguard_p.h>
#include <qdeclarativeproperty_p.h>
#include <qdeclarativecontext_p.h>
+#include <qdeclarativestate_p_p.h>
#include <QtCore/qdebug.h>
@@ -200,14 +201,14 @@ public:
};
-class QDeclarativePropertyChangesPrivate : public QObjectPrivate
+class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate
{
Q_DECLARE_PUBLIC(QDeclarativePropertyChanges)
public:
- QDeclarativePropertyChangesPrivate() : object(0), decoded(true), restore(true),
+ QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
isExplicit(false) {}
- QObject *object;
+ QDeclarativeGuard<QObject> object;
QByteArray data;
bool decoded : 1;
@@ -497,4 +498,272 @@ void QDeclarativePropertyChanges::setIsExplicit(bool e)
d->isExplicit = e;
}
+bool QDeclarativePropertyChanges::containsValue(const QByteArray &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsExpression(const QByteArray &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsProperty(const QByteArray &name) const
+{
+ return containsValue(name) || containsExpression(name);
+}
+
+void QDeclarativePropertyChanges::changeValue(const QByteArray &name, const QVariant &value)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ expressionIterator.remove();
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+ d->property(name).write(value);
+ }
+
+ d->properties.append(PropertyEntry(name, value));
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ entry.second = value;
+ if (state() && state()->isStateActive())
+ d->property(name).write(value);
+ return;
+ }
+ }
+
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = QString::fromUtf8(name);
+ action.toValue = value;
+
+ propertyIterator.insert(PropertyEntry(name, value));
+ if (state() && state()->isStateActive()) {
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ d->property(name).write(value);
+ }
+}
+
+void QDeclarativePropertyChanges::changeExpression(const QByteArray &name, const QString &expression)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ bool hadValue = false;
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ hadValue = true;
+ break;
+ }
+ }
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ entry.second->setExpression(expression);
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ return;
+ }
+ }
+
+ QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
+ expressionIterator.insert(ExpressionEntry(name, newExpression));
+
+ if (state() && state()->isStateActive()) {
+ if (hadValue) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ state()->changeBindingInRevertList(object(), name, oldBinding);
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ } else {
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = QString::fromUtf8(name);
+
+
+ if (d->isExplicit) {
+ action.toValue = newExpression->evaluate();
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ action.toBinding = newBinding;
+ action.deletableToBinding = true;
+
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+
+ QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ }
+ }
+ // what about the signal handler?
+}
+
+QVariant QDeclarativePropertyChanges::property(const QByteArray &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ return QVariant(entry.second->expression());
+ }
+ }
+
+ return QVariant();
+}
+
+void QDeclarativePropertyChanges::removeProperty(const QByteArray &name)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ expressionIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+}
+
+QVariant QDeclarativePropertyChanges::value(const QByteArray &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ return QVariant();
+}
+
+QString QDeclarativePropertyChanges::expression(const QByteArray &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QByteArray, QDeclarativeExpression *> ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.first == name) {
+ return entry.second->expression();
+ }
+ }
+
+ return QString();
+}
+
+void QDeclarativePropertyChanges::detachFromState()
+{
+ if (state())
+ state()->removeAllEntriesFromRevertList(object());
+}
+
+void QDeclarativePropertyChanges::attachToState()
+{
+ if (state())
+ state()->addEntriesToRevertList(actions());
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepropertychanges_p.h b/src/declarative/util/qdeclarativepropertychanges_p.h
index 8578086..199928f 100644
--- a/src/declarative/util/qdeclarativepropertychanges_p.h
+++ b/src/declarative/util/qdeclarativepropertychanges_p.h
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QDeclarativePropertyChangesPrivate;
-class Q_AUTOTEST_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation
+class Q_DECLARATIVE_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation
{
Q_OBJECT
Q_DECLARE_PRIVATE(QDeclarativePropertyChanges)
@@ -74,6 +74,20 @@ public:
void setIsExplicit(bool);
virtual ActionList actions();
+
+ bool containsProperty(const QByteArray &name) const;
+ bool containsValue(const QByteArray &name) const;
+ bool containsExpression(const QByteArray &name) const;
+ void changeValue(const QByteArray &name, const QVariant &value);
+ void changeExpression(const QByteArray &name, const QString &expression);
+ void removeProperty(const QByteArray &name);
+ QVariant value(const QByteArray &name) const;
+ QString expression(const QByteArray &name) const;
+
+ void detachFromState();
+ void attachToState();
+
+ QVariant property(const QByteArray &name) const;
};
class QDeclarativePropertyChangesParser : public QDeclarativeCustomParser
diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp
index 1ed7923..0f5413e 100644
--- a/src/declarative/util/qdeclarativestate.cpp
+++ b/src/declarative/util/qdeclarativestate.cpp
@@ -304,7 +304,7 @@ void QDeclarativeStatePrivate::complete()
for (int ii = 0; ii < reverting.count(); ++ii) {
for (int jj = 0; jj < revertList.count(); ++jj) {
- if (revertList.at(jj).property == reverting.at(ii)) {
+ if (revertList.at(jj).property() == reverting.at(ii)) {
revertList.removeAt(jj);
break;
}
@@ -370,6 +370,192 @@ void QDeclarativeAction::deleteFromBinding()
}
}
+bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QByteArray &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) {
+ simpleAction.setValue(revertValue);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) {
+ if (simpleAction.binding())
+ simpleAction.binding()->destroy();
+
+ simpleAction.setBinding(binding);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QByteArray &name)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target && simpleAction.property().name().toUtf8() == name) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void QDeclarativeState::addEntryToRevertList(const QDeclarativeAction &action)
+{
+ Q_D(QDeclarativeState);
+
+ QDeclarativeSimpleAction simpleAction(action);
+
+ d->revertList.append(simpleAction);
+}
+
+void QDeclarativeState::removeAllEntriesFromRevertList(QObject *target)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ }
+ }
+ }
+}
+
+void QDeclarativeState::addEntriesToRevertList(const QList<QDeclarativeAction> &actionList)
+{
+ Q_D(QDeclarativeState);
+ if (isStateActive()) {
+ QList<QDeclarativeSimpleAction> simpleActionList;
+
+ QListIterator<QDeclarativeAction> actionListIterator(actionList);
+ while(actionListIterator.hasNext()) {
+ const QDeclarativeAction &action = actionListIterator.next();
+ QDeclarativeSimpleAction simpleAction(action);
+ action.property.write(action.toValue);
+ if (action.toBinding) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding)
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), action.toBinding, QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+
+ simpleActionList.append(simpleAction);
+ }
+
+ d->revertList.append(simpleActionList);
+ }
+}
+
+QVariant QDeclarativeState::valueInRevertList(QObject *target, const QByteArray &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name)
+ return simpleAction.value();
+ }
+ }
+
+ return QVariant();
+}
+
+QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QByteArray &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name)
+ return simpleAction.binding();
+ }
+ }
+
+ return 0;
+}
+
+bool QDeclarativeState::isStateActive() const
+{
+ return stateGroup() && stateGroup()->state() == name();
+}
+
void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransition *trans, QDeclarativeState *revert)
{
Q_D(QDeclarativeState);
@@ -403,13 +589,13 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
continue;
bool found = false;
for (int jj = 0; jj < d->revertList.count(); ++jj) {
- QDeclarativeActionEvent *event = d->revertList.at(jj).event;
+ QDeclarativeActionEvent *event = d->revertList.at(jj).event();
if (event && event->typeName() == action.event->typeName()) {
if (action.event->override(event)) {
found = true;
- if (action.event != d->revertList.at(jj).event && action.event->needsCopy()) {
- action.event->copyOriginals(d->revertList.at(jj).event);
+ if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) {
+ action.event->copyOriginals(d->revertList.at(jj).event());
QDeclarativeSimpleAction r(action);
additionalReverts << r;
@@ -434,9 +620,9 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
for (int jj = 0; jj < d->revertList.count(); ++jj) {
- if (d->revertList.at(jj).property == action.property) {
+ if (d->revertList.at(jj).property() == action.property) {
found = true;
- if (d->revertList.at(jj).binding != action.fromBinding) {
+ if (d->revertList.at(jj).binding() != action.fromBinding) {
action.deleteFromBinding();
}
break;
@@ -445,7 +631,7 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
if (!found) {
if (!action.restore) {
- action.deleteFromBinding();
+ action.deleteFromBinding();;
} else {
// Only need to revert the applyList action if the previous
// state doesn't have a higher priority revert already
@@ -460,8 +646,8 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
// into this state need to be translated into apply actions
for (int ii = 0; ii < d->revertList.count(); ++ii) {
bool found = false;
- if (d->revertList.at(ii).event) {
- QDeclarativeActionEvent *event = d->revertList.at(ii).event;
+ if (d->revertList.at(ii).event()) {
+ QDeclarativeActionEvent *event = d->revertList.at(ii).event();
if (!event->isReversable())
continue;
for (int jj = 0; !found && jj < applyList.count(); ++jj) {
@@ -474,31 +660,31 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
} else {
for (int jj = 0; !found && jj < applyList.count(); ++jj) {
const QDeclarativeAction &action = applyList.at(jj);
- if (action.property == d->revertList.at(ii).property)
+ if (action.property == d->revertList.at(ii).property())
found = true;
}
}
if (!found) {
- QVariant cur = d->revertList.at(ii).property.read();
+ QVariant cur = d->revertList.at(ii).property().read();
QDeclarativeAbstractBinding *delBinding =
- QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property, 0);
+ QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0);
if (delBinding)
delBinding->destroy();
QDeclarativeAction a;
- a.property = d->revertList.at(ii).property;
+ a.property = d->revertList.at(ii).property();
a.fromValue = cur;
- a.toValue = d->revertList.at(ii).value;
- a.toBinding = d->revertList.at(ii).binding;
- a.specifiedObject = d->revertList.at(ii).specifiedObject;
- a.specifiedProperty = d->revertList.at(ii).specifiedProperty;
- a.event = d->revertList.at(ii).event;
- a.reverseEvent = d->revertList.at(ii).reverseEvent;
+ a.toValue = d->revertList.at(ii).value();
+ a.toBinding = d->revertList.at(ii).binding();
+ a.specifiedObject = d->revertList.at(ii).specifiedObject();
+ a.specifiedProperty = d->revertList.at(ii).specifiedProperty();
+ a.event = d->revertList.at(ii).event();
+ a.reverseEvent = d->revertList.at(ii).reverseEvent();
if (a.event && a.event->isRewindable())
a.event->saveCurrentValues();
applyList << a;
// Store these special reverts in the reverting list
- d->reverting << d->revertList.at(ii).property;
+ d->reverting << d->revertList.at(ii).property();
}
}
// All the local reverts now become part of the ongoing revertList
@@ -526,4 +712,16 @@ QDeclarativeStateOperation::ActionList QDeclarativeStateOperation::actions()
return ActionList();
}
+QDeclarativeState *QDeclarativeStateOperation::state() const
+{
+ Q_D(const QDeclarativeStateOperation);
+ return d->m_state;
+}
+
+void QDeclarativeStateOperation::setState(QDeclarativeState *state)
+{
+ Q_D(QDeclarativeStateOperation);
+ d->m_state = state;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativestate_p.h b/src/declarative/util/qdeclarativestate_p.h
index 2e2ce7b..a0ab11b 100644
--- a/src/declarative/util/qdeclarativestate_p.h
+++ b/src/declarative/util/qdeclarativestate_p.h
@@ -111,6 +111,8 @@ public:
//### rename to QDeclarativeStateChange?
class QDeclarativeStateGroup;
+class QDeclarativeState;
+class QDeclarativeStateOperationPrivate;
class Q_DECLARATIVE_EXPORT QDeclarativeStateOperation : public QObject
{
Q_OBJECT
@@ -121,8 +123,15 @@ public:
virtual ActionList actions();
+ QDeclarativeState *state() const;
+ void setState(QDeclarativeState *state);
+
protected:
QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeStateOperation)
+ Q_DISABLE_COPY(QDeclarativeStateOperation)
};
typedef QDeclarativeStateOperation::ActionList QDeclarativeStateActions;
@@ -169,6 +178,18 @@ public:
QDeclarativeStateGroup *stateGroup() const;
void setStateGroup(QDeclarativeStateGroup *);
+ bool containsPropertyInRevertList(QObject *target, const QByteArray &name) const;
+ bool changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue);
+ bool changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding);
+ bool removeEntryFromRevertList(QObject *target, const QByteArray &name);
+ void addEntryToRevertList(const QDeclarativeAction &action);
+ void removeAllEntriesFromRevertList(QObject *target);
+ void addEntriesToRevertList(const QList<QDeclarativeAction> &actions);
+ QVariant valueInRevertList(QObject *target, const QByteArray &name) const;
+ QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QByteArray &name) const;
+
+ bool isStateActive() const;
+
Q_SIGNALS:
void completed();
diff --git a/src/declarative/util/qdeclarativestate_p_p.h b/src/declarative/util/qdeclarativestate_p_p.h
index 2ef9bb0..4fd8f21 100644
--- a/src/declarative/util/qdeclarativestate_p_p.h
+++ b/src/declarative/util/qdeclarativestate_p_p.h
@@ -61,6 +61,8 @@
#include <private/qdeclarativeproperty_p.h>
#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativebinding_p.h>
+
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
@@ -69,30 +71,123 @@ class QDeclarativeSimpleAction
{
public:
enum State { StartState, EndState };
- QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState)
+ QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState)
{
- property = a.property;
- specifiedObject = a.specifiedObject;
- specifiedProperty = a.specifiedProperty;
- event = a.event;
+ m_property = a.property;
+ m_specifiedObject = a.specifiedObject;
+ m_specifiedProperty = a.specifiedProperty;
+ m_event = a.event;
if (state == StartState) {
- value = a.fromValue;
- binding = QDeclarativePropertyPrivate::binding(property);
- reverseEvent = true;
+ m_value = a.fromValue;
+ if (QDeclarativePropertyPrivate::binding(m_property)) {
+ m_binding = QDeclarativeAbstractBinding::getPointer(QDeclarativePropertyPrivate::binding(m_property));
+ }
+ m_reverseEvent = true;
} else {
- value = a.toValue;
- binding = a.toBinding;
- reverseEvent = false;
+ m_value = a.toValue;
+ m_binding = QDeclarativeAbstractBinding::getPointer(a.toBinding);
+ m_reverseEvent = false;
}
}
- QDeclarativeProperty property;
- QVariant value;
- QDeclarativeAbstractBinding *binding;
- QObject *specifiedObject;
- QString specifiedProperty;
- QDeclarativeActionEvent *event;
- bool reverseEvent;
+ ~QDeclarativeSimpleAction()
+ {
+ }
+
+ QDeclarativeSimpleAction(const QDeclarativeSimpleAction &other)
+ : m_property(other.m_property),
+ m_value(other.m_value),
+ m_binding(QDeclarativeAbstractBinding::getPointer(other.binding())),
+ m_specifiedObject(other.m_specifiedObject),
+ m_specifiedProperty(other.m_specifiedProperty),
+ m_event(other.m_event),
+ m_reverseEvent(other.m_reverseEvent)
+ {
+ }
+
+ QDeclarativeSimpleAction &operator =(const QDeclarativeSimpleAction &other)
+ {
+ m_property = other.m_property;
+ m_value = other.m_value;
+ m_binding = QDeclarativeAbstractBinding::getPointer(other.binding());
+ m_specifiedObject = other.m_specifiedObject;
+ m_specifiedProperty = other.m_specifiedProperty;
+ m_event = other.m_event;
+ m_reverseEvent = other.m_reverseEvent;
+
+ return *this;
+ }
+
+ void setProperty(const QDeclarativeProperty &property)
+ {
+ m_property = property;
+ }
+
+ const QDeclarativeProperty &property() const
+ {
+ return m_property;
+ }
+
+ void setValue(const QVariant &value)
+ {
+ m_value = value;
+ }
+
+ const QVariant &value() const
+ {
+ return m_value;
+ }
+
+ void setBinding(QDeclarativeAbstractBinding *binding)
+ {
+ m_binding = QDeclarativeAbstractBinding::getPointer(binding);
+ }
+
+ QDeclarativeAbstractBinding *binding() const
+ {
+ return m_binding.data();
+ }
+
+ QObject *specifiedObject() const
+ {
+ return m_specifiedObject;
+ }
+
+ const QString &specifiedProperty() const
+ {
+ return m_specifiedProperty;
+ }
+
+ QDeclarativeActionEvent *event() const
+ {
+ return m_event;
+ }
+
+ bool reverseEvent() const
+ {
+ return m_reverseEvent;
+ }
+
+private:
+ QDeclarativeProperty m_property;
+ QVariant m_value;
+ QDeclarativeAbstractBinding::Pointer m_binding;
+ QObject *m_specifiedObject;
+ QString m_specifiedProperty;
+ QDeclarativeActionEvent *m_event;
+ bool m_reverseEvent;
+};
+
+class QDeclarativeStateOperationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeStateOperation)
+
+public:
+
+ QDeclarativeStateOperationPrivate()
+ : m_state(0) {}
+
+ QDeclarativeState *m_state;
};
class QDeclarativeStatePrivate : public QObjectPrivate
@@ -122,10 +217,14 @@ public:
static void operations_append(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, QDeclarativeStateOperation *op) {
QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ op->setState(qobject_cast<QDeclarativeState*>(prop->object));
list->append(OperationGuard(op, list));
}
static void operations_clear(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ QMutableListIterator<OperationGuard> listIterator(*list);
+ while(listIterator.hasNext())
+ listIterator.next()->setState(0);
list->clear();
}
static int operations_count(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp
index 845b3da..8cb813c 100644
--- a/src/declarative/util/qdeclarativestateoperations.cpp
+++ b/src/declarative/util/qdeclarativestateoperations.cpp
@@ -52,6 +52,7 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativebinding_p.h"
+#include "private/qdeclarativestate_p_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qgraphicsitem.h>
@@ -61,7 +62,7 @@
QT_BEGIN_NAMESPACE
-class QDeclarativeParentChangePrivate : public QObjectPrivate
+class QDeclarativeParentChangePrivate : public QDeclarativeStateOperationPrivate
{
Q_DECLARE_PUBLIC(QDeclarativeParentChange)
public:
@@ -98,14 +99,15 @@ void QDeclarativeParentChangePrivate::doChange(QDeclarativeItem *targetParent, Q
qreal scale = 1;
qreal rotation = 0;
- if (ok && transform.type() != QTransform::TxRotate) {
+ bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
+ if (ok && !isRotate) {
if (transform.m11() == transform.m22())
scale = transform.m11();
else {
qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under non-uniform scale");
ok = false;
}
- } else if (ok && transform.type() == QTransform::TxRotate) {
+ } else if (ok && isRotate) {
if (transform.m11() == transform.m22())
scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
else {
@@ -579,7 +581,7 @@ void QDeclarativeParentChange::rewind()
d->doChange(d->rewindParent, d->rewindStackBefore);
}
-class QDeclarativeStateChangeScriptPrivate : public QObjectPrivate
+class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate
{
public:
QDeclarativeStateChangeScriptPrivate() {}
@@ -964,7 +966,7 @@ void QDeclarativeAnchorSet::resetCenterIn()
}
-class QDeclarativeAnchorChangesPrivate : public QObjectPrivate
+class QDeclarativeAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
{
public:
QDeclarativeAnchorChangesPrivate()
@@ -1029,6 +1031,11 @@ public:
bool applyOrigVCenter;
bool applyOrigBaseline;
+ QDeclarativeNullableValue<qreal> origWidth;
+ QDeclarativeNullableValue<qreal> origHeight;
+ qreal origX;
+ qreal origY;
+
QList<QDeclarativeAbstractBinding*> oldBindings;
QDeclarativeProperty leftProp;
@@ -1320,6 +1327,42 @@ void QDeclarativeAnchorChanges::reverse(Reason reason)
QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
if (d->origBaselineBinding)
QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
+
+ //restore any absolute geometry changed by the state's anchors
+ QDeclarativeAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Vertical_Mask;
+ QDeclarativeAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Vertical_Mask;
+ QDeclarativeAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Horizontal_Mask;
+ QDeclarativeAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Horizontal_Mask;
+
+ bool stateSetWidth = (stateHAnchors &&
+ stateHAnchors != QDeclarativeAnchors::LeftAnchor &&
+ stateHAnchors != QDeclarativeAnchors::RightAnchor &&
+ stateHAnchors != QDeclarativeAnchors::HCenterAnchor);
+ bool origSetWidth = (origHAnchors &&
+ origHAnchors != QDeclarativeAnchors::LeftAnchor &&
+ origHAnchors != QDeclarativeAnchors::RightAnchor &&
+ origHAnchors != QDeclarativeAnchors::HCenterAnchor);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
+ d->target->setWidth(d->origWidth.value);
+
+ bool stateSetHeight = (stateVAnchors &&
+ stateVAnchors != QDeclarativeAnchors::TopAnchor &&
+ stateVAnchors != QDeclarativeAnchors::BottomAnchor &&
+ stateVAnchors != QDeclarativeAnchors::VCenterAnchor &&
+ stateVAnchors != QDeclarativeAnchors::BaselineAnchor);
+ bool origSetHeight = (origVAnchors &&
+ origVAnchors != QDeclarativeAnchors::TopAnchor &&
+ origVAnchors != QDeclarativeAnchors::BottomAnchor &&
+ origVAnchors != QDeclarativeAnchors::VCenterAnchor &&
+ origVAnchors != QDeclarativeAnchors::BaselineAnchor);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
+ d->target->setHeight(d->origHeight.value);
+
+ if (stateHAnchors && !origHAnchors)
+ d->target->setX(d->origX);
+
+ if (stateVAnchors && !origVAnchors)
+ d->target->setY(d->origY);
}
QString QDeclarativeAnchorChanges::typeName() const
@@ -1382,6 +1425,14 @@ void QDeclarativeAnchorChanges::saveOriginals()
d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp);
d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp);
+ QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
+ if (targetPrivate->widthValid)
+ d->origWidth = d->target->width();
+ if (targetPrivate->heightValid)
+ d->origHeight = d->target->height();
+ d->origX = d->target->x();
+ d->origY = d->target->y();
+
d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
= d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
@@ -1414,6 +1465,11 @@ void QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
d->origVCenterBinding = acp->origVCenterBinding;
d->origBaselineBinding = acp->origBaselineBinding;
+ d->origWidth = acp->origWidth;
+ d->origHeight = acp->origHeight;
+ d->origX = acp->origX;
+ d->origY = acp->origY;
+
d->oldBindings.clear();
d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding
<< acp->topBinding << acp->bottomBinding << acp->baselineBinding;
diff --git a/src/declarative/util/qdeclarativetransitionmanager.cpp b/src/declarative/util/qdeclarativetransitionmanager.cpp
index d82c4bb..89b0044 100644
--- a/src/declarative/util/qdeclarativetransitionmanager.cpp
+++ b/src/declarative/util/qdeclarativetransitionmanager.cpp
@@ -86,8 +86,8 @@ void QDeclarativeTransitionManager::complete()
d->applyBindings();
for (int ii = 0; ii < d->completeList.count(); ++ii) {
- const QDeclarativeProperty &prop = d->completeList.at(ii).property;
- prop.write(d->completeList.at(ii).value);
+ const QDeclarativeProperty &prop = d->completeList.at(ii).property();
+ prop.write(d->completeList.at(ii).value());
}
d->completeList.clear();
diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp
index 905ef1e..870a523 100644
--- a/src/declarative/util/qdeclarativexmllistmodel.cpp
+++ b/src/declarative/util/qdeclarativexmllistmodel.cpp
@@ -209,8 +209,9 @@ Q_SIGNALS:
protected:
void run() {
+ m_mutex.lock();
+
while (!m_quit) {
- m_mutex.lock();
if (!m_jobs.isEmpty())
m_currentJob = m_jobs.dequeue();
m_mutex.unlock();
@@ -230,12 +231,13 @@ protected:
m_mutex.lock();
if (m_currentJob.queryId != -1 && m_abortQueryId != m_currentJob.queryId)
emit queryCompleted(r);
- if (m_jobs.isEmpty())
+ if (m_jobs.isEmpty() && !m_quit)
m_condition.wait(&m_mutex);
m_currentJob.queryId = -1;
m_abortQueryId = -1;
- m_mutex.unlock();
}
+
+ m_mutex.unlock();
}
private: