summaryrefslogtreecommitdiffstats
path: root/src/declarative/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/util')
-rw-r--r--src/declarative/util/qdeclarativeanimation.cpp112
-rw-r--r--src/declarative/util/qdeclarativeanimation_p.h21
-rw-r--r--src/declarative/util/qdeclarativeanimation_p_p.h13
-rw-r--r--src/declarative/util/qdeclarativefontloader.cpp19
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp987
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p.h21
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p_p.h199
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp240
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent_p.h155
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp41
-rw-r--r--src/declarative/util/qdeclarativepropertychanges.cpp3
-rw-r--r--src/declarative/util/qdeclarativestate.cpp62
-rw-r--r--src/declarative/util/qdeclarativestate_p.h8
-rw-r--r--src/declarative/util/qdeclarativestateoperations.cpp251
-rw-r--r--src/declarative/util/qdeclarativestateoperations_p.h9
-rw-r--r--src/declarative/util/qdeclarativetransitionmanager.cpp26
-rw-r--r--src/declarative/util/qdeclarativeutilmodule.cpp76
-rw-r--r--src/declarative/util/qdeclarativeview.cpp5
-rw-r--r--src/declarative/util/qdeclarativexmllistmodel.cpp55
-rw-r--r--src/declarative/util/util.pri8
20 files changed, 1801 insertions, 510 deletions
diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp
index 81c548b..461d626 100644
--- a/src/declarative/util/qdeclarativeanimation.cpp
+++ b/src/declarative/util/qdeclarativeanimation.cpp
@@ -132,7 +132,7 @@ QDeclarativeAbstractAnimation::QDeclarativeAbstractAnimation(QDeclarativeAbstrac
using the \c start() and \c stop() methods.
By default, animations are not running. Though, when the animations are assigned to properties,
- as property value sources, they are set to running by default.
+ as property value sources using the \e on syntax, they are set to running by default.
*/
bool QDeclarativeAbstractAnimation::isRunning() const
{
@@ -1877,13 +1877,17 @@ void QDeclarativePropertyAnimation::setTo(const QVariant &t)
}
/*!
- \qmlproperty QEasingCurve PropertyAnimation::easing
- \brief the easing curve used for the transition.
+ \qmlproperty enum PropertyAnimation::easing.type
+ \qmlproperty real PropertyAnimation::easing.amplitude
+ \qmlproperty real PropertyAnimation::easing.overshoot
+ \qmlproperty real PropertyAnimation::easing.period
+ \brief the easing curve used for the animation.
- For the easing you can specify the following parameters: type, amplitude, period and overshoot.
+ To specify an easing curve you need to specify at least the type. For some curves you can also specify
+ amplitude, period and/or overshoot (more details provided after the table).
\qml
- PropertyAnimation { properties: "y"; easing.type: "InOutElastc"; easing.amplitude: 2.0; easing.period: 1.5 }
+ PropertyAnimation { properties: "y"; easing.type: "InOutElastic"; easing.amplitude: 2.0; easing.period: 1.5 }
\endqml
Available types are:
@@ -2447,12 +2451,15 @@ QDeclarativeParentAnimation::QDeclarativeParentAnimation(QObject *parent)
QDeclarative_setParent_noEvent(d->topLevelGroup, this);
d->startAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->startAction, d->topLevelGroup);
d->topLevelGroup->addAnimation(d->startAction);
d->ag = new QParallelAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, d->topLevelGroup);
d->topLevelGroup->addAnimation(d->ag);
d->endAction = new QActionAnimation;
+ QDeclarative_setParent_noEvent(d->endAction, d->topLevelGroup);
d->topLevelGroup->addAnimation(d->endAction);
}
@@ -2743,4 +2750,99 @@ QAbstractAnimation *QDeclarativeParentAnimation::qtAnimation()
return d->topLevelGroup;
}
+/*!
+ \qmlclass AnchorAnimation QDeclarativeAnchorAnimation
+ \since 4.7
+ \inherits Animation
+ \brief The AnchorAnimation element allows you to animate anchor changes.
+
+ AnchorAnimation will animated any changes specified by a state's AnchorChanges.
+ In the following snippet we animate the addition of a right anchor to our item.
+ \qml
+ Item {
+ id: myItem
+ width: 100
+ }
+ ...
+ State {
+ AnchorChanges {
+ target: myItem
+ anchors.right: container.right
+ }
+ }
+ ...
+ Transition {
+ //smoothly reanchor myItem and move into new position
+ AnchorAnimation {}
+ }
+ \endqml
+
+ \sa AnchorChanges
+*/
+
+QDeclarativeAnchorAnimation::QDeclarativeAnchorAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativeAnchorAnimationPrivate), parent)
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ d->va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(d->va, this);
+}
+
+QDeclarativeAnchorAnimation::~QDeclarativeAnchorAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeAnchorAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ return d->va;
+}
+
+/*!
+ \qmlproperty list<Item> AnchorAnimation::targets
+ The items to reanchor.
+
+ If no targets are specified all AnchorChanges will be
+ animated by the AnchorAnimation.
+*/
+QDeclarativeListProperty<QDeclarativeItem> QDeclarativeAnchorAnimation::targets()
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ return QDeclarativeListProperty<QDeclarativeItem>(this, d->targets);
+}
+
+void QDeclarativeAnchorAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeAnchorAnimation);
+ PropertyUpdater *data = new PropertyUpdater;
+ data->interpolatorType = QMetaType::QReal;
+ data->interpolator = d->interpolator;
+
+ data->reverse = direction == Backward ? true : false;
+ data->fromSourced = false;
+ data->fromDefined = false;
+
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+ if (action.event && action.event->typeName() == QLatin1String("AnchorChanges")
+ && (d->targets.isEmpty() || d->targets.contains(static_cast<QDeclarativeAnchorChanges*>(action.event)->object()))) {
+ data->actions << static_cast<QDeclarativeAnchorChanges*>(action.event)->additionalActions();
+ }
+ }
+
+ if (data->actions.count()) {
+ if (!d->rangeIsSet) {
+ d->va->setStartValue(qreal(0));
+ d->va->setEndValue(qreal(1));
+ d->rangeIsSet = true;
+ }
+ d->va->setAnimValue(data, QAbstractAnimation::DeleteWhenStopped);
+ d->va->setFromSourcedValue(&data->fromSourced);
+ } else {
+ delete data;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h
index af48309..eb339f6 100644
--- a/src/declarative/util/qdeclarativeanimation_p.h
+++ b/src/declarative/util/qdeclarativeanimation_p.h
@@ -480,6 +480,26 @@ protected:
virtual QAbstractAnimation *qtAnimation();
};
+class QDeclarativeAnchorAnimationPrivate;
+class QDeclarativeAnchorAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnchorAnimation)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeItem> targets READ targets)
+
+public:
+ QDeclarativeAnchorAnimation(QObject *parent=0);
+ virtual ~QDeclarativeAnchorAnimation();
+
+ QDeclarativeListProperty<QDeclarativeItem> targets();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QDeclarativeAbstractAnimation)
@@ -495,6 +515,7 @@ QML_DECLARE_TYPE(QDeclarativeParallelAnimation)
QML_DECLARE_TYPE(QDeclarativeVector3dAnimation)
QML_DECLARE_TYPE(QDeclarativeRotationAnimation)
QML_DECLARE_TYPE(QDeclarativeParentAnimation)
+QML_DECLARE_TYPE(QDeclarativeAnchorAnimation)
QT_END_HEADER
diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h
index ae82a90..0460312 100644
--- a/src/declarative/util/qdeclarativeanimation_p_p.h
+++ b/src/declarative/util/qdeclarativeanimation_p_p.h
@@ -393,6 +393,19 @@ public:
QPointF computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const;
};
+class QDeclarativeAnchorAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnchorAnimation)
+public:
+ QDeclarativeAnchorAnimationPrivate() : rangeIsSet(false), va(0),
+ interpolator(QVariantAnimationPrivate::getInterpolator(QMetaType::QReal)) {}
+
+ bool rangeIsSet;
+ QDeclarativeBulkValueAnimator *va;
+ QVariantAnimation::Interpolator interpolator;
+ QList<QDeclarativeItem*> targets;
+};
+
QT_END_NAMESPACE
#endif // QDECLARATIVEANIMATION_P_H
diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp
index 8f5f537..bf98d40 100644
--- a/src/declarative/util/qdeclarativefontloader.cpp
+++ b/src/declarative/util/qdeclarativefontloader.cpp
@@ -61,7 +61,7 @@ class QDeclarativeFontLoaderPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QDeclarativeFontLoader)
public:
- QDeclarativeFontLoaderPrivate() : reply(0), status(QDeclarativeFontLoader::Null) {}
+ QDeclarativeFontLoaderPrivate() : reply(0), status(QDeclarativeFontLoader::Null), redirectCount(0) {}
void addFontToDatabase(const QByteArray &);
@@ -69,6 +69,7 @@ public:
QString name;
QNetworkReply *reply;
QDeclarativeFontLoader::Status status;
+ int redirectCount;
};
@@ -206,15 +207,31 @@ 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;
+ qWarning() << "Cannot load font:" << d->reply->url();
emit statusChanged();
}
d->reply->deleteLater();
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
index b968ca5..5b0a7ea 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
@@ -96,9 +94,12 @@ static void dump(ModelNode *node, int ind);
}
\endcode
- Roles (properties) must begin with a lower-case letter. The above example defines a
+ Roles (properties) must begin with a lower-case letter.The above example defines a
ListModel containing three elements, with the roles "name" and "cost".
+ Values must be simple constants - either strings (quoted), bools (true, false), numbers,
+ or enum values (like Text.AlignHCenter).
+
The defined model can be used in views such as ListView:
\code
Component {
@@ -169,6 +170,8 @@ static void dump(ModelNode *node, int ind);
}
\endcode
+ \section2 Modifying list models
+
The content of a ListModel may be created and modified using the clear(),
append(), and set() methods. For example:
@@ -193,252 +196,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;
- }
+ 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 setObjectValue(const QScriptValue& valuemap);
- void setListValue(const QScriptValue& valuelist);
+ \section3 Limitations
- 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);
- }
-
- QDeclarativeListModel *modelCache;
- ModelObject *objectCache;
- bool isArray;
-};
-
-QT_END_NAMESPACE
+ 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:
-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) {
- int size = valuelist.property(QString::fromLatin1("length")).toInt32();
- values.clear();
- for (int i = 0; i < size; ++i) {
- ModelNode *value = new ModelNode;
- QScriptValue v = valuelist.property(i);
- 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));
-
- 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 QHash<int, QVariant>();
- 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);
}
/*!
@@ -447,8 +344,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();
}
/*!
@@ -462,12 +358,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);
+ }
}
/*!
@@ -479,17 +378,20 @@ 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 itemsRemoved(index, 1);
+ emit countChanged(this->count());
+ }
}
/*!
@@ -513,20 +415,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());
+ }
}
/*!
@@ -551,9 +450,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;
@@ -562,24 +462,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);
}
/*!
@@ -600,13 +490,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);
}
/*!
@@ -640,15 +525,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);
}
/*!
@@ -672,27 +549,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);
}
}
@@ -711,22 +583,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)
@@ -736,7 +619,7 @@ bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParser
const QVariant &value = values.at(ii);
if(value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
- QDeclarativeCustomParserNode node =
+ QDeclarativeCustomParserNode node =
qvariant_cast<QDeclarativeCustomParserNode>(value);
{
@@ -783,7 +666,7 @@ bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParser
} else {
- QDeclarativeParser::Variant variant =
+ QDeclarativeParser::Variant variant =
qvariant_cast<QDeclarativeParser::Variant>(value);
int ref = data.count();
@@ -798,10 +681,17 @@ bool QDeclarativeListModelParser::compileProperty(const QDeclarativeCustomParser
d += char(variant.asBoolean());
} else if (variant.isScript()) {
if (definesEmptyList(variant.asScript())) {
- d[0] = 0; // QDeclarativeParser::Variant::Invalid - marks empty list
+ d[0] = char(QDeclarativeParser::Variant::Invalid); // marks empty list
} else {
- error(prop, QDeclarativeListModel::tr("ListElement: cannot use script for property value"));
- return false;
+ QByteArray script = variant.asScript().toUtf8();
+ int v = evaluateEnum(script);
+ if (v<0) {
+ error(prop, QDeclarativeListModel::tr("ListElement: cannot use script for property value"));
+ return false;
+ } else {
+ d[0] = char(QDeclarativeParser::Variant::Number);
+ d += QByteArray::number(v);
+ }
}
}
d.append('\0');
@@ -834,15 +724,15 @@ QByteArray QDeclarativeListModelParser::compile(const QList<QDeclarativeCustomPa
}
}
- int size = sizeof(ListModelData) +
- instr.count() * sizeof(ListInstruction) +
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
data.count();
QByteArray rv;
rv.resize(size);
ListModelData *lmd = (ListModelData *)rv.data();
- lmd->dataOffset = sizeof(ListModelData) +
+ lmd->dataOffset = sizeof(ListModelData) +
instr.count() * sizeof(ListInstruction);
lmd->instrCount = instr.count();
for (int ii = 0; ii < instr.count(); ++ii)
@@ -857,7 +747,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;
@@ -942,7 +832,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();
@@ -963,22 +1337,15 @@ 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>
+QT_END_NAMESPACE
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..2951262
--- /dev/null
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** 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
+{
+ 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 ListModel worker: sync() failed");
+ 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());
+ }
+ }
+
+ 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/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
index cfb25dd..942d5f6 100644
--- a/src/declarative/util/qdeclarativepixmapcache.cpp
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -137,7 +137,7 @@ class QDeclarativeImageRequestHandler : public QObject
Q_OBJECT
public:
QDeclarativeImageRequestHandler(QDeclarativeImageReader *read, QDeclarativeEngine *eng)
- : QObject(), accessManager(0), engine(eng), reader(read)
+ : QObject(), accessManager(0), engine(eng), reader(read), redirectCount(0)
{
QCoreApplication::postEvent(this, new QEvent(QEvent::User));
}
@@ -162,18 +162,24 @@ private:
QNetworkAccessManager *accessManager;
QDeclarativeEngine *engine;
QDeclarativeImageReader *reader;
+ int redirectCount;
+
+ static int replyDownloadProgress;
+ static int replyFinished;
+ static int downloadProgress;
+ static int thisNetworkRequestDone;
};
//===========================================================================
+int QDeclarativeImageRequestHandler::replyDownloadProgress = -1;
+int QDeclarativeImageRequestHandler::replyFinished = -1;
+int QDeclarativeImageRequestHandler::downloadProgress = -1;
+int QDeclarativeImageRequestHandler::thisNetworkRequestDone = -1;
+
bool QDeclarativeImageRequestHandler::event(QEvent *event)
{
if (event->type() == QEvent::User) {
- static int replyDownloadProgress = -1;
- static int replyFinished = -1;
- static int downloadProgress = -1;
- static int thisNetworkRequestDone = -1;
-
if (replyDownloadProgress == -1) {
replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()");
@@ -264,10 +270,33 @@ bool QDeclarativeImageRequestHandler::event(QEvent *event)
return QObject::event(event);
}
+#define IMAGEREQUESTHANDLER_MAX_REDIRECT_RECURSION 16
+
void QDeclarativeImageRequestHandler::networkRequestDone()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
QDeclarativePixmapReply *job = replies.take(reply);
+
+ redirectCount++;
+ if (redirectCount < IMAGEREQUESTHANDLER_MAX_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+
+ reply->deleteLater();
+ reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, job, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone);
+
+ replies.insert(reply, job);
+ return;
+ }
+ }
+ redirectCount=0;
+
if (job) {
QImage image;
QDeclarativeImageReaderEvent::ReadError error;
diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp
index 9c2b1e6..8865e04 100644
--- a/src/declarative/util/qdeclarativepropertychanges.cpp
+++ b/src/declarative/util/qdeclarativepropertychanges.cpp
@@ -439,7 +439,8 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
if (d->isExplicit) {
a.toValue = d->expressions.at(ii).second->value();
} else {
- QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this));
+ QDeclarativeBinding *newBinding =
+ new QDeclarativeBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this));
newBinding->setTarget(prop);
a.toBinding = newBinding;
a.deletableToBinding = true;
diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp
index 1d70d33..802ff1c 100644
--- a/src/declarative/util/qdeclarativestate.cpp
+++ b/src/declarative/util/qdeclarativestate.cpp
@@ -96,21 +96,12 @@ void QDeclarativeActionEvent::reverse()
{
}
-QList<QDeclarativeAction> QDeclarativeActionEvent::extraActions()
-{
- return QList<QDeclarativeAction>();
-}
-
bool QDeclarativeActionEvent::changesBindings()
{
return false;
}
-void QDeclarativeActionEvent::clearForwardBindings()
-{
-}
-
-void QDeclarativeActionEvent::clearReverseBindings()
+void QDeclarativeActionEvent::clearBindings()
{
}
@@ -368,47 +359,60 @@ void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransit
for (int ii = 0; ii < applyList.count(); ++ii) {
QDeclarativeAction &action = applyList[ii];
- bool found = false;
-
- int jj;
if (action.event) {
if (!action.event->isReversable())
continue;
- for (jj = 0; jj < d->revertList.count(); ++jj) {
+ bool found = false;
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
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->copyOriginals(d->revertList.at(jj).event);
+
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ d->revertList.removeAt(jj);
+ } else if (action.event->isRewindable()) //###why needed?
+ action.event->saveCurrentValues();
+
break;
}
}
}
- if (!found || action.event != d->revertList.at(jj).event)
+ if (!found) {
action.event->saveOriginals();
- else if (action.event->isRewindable())
- action.event->saveCurrentValues();
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
} else {
+ bool found = false;
action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
- for (jj = 0; jj < d->revertList.count(); ++jj) {
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
if (d->revertList.at(jj).property == action.property) {
found = true;
+ if (d->revertList.at(jj).binding != action.fromBinding) {
+ action.deleteFromBinding();
+ }
break;
}
}
- }
- if (!found) {
- if (!action.restore) {
- action.deleteFromBinding();
- } else {
- // Only need to revert the applyList action if the previous
- // state doesn't have a higher priority revert already
- QDeclarativeSimpleAction r(action);
- additionalReverts << r;
+ if (!found) {
+ if (!action.restore) {
+ action.deleteFromBinding();
+ } else {
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
}
- } else if (d->revertList.at(jj).binding != action.fromBinding) {
- action.deleteFromBinding();
}
}
diff --git a/src/declarative/util/qdeclarativestate_p.h b/src/declarative/util/qdeclarativestate_p.h
index 0c6e7a3..ee2b7e8 100644
--- a/src/declarative/util/qdeclarativestate_p.h
+++ b/src/declarative/util/qdeclarativestate_p.h
@@ -92,17 +92,15 @@ public:
virtual bool isReversable();
virtual void reverse();
virtual void saveOriginals() {}
+ virtual void copyOriginals(QDeclarativeActionEvent *) {}
virtual bool isRewindable() { return isReversable(); }
virtual void rewind() {}
virtual void saveCurrentValues() {}
-
- //virtual bool hasExtraActions();
- virtual QList<QDeclarativeAction> extraActions();
+ virtual void saveTargetValues() {}
virtual bool changesBindings();
- virtual void clearForwardBindings();
- virtual void clearReverseBindings();
+ virtual void clearBindings();
virtual bool override(QDeclarativeActionEvent*other);
};
diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp
index 766d1bc..6f5bb66 100644
--- a/src/declarative/util/qdeclarativestateoperations.cpp
+++ b/src/declarative/util/qdeclarativestateoperations.cpp
@@ -403,6 +403,17 @@ void QDeclarativeParentChange::saveOriginals()
d->origStackBefore = d->rewindStackBefore;
}
+void QDeclarativeParentChange::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QDeclarativeParentChange);
+ QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(other);
+
+ d->origParent = pc->d_func()->rewindParent;
+ d->origStackBefore = pc->d_func()->rewindStackBefore;
+
+ saveCurrentValues();
+}
+
void QDeclarativeParentChange::execute()
{
Q_D(QDeclarativeParentChange);
@@ -561,11 +572,17 @@ QString QDeclarativeStateChangeScript::typeName() const
\qmlclass AnchorChanges QDeclarativeAnchorChanges
\brief The AnchorChanges element allows you to change the anchors of an item in a state.
- AnchorChanges will 'inject' \c x, \c y, \c width, and \c height changes into the transition,
- so you can animate them as you would normally changes to these properties:
+ In the following example we change the top and bottom anchors of an item:
+ \qml
+ AnchorChanges {
+ target: content; top: window.top; bottom: window.bottom
+ }
+ \endqml
+
+ AnchorChanges can be animated using AnchorAnimation.
\qml
//animate our anchor changes
- NumberAnimation { targets: content; properties: "x,y,width,height" }
+ AnchorAnimation {}
\endqml
For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
@@ -578,10 +595,10 @@ class QDeclarativeAnchorChangesPrivate : public QObjectPrivate
public:
QDeclarativeAnchorChangesPrivate() : target(0) {}
- QString name;
QDeclarativeItem *target;
QString resetString;
QStringList resetList;
+
QDeclarativeAnchorLine left;
QDeclarativeAnchorLine right;
QDeclarativeAnchorLine horizontalCenter;
@@ -610,6 +627,24 @@ public:
qreal fromY;
qreal fromWidth;
qreal fromHeight;
+
+ qreal toX;
+ qreal toY;
+ qreal toWidth;
+ qreal toHeight;
+
+ qreal rewindX;
+ qreal rewindY;
+ qreal rewindWidth;
+ qreal rewindHeight;
+
+ bool applyOrigLeft;
+ bool applyOrigRight;
+ bool applyOrigHCenter;
+ bool applyOrigTop;
+ bool applyOrigBottom;
+ bool applyOrigVCenter;
+ bool applyOrigBaseline;
};
/*!
@@ -762,6 +797,38 @@ void QDeclarativeAnchorChanges::execute()
if (!d->target)
return;
+ //incorporate any needed "reverts"
+ if (d->applyOrigLeft)
+ d->target->anchors()->setLeft(d->origLeft);
+ if (d->applyOrigRight)
+ d->target->anchors()->setRight(d->origRight);
+ if (d->applyOrigHCenter)
+ d->target->anchors()->setHorizontalCenter(d->origHCenter);
+ if (d->applyOrigTop)
+ d->target->anchors()->setTop(d->origTop);
+ if (d->applyOrigBottom)
+ d->target->anchors()->setBottom(d->origBottom);
+ if (d->applyOrigVCenter)
+ d->target->anchors()->setVerticalCenter(d->origVCenter);
+ if (d->applyOrigBaseline)
+ d->target->anchors()->setBaseline(d->origBaseline);
+
+ //reset any anchors that have been specified
+ if (d->resetList.contains(QLatin1String("left")))
+ d->target->anchors()->resetLeft();
+ if (d->resetList.contains(QLatin1String("right")))
+ d->target->anchors()->resetRight();
+ if (d->resetList.contains(QLatin1String("horizontalCenter")))
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->resetList.contains(QLatin1String("top")))
+ d->target->anchors()->resetTop();
+ if (d->resetList.contains(QLatin1String("bottom")))
+ d->target->anchors()->resetBottom();
+ if (d->resetList.contains(QLatin1String("verticalCenter")))
+ d->target->anchors()->resetVerticalCenter();
+ if (d->resetList.contains(QLatin1String("baseline")))
+ d->target->anchors()->resetBaseline();
+
//set any anchors that have been specified
if (d->left.anchorLine != QDeclarativeAnchorLine::Invalid)
d->target->anchors()->setLeft(d->left);
@@ -790,6 +857,22 @@ void QDeclarativeAnchorChanges::reverse()
if (!d->target)
return;
+ //reset any anchors set by the state
+ if (d->left.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetLeft();
+ if (d->right.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetRight();
+ if (d->horizontalCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->top.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetTop();
+ if (d->bottom.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetBottom();
+ if (d->verticalCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetVerticalCenter();
+ if (d->baseline.anchorLine != QDeclarativeAnchorLine::Invalid)
+ d->target->anchors()->resetBaseline();
+
//restore previous anchors
if (d->origLeft.anchorLine != QDeclarativeAnchorLine::Invalid)
d->target->anchors()->setLeft(d->origLeft);
@@ -812,31 +895,33 @@ QString QDeclarativeAnchorChanges::typeName() const
return QLatin1String("AnchorChanges");
}
-QList<QDeclarativeAction> QDeclarativeAnchorChanges::extraActions()
+QList<QDeclarativeAction> QDeclarativeAnchorChanges::additionalActions()
{
Q_D(QDeclarativeAnchorChanges);
QList<QDeclarativeAction> extra;
- //### try to be smarter about which ones we add.
- // or short-circuit later on if they haven't actually changed.
- // we shouldn't set explicit width if there wasn't one before.
if (d->target) {
QDeclarativeAction a;
- a.fromValue = d->fromX;
- a.property = QDeclarativeProperty(d->target, QLatin1String("x"));
- extra << a;
-
- a.fromValue = d->fromY;
- a.property = QDeclarativeProperty(d->target, QLatin1String("y"));
- extra << a;
-
- a.fromValue = d->fromWidth;
- a.property = QDeclarativeProperty(d->target, QLatin1String("width"));
- extra << a;
-
- a.fromValue = d->fromHeight;
- a.property = QDeclarativeProperty(d->target, QLatin1String("height"));
- extra << a;
+ if (d->fromX != d->toX) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("x"));
+ a.toValue = d->toX;
+ extra << a;
+ }
+ if (d->fromY != d->toY) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("y"));
+ a.toValue = d->toY;
+ extra << a;
+ }
+ if (d->fromWidth != d->toWidth) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("width"));
+ a.toValue = d->toWidth;
+ extra << a;
+ }
+ if (d->fromHeight != d->toHeight) {
+ a.property = QDeclarativeProperty(d->target, QLatin1String("height"));
+ a.toValue = d->toHeight;
+ extra << a;
+ }
}
return extra;
@@ -858,10 +943,52 @@ void QDeclarativeAnchorChanges::saveOriginals()
d->origVCenter = d->target->anchors()->verticalCenter();
d->origBaseline = d->target->anchors()->baseline();
+ d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
+ = d->applyOrigBottom = d->applyOrigHCenter = d->applyOrigBaseline = false;
+
saveCurrentValues();
}
-void QDeclarativeAnchorChanges::clearForwardBindings()
+void QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
+{
+ Q_D(QDeclarativeAnchorChanges);
+ QDeclarativeAnchorChanges *ac = static_cast<QDeclarativeAnchorChanges*>(other);
+ QDeclarativeAnchorChangesPrivate *acp = ac->d_func();
+
+ //probably also need to revert some things
+ d->applyOrigLeft = (acp->left.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("left")));
+
+ d->applyOrigRight = (acp->right.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("right")));
+
+ d->applyOrigHCenter = (acp->horizontalCenter.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("horizontalCenter")));
+
+ d->applyOrigTop = (acp->top.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("top")));
+
+ d->applyOrigBottom = (acp->bottom.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("bottom")));
+
+ d->applyOrigVCenter = (acp->verticalCenter.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("verticalCenter")));
+
+ d->applyOrigBaseline = (acp->baseline.anchorLine != QDeclarativeAnchorLine::Invalid ||
+ acp->resetList.contains(QLatin1String("baseline")));
+
+ d->origLeft = ac->d_func()->origLeft;
+ d->origRight = ac->d_func()->origRight;
+ d->origHCenter = ac->d_func()->origHCenter;
+ d->origTop = ac->d_func()->origTop;
+ d->origBottom = ac->d_func()->origBottom;
+ d->origVCenter = ac->d_func()->origVCenter;
+ d->origBaseline = ac->d_func()->origBaseline;
+
+ saveCurrentValues();
+}
+
+void QDeclarativeAnchorChanges::clearBindings()
{
Q_D(QDeclarativeAnchorChanges);
d->fromX = d->target->x();
@@ -869,6 +996,22 @@ void QDeclarativeAnchorChanges::clearForwardBindings()
d->fromWidth = d->target->width();
d->fromHeight = d->target->height();
+ //reset any anchors with corresponding reverts
+ if (d->applyOrigLeft)
+ d->target->anchors()->resetLeft();
+ if (d->applyOrigRight)
+ d->target->anchors()->resetRight();
+ if (d->applyOrigHCenter)
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->applyOrigTop)
+ d->target->anchors()->resetTop();
+ if (d->applyOrigBottom)
+ d->target->anchors()->resetBottom();
+ if (d->applyOrigVCenter)
+ d->target->anchors()->resetVerticalCenter();
+ if (d->applyOrigBaseline)
+ d->target->anchors()->resetBaseline();
+
//reset any anchors that have been specified
if (d->resetList.contains(QLatin1String("left")))
d->target->anchors()->resetLeft();
@@ -902,47 +1045,6 @@ void QDeclarativeAnchorChanges::clearForwardBindings()
d->target->anchors()->resetBaseline();
}
-void QDeclarativeAnchorChanges::clearReverseBindings()
-{
- Q_D(QDeclarativeAnchorChanges);
- d->fromX = d->target->x();
- d->fromY = d->target->y();
- d->fromWidth = d->target->width();
- d->fromHeight = d->target->height();
-
- //reset any anchors that were set in the state
- if (d->left.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetLeft();
- if (d->right.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetRight();
- if (d->horizontalCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetHorizontalCenter();
- if (d->top.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetTop();
- if (d->bottom.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetBottom();
- if (d->verticalCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetVerticalCenter();
- if (d->baseline.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetBaseline();
-
- //reset any anchors that were set in the original state
- if (d->origLeft.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetLeft();
- if (d->origRight.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetRight();
- if (d->origHCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetHorizontalCenter();
- if (d->origTop.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetTop();
- if (d->origBottom.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetBottom();
- if (d->origVCenter.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetVerticalCenter();
- if (d->origBaseline.anchorLine != QDeclarativeAnchorLine::Invalid)
- d->target->anchors()->resetBaseline();
-}
-
bool QDeclarativeAnchorChanges::override(QDeclarativeActionEvent*other)
{
if (other->typeName() != QLatin1String("AnchorChanges"))
@@ -975,6 +1077,11 @@ void QDeclarativeAnchorChanges::rewind()
d->target->anchors()->setVerticalCenter(d->rewindVCenter);
if (d->rewindBaseline.anchorLine != QDeclarativeAnchorLine::Invalid)
d->target->anchors()->setBaseline(d->rewindBaseline);
+
+ d->target->setX(d->rewindX);
+ d->target->setY(d->rewindY);
+ d->target->setWidth(d->rewindWidth);
+ d->target->setHeight(d->rewindHeight);
}
void QDeclarativeAnchorChanges::saveCurrentValues()
@@ -987,6 +1094,20 @@ void QDeclarativeAnchorChanges::saveCurrentValues()
d->rewindBottom = d->target->anchors()->bottom();
d->rewindVCenter = d->target->anchors()->verticalCenter();
d->rewindBaseline = d->target->anchors()->baseline();
+
+ d->rewindX = d->target->x();
+ d->rewindY = d->target->y();
+ d->rewindWidth = d->target->width();
+ d->rewindHeight = d->target->height();
+}
+
+void QDeclarativeAnchorChanges::saveTargetValues()
+{
+ Q_D(QDeclarativeAnchorChanges);
+ d->toX = d->target->x();
+ d->toY = d->target->y();
+ d->toWidth = d->target->width();
+ d->toHeight = d->target->height();
}
#include <qdeclarativestateoperations.moc>
diff --git a/src/declarative/util/qdeclarativestateoperations_p.h b/src/declarative/util/qdeclarativestateoperations_p.h
index dd4248023..66a8717 100644
--- a/src/declarative/util/qdeclarativestateoperations_p.h
+++ b/src/declarative/util/qdeclarativestateoperations_p.h
@@ -107,6 +107,7 @@ public:
virtual ActionList actions();
virtual void saveOriginals();
+ virtual void copyOriginals(QDeclarativeActionEvent*);
virtual void execute();
virtual bool isReversable();
virtual void reverse();
@@ -196,13 +197,15 @@ public:
virtual void reverse();
virtual QString typeName() const;
virtual bool override(QDeclarativeActionEvent*other);
- virtual QList<QDeclarativeAction> extraActions();
virtual bool changesBindings();
virtual void saveOriginals();
- virtual void clearForwardBindings();
- virtual void clearReverseBindings();
+ virtual void copyOriginals(QDeclarativeActionEvent*);
+ virtual void clearBindings();
virtual void rewind();
virtual void saveCurrentValues();
+
+ QList<QDeclarativeAction> additionalActions();
+ virtual void saveTargetValues();
};
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativetransitionmanager.cpp b/src/declarative/util/qdeclarativetransitionmanager.cpp
index e1143fa..f07fb23 100644
--- a/src/declarative/util/qdeclarativetransitionmanager.cpp
+++ b/src/declarative/util/qdeclarativetransitionmanager.cpp
@@ -126,10 +126,7 @@ void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &
QDeclarativePropertyPrivate::setBinding(action.property, 0); // Disable current binding
if (action.event && action.event->changesBindings()) { //### assume isReversable()?
d->bindingsList << action;
- if (action.reverseEvent)
- action.event->clearReverseBindings();
- else
- action.event->clearForwardBindings();
+ action.event->clearBindings();
}
}
@@ -144,8 +141,6 @@ void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &
if (!d->bindingsList.isEmpty()) {
- //### do extra actions here?
-
// Apply all the property and binding changes
for (int ii = 0; ii < applyList.size(); ++ii) {
const QDeclarativeAction &action = applyList.at(ii);
@@ -158,17 +153,18 @@ void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &
action.event->reverse();
else
action.event->execute();
- applyList << action.event->extraActions();
}
}
// Read all the end values for binding changes
for (int ii = 0; ii < applyList.size(); ++ii) {
QDeclarativeAction *action = &applyList[ii];
- if (action->event)
+ if (action->event) {
+ action->event->saveTargetValues();
continue;
+ }
const QDeclarativeProperty &prop = action->property;
- if (action->toBinding || !action->toValue.isValid()) { //### is this always right (used for exta actions)
+ if (action->toBinding || !action->toValue.isValid()) {
action->toValue = prop.read();
}
}
@@ -177,15 +173,9 @@ void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &
foreach(const QDeclarativeAction &action, applyList) {
if (action.event) {
if (action.event->isReversable()) {
- if (action.reverseEvent) { //reverse the reverse
- action.event->clearForwardBindings();
- action.event->rewind();
- action.event->clearReverseBindings();
- } else {
- action.event->clearReverseBindings();
- action.event->rewind();
- action.event->clearForwardBindings();
- }
+ action.event->clearBindings();
+ action.event->rewind();
+ action.event->clearBindings();
}
continue;
}
diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp
index 65bfdc1..4d4678a 100644
--- a/src/declarative/util/qdeclarativeutilmodule.cpp
+++ b/src/declarative/util/qdeclarativeutilmodule.cpp
@@ -75,44 +75,48 @@
void QDeclarativeUtilModule::defineModule()
{
- QML_REGISTER_TYPE(Qt,4,6,AnchorChanges,QDeclarativeAnchorChanges);
- QML_REGISTER_TYPE(Qt,4,6,Behavior,QDeclarativeBehavior);
- QML_REGISTER_TYPE(Qt,4,6,Binding,QDeclarativeBind);
- QML_REGISTER_TYPE(Qt,4,6,ColorAnimation,QDeclarativeColorAnimation);
- QML_REGISTER_TYPE(Qt,4,6,Connections,QDeclarativeConnections);
- QML_REGISTER_TYPE(Qt,4,6,EaseFollow,QDeclarativeEaseFollow);;
- QML_REGISTER_TYPE(Qt,4,6,FontLoader,QDeclarativeFontLoader);
- QML_REGISTER_TYPE(Qt,4,6,ListElement,QDeclarativeListElement);
- QML_REGISTER_TYPE(Qt,4,6,NumberAnimation,QDeclarativeNumberAnimation);
- QML_REGISTER_TYPE(Qt,4,6,Package,QDeclarativePackage);
- QML_REGISTER_TYPE(Qt,4,6,ParallelAnimation,QDeclarativeParallelAnimation);
- QML_REGISTER_TYPE(Qt,4,6,ParentAction,QDeclarativeParentAction);
- QML_REGISTER_TYPE(Qt,4,6,ParentAnimation,QDeclarativeParentAnimation);
- QML_REGISTER_TYPE(Qt,4,6,ParentChange,QDeclarativeParentChange);
- QML_REGISTER_TYPE(Qt,4,6,PauseAnimation,QDeclarativePauseAnimation);
- QML_REGISTER_TYPE(Qt,4,6,PropertyAction,QDeclarativePropertyAction);
- QML_REGISTER_TYPE(Qt,4,6,PropertyAnimation,QDeclarativePropertyAnimation);
- QML_REGISTER_TYPE(Qt,4,6,RotationAnimation,QDeclarativeRotationAnimation);
- QML_REGISTER_TYPE(Qt,4,6,ScriptAction,QDeclarativeScriptAction);
- QML_REGISTER_TYPE(Qt,4,6,SequentialAnimation,QDeclarativeSequentialAnimation);
- QML_REGISTER_TYPE(Qt,4,6,SpringFollow,QDeclarativeSpringFollow);
- QML_REGISTER_TYPE(Qt,4,6,StateChangeScript,QDeclarativeStateChangeScript);
- QML_REGISTER_TYPE(Qt,4,6,StateGroup,QDeclarativeStateGroup);
- QML_REGISTER_TYPE(Qt,4,6,State,QDeclarativeState);
- QML_REGISTER_TYPE(Qt,4,6,SystemPalette,QDeclarativeSystemPalette);
- QML_REGISTER_TYPE(Qt,4,6,Timer,QDeclarativeTimer);
- QML_REGISTER_TYPE(Qt,4,6,Transition,QDeclarativeTransition);
- QML_REGISTER_TYPE(Qt,4,6,Vector3dAnimation,QDeclarativeVector3dAnimation);
+ qmlRegisterType<QDeclarativeAnchorAnimation>("Qt",4,6,"AnchorAnimation");
+ qmlRegisterType<QDeclarativeAnchorChanges>("Qt",4,6,"AnchorChanges");
+ qmlRegisterType<QDeclarativeBehavior>("Qt",4,6,"Behavior");
+ qmlRegisterType<QDeclarativeBind>("Qt",4,6,"Binding");
+ qmlRegisterType<QDeclarativeColorAnimation>("Qt",4,6,"ColorAnimation");
+ qmlRegisterType<QDeclarativeConnections>("Qt",4,6,"Connections");
+ qmlRegisterType<QDeclarativeEaseFollow>("Qt",4,6,"EaseFollow");
+ qmlRegisterType<QDeclarativeFontLoader>("Qt",4,6,"FontLoader");
+ qmlRegisterType<QDeclarativeListElement>("Qt",4,6,"ListElement");
+ qmlRegisterType<QDeclarativeNumberAnimation>("Qt",4,6,"NumberAnimation");
+ qmlRegisterType<QDeclarativePackage>("Qt",4,6,"Package");
+ qmlRegisterType<QDeclarativeParallelAnimation>("Qt",4,6,"ParallelAnimation");
+ qmlRegisterType<QDeclarativeParentAction>("Qt",4,6,"ParentAction");
+ qmlRegisterType<QDeclarativeParentAnimation>("Qt",4,6,"ParentAnimation");
+ qmlRegisterType<QDeclarativeParentChange>("Qt",4,6,"ParentChange");
+ qmlRegisterType<QDeclarativePauseAnimation>("Qt",4,6,"PauseAnimation");
+ qmlRegisterType<QDeclarativePropertyAction>("Qt",4,6,"PropertyAction");
+ qmlRegisterType<QDeclarativePropertyAnimation>("Qt",4,6,"PropertyAnimation");
+ qmlRegisterType<QDeclarativeRotationAnimation>("Qt",4,6,"RotationAnimation");
+ qmlRegisterType<QDeclarativeScriptAction>("Qt",4,6,"ScriptAction");
+ qmlRegisterType<QDeclarativeSequentialAnimation>("Qt",4,6,"SequentialAnimation");
+ qmlRegisterType<QDeclarativeSpringFollow>("Qt",4,6,"SpringFollow");
+ qmlRegisterType<QDeclarativeStateChangeScript>("Qt",4,6,"StateChangeScript");
+ qmlRegisterType<QDeclarativeStateGroup>("Qt",4,6,"StateGroup");
+ qmlRegisterType<QDeclarativeState>("Qt",4,6,"State");
+ qmlRegisterType<QDeclarativeSystemPalette>("Qt",4,6,"SystemPalette");
+ qmlRegisterType<QDeclarativeTimer>("Qt",4,6,"Timer");
+ qmlRegisterType<QDeclarativeTransition>("Qt",4,6,"Transition");
+ qmlRegisterType<QDeclarativeVector3dAnimation>("Qt",4,6,"Vector3dAnimation");
#ifndef QT_NO_XMLPATTERNS
- QML_REGISTER_TYPE(Qt,4,6,XmlListModel,QDeclarativeXmlListModel);
- QML_REGISTER_TYPE(Qt,4,6,XmlRole,QDeclarativeXmlListModelRole);
+ qmlRegisterType<QDeclarativeXmlListModel>("Qt",4,6,"XmlListModel");
+ qmlRegisterType<QDeclarativeXmlListModelRole>("Qt",4,6,"XmlRole");
#endif
- QML_REGISTER_NOCREATE_TYPE(QDeclarativeAnchors);
- QML_REGISTER_NOCREATE_TYPE(QDeclarativeAbstractAnimation);
- QML_REGISTER_NOCREATE_TYPE(QDeclarativeStateOperation);
+ qmlRegisterType<QDeclarativeAnchors>();
+ qmlRegisterType<QDeclarativeAbstractAnimation>();
+ qmlRegisterType<QDeclarativeStateOperation>();
- QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, ListModel, QDeclarativeListModel, QDeclarativeListModelParser);
- QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, PropertyChanges, QDeclarativePropertyChanges, QDeclarativePropertyChangesParser);
- QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, Connections, QDeclarativeConnections, QDeclarativeConnectionsParser);
+ qmlRegisterCustomType<QDeclarativeListModel>("Qt", 4,6, "ListModel", "QDeclarativeListModel",
+ new QDeclarativeListModelParser);
+ qmlRegisterCustomType<QDeclarativePropertyChanges>("Qt", 4, 6, "PropertyChanges", "QDeclarativePropertyChanges",
+ new QDeclarativePropertyChangesParser);
+ qmlRegisterCustomType<QDeclarativeConnections>("Qt", 4, 6, "Connections", "QDeclarativeConnections",
+ new QDeclarativeConnectionsParser);
}
diff --git a/src/declarative/util/qdeclarativeview.cpp b/src/declarative/util/qdeclarativeview.cpp
index 735a009..59a062a 100644
--- a/src/declarative/util/qdeclarativeview.cpp
+++ b/src/declarative/util/qdeclarativeview.cpp
@@ -298,6 +298,7 @@ QDeclarativeView::~QDeclarativeView()
void QDeclarativeView::setSource(const QUrl& url)
{
d->source = url;
+ d->engine.setBaseUrl(url);
d->execute();
}
@@ -458,8 +459,8 @@ void QDeclarativeView::setRootObject(QObject *obj)
QPerformanceLog::clear();
d->root = item;
d->qmlRoot = item;
- connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged()));
- connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged()));
+ connect(item, SIGNAL(widthChanged(qreal)), this, SLOT(sizeChanged()));
+ connect(item, SIGNAL(heightChanged(qreal)), this, SLOT(sizeChanged()));
if (d->initialSize.height() <= 0 && d->qmlRoot->width() > 0)
d->initialSize.setWidth(d->qmlRoot->width());
if (d->initialSize.height() <= 0 && d->qmlRoot->height() > 0)
diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp
index 49dbb27..01ae2ed 100644
--- a/src/declarative/util/qdeclarativexmllistmodel.cpp
+++ b/src/declarative/util/qdeclarativexmllistmodel.cpp
@@ -61,6 +61,9 @@
QT_BEGIN_NAMESPACE
+
+
+
typedef QPair<int, int> QDeclarativeXmlListRange;
/*!
@@ -111,6 +114,9 @@ class QDeclarativeXmlQuery : public QThread
{
Q_OBJECT
public:
+ QDeclarativeXmlQuery(QObject *parent=0)
+ : QThread(parent), m_quit(false), m_restart(false), m_abort(false), m_queryId(0) {
+ }
~QDeclarativeXmlQuery() {
m_mutex.lock();
m_quit = true;
@@ -120,11 +126,6 @@ public:
wait();
}
- static QDeclarativeXmlQuery *instance() {
- static QDeclarativeXmlQuery *query = new QDeclarativeXmlQuery;
- return query;
- }
-
void abort() {
QMutexLocker locker(&m_mutex);
m_abort = true;
@@ -163,11 +164,6 @@ public:
return m_removedItemRanges;
}
-private:
- QDeclarativeXmlQuery(QObject *parent=0)
- : QThread(parent), m_quit(false), m_restart(false), m_abort(false), m_queryId(0) {
- }
-
Q_SIGNALS:
void queryCompleted(int queryId, int size);
@@ -217,8 +213,6 @@ private:
QList<QDeclarativeXmlListRange> m_removedItemRanges;
};
-//Q_GLOBAL_STATIC(QDeclarativeXmlQuery, QDeclarativeXmlQuery::instance());
-
void QDeclarativeXmlQuery::doQueryJob()
{
QString r;
@@ -396,7 +390,7 @@ public:
QDeclarativeXmlListModelPrivate()
: isComponentComplete(true), size(-1), highestRole(Qt::UserRole)
, reply(0), status(QDeclarativeXmlListModel::Null), progress(0.0)
- , queryId(-1), roleObjects() {}
+ , queryId(-1), roleObjects(), redirectCount(0) {}
bool isComponentComplete;
QUrl src;
@@ -410,6 +404,7 @@ public:
QNetworkReply *reply;
QDeclarativeXmlListModel::Status status;
qreal progress;
+ QDeclarativeXmlQuery qmlXmlQuery;
int queryId;
QList<QDeclarativeXmlListModelRole *> roleObjects;
static void append_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list, QDeclarativeXmlListModelRole *role);
@@ -417,6 +412,7 @@ public:
static void removeAt_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list, int i);
static void insert_role(QDeclarativeListProperty<QDeclarativeXmlListModelRole> *list, int i, QDeclarativeXmlListModelRole *role);
QList<QList<QVariant> > data;
+ int redirectCount;
};
@@ -493,7 +489,8 @@ void QDeclarativeXmlListModelPrivate::clear_role(QDeclarativeListProperty<QDecla
QDeclarativeXmlListModel::QDeclarativeXmlListModel(QObject *parent)
: QListModelInterface(*(new QDeclarativeXmlListModelPrivate), parent)
{
- connect(QDeclarativeXmlQuery::instance(), SIGNAL(queryCompleted(int,int)),
+ Q_D(QDeclarativeXmlListModel);
+ connect(&d->qmlXmlQuery, SIGNAL(queryCompleted(int,int)),
this, SLOT(queryCompleted(int,int)));
}
@@ -575,8 +572,8 @@ void QDeclarativeXmlListModel::setSource(const QUrl &src)
{
Q_D(QDeclarativeXmlListModel);
if (d->src != src) {
- reload();
d->src = src;
+ reload();
emit sourceChanged();
}
}
@@ -726,7 +723,7 @@ void QDeclarativeXmlListModel::reload()
if (!d->isComponentComplete)
return;
- QDeclarativeXmlQuery::instance()->abort();
+ d->qmlXmlQuery.abort();
d->queryId = -1;
int count = d->size;
@@ -758,7 +755,7 @@ void QDeclarativeXmlListModel::reload()
}
if (!d->xml.isEmpty()) {
- d->queryId = QDeclarativeXmlQuery::instance()->doQuery(d->query, d->namespaces, d->xml.toUtf8(), &d->roleObjects);
+ d->queryId = d->qmlXmlQuery.doQuery(d->query, d->namespaces, d->xml.toUtf8(), &d->roleObjects);
d->progress = 1.0;
d->status = Ready;
emit progressChanged(d->progress);
@@ -778,9 +775,25 @@ void QDeclarativeXmlListModel::reload()
this, SLOT(requestProgress(qint64,qint64)));
}
+#define XMLLISTMODEL_MAX_REDIRECT 16
+
void QDeclarativeXmlListModel::requestFinished()
{
Q_D(QDeclarativeXmlListModel);
+
+ d->redirectCount++;
+ if (d->redirectCount < XMLLISTMODEL_MAX_REDIRECT) {
+ 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() != QNetworkReply::NoError) {
disconnect(d->reply, 0, this, 0);
d->reply->deleteLater();
@@ -789,7 +802,7 @@ void QDeclarativeXmlListModel::requestFinished()
} else {
d->status = Ready;
QByteArray data = d->reply->readAll();
- d->queryId = QDeclarativeXmlQuery::instance()->doQuery(d->query, d->namespaces, data, &d->roleObjects);
+ d->queryId = d->qmlXmlQuery.doQuery(d->query, d->namespaces, data, &d->roleObjects);
disconnect(d->reply, 0, this, 0);
d->reply->deleteLater();
d->reply = 0;
@@ -815,10 +828,10 @@ void QDeclarativeXmlListModel::queryCompleted(int id, int size)
return;
bool sizeChanged = size != d->size;
d->size = size;
- d->data = QDeclarativeXmlQuery::instance()->modelData();
+ d->data = d->qmlXmlQuery.modelData();
- QList<QDeclarativeXmlListRange> removed = QDeclarativeXmlQuery::instance()->removedItemRanges();
- QList<QDeclarativeXmlListRange> inserted = QDeclarativeXmlQuery::instance()->insertedItemRanges();
+ QList<QDeclarativeXmlListRange> removed = d->qmlXmlQuery.removedItemRanges();
+ QList<QDeclarativeXmlListRange> inserted = d->qmlXmlQuery.insertedItemRanges();
for (int i=0; i<removed.count(); i++)
emit itemsRemoved(removed[i].first, removed[i].second);
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
index 26edecc..ddf00ea 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\
@@ -49,6 +50,7 @@ HEADERS += \
$$PWD/qdeclarativestategroup_p.h \
$$PWD/qdeclarativetransition_p.h \
$$PWD/qdeclarativelistmodel_p.h\
+ $$PWD/qdeclarativelistmodel_p_p.h\
$$PWD/qdeclarativelistaccessor_p.h \
$$PWD/qdeclarativeopenmetaobject_p.h \
$$PWD/qdeclarativenullablevalue_p_p.h \
@@ -59,7 +61,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