summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/declarative/extending.qdoc12
-rw-r--r--src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp3
-rw-r--r--src/declarative/qml/qml.pri2
-rw-r--r--src/declarative/qml/qmlbinding.cpp12
-rw-r--r--src/declarative/qml/qmlbinding.h132
-rw-r--r--src/declarative/qml/qmlbinding_p.h76
-rw-r--r--src/declarative/qml/qmlbinding_p_p.h91
-rw-r--r--src/declarative/qml/qmlboundsignal.cpp3
-rw-r--r--src/declarative/qml/qmlcompiledbindings_p.h2
-rw-r--r--src/declarative/qml/qmlcompiler.cpp2
-rw-r--r--src/declarative/qml/qmlcomponent.cpp2
-rw-r--r--src/declarative/qml/qmlengine.cpp2
-rw-r--r--src/declarative/qml/qmlenginedebug.cpp7
-rw-r--r--src/declarative/qml/qmlexpression.cpp62
-rw-r--r--src/declarative/qml/qmlexpression.h11
-rw-r--r--src/declarative/qml/qmlexpression_p.h2
-rw-r--r--src/declarative/qml/qmlmetaproperty.cpp2
-rw-r--r--src/declarative/qml/qmlobjectscriptclass.cpp2
-rw-r--r--src/declarative/qml/qmlpropertycache.cpp4
-rw-r--r--src/declarative/qml/qmlvme.cpp4
-rw-r--r--src/declarative/qml/qmlwatcher.cpp1
-rw-r--r--src/declarative/util/qmlanimation.cpp1
-rw-r--r--src/declarative/util/qmlpropertychanges.cpp4
-rw-r--r--src/declarative/util/qmlstate.cpp2
-rw-r--r--src/declarative/util/qmlstategroup.cpp2
-rw-r--r--src/declarative/util/qmlstateoperations.cpp1
-rw-r--r--src/declarative/util/qmltransitionmanager.cpp2
-rw-r--r--src/declarative/util/qmlxmllistmodel.cpp179
-rw-r--r--tests/auto/declarative/qmldebug/tst_qmldebug.cpp2
-rw-r--r--tests/auto/declarative/qmlecmascript/testtypes.h10
-rw-r--r--tests/auto/declarative/qmlgraphicslistview/tst_qmlgraphicslistview.cpp1
-rw-r--r--tests/auto/declarative/qmlgraphicspathview/tst_qmlgraphicspathview.cpp1
-rw-r--r--tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp2
-rw-r--r--tests/auto/declarative/qmlxmllistmodel/tst_qmlxmllistmodel.cpp254
34 files changed, 616 insertions, 279 deletions
diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc
index d3e6c14..396ddab 100644
--- a/doc/src/declarative/extending.qdoc
+++ b/doc/src/declarative/extending.qdoc
@@ -557,18 +557,6 @@ to be used in bindings should have a NOTIFY signal instead.
\l {Extending QML - Binding Example} shows the BirthdayParty example updated to
include NOTIFY signals for use in binding.
-\section1 Binding and Script Properties
-
-While generally no changes are needed to a C++ class to use property
-binding, sometimes more advanced interaction between the binding engine and
-an object is desirable. To facilitate this, there is a special exception
-in the bind engine for allowing an object to access the binding directly.
-
-If a binding is assigned to a property with a type of QmlBinding
-pointer (ie. \c {QmlBinding *}), each time the binding value changes,
-a QmlBinding instance is assigned to that property. The QmlBinding instance
-allows the object to read the binding and to evaluate the binding's current value.
-
\section1 Extension Objects
\snippet examples/declarative/extending/extended/example.qml 0
diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
index a9d67ab..bf3df03 100644
--- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
+++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp
@@ -187,7 +187,6 @@ QVariant QmlGraphicsVisualItemModel::evaluate(int index, const QString &expressi
QmlContext *ctxt = new QmlContext(ccontext);
ctxt->addDefaultObject(d->children.at(index));
QmlExpression e(ctxt, expression, objectContext);
- e.setTrackChange(false);
QVariant value = e.value();
delete ctxt;
return value;
@@ -1056,7 +1055,6 @@ QVariant QmlGraphicsVisualDataModel::evaluate(int index, const QString &expressi
QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(nobj);
if (item) {
QmlExpression e(qmlContext(item), expression, objectContext);
- e.setTrackChange(false);
value = e.value();
}
} else {
@@ -1066,7 +1064,6 @@ QVariant QmlGraphicsVisualDataModel::evaluate(int index, const QString &expressi
QmlGraphicsVisualDataModelData *data = new QmlGraphicsVisualDataModelData(index, this);
ctxt->addDefaultObject(data);
QmlExpression e(ctxt, expression, objectContext);
- e.setTrackChange(false);
value = e.value();
delete data;
delete ctxt;
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index 2313c37..f09a944 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -60,8 +60,8 @@ HEADERS += \
$$PWD/qmlinstruction_p.h \
$$PWD/qmlvmemetaobject_p.h \
$$PWD/qml.h \
- $$PWD/qmlbinding.h \
$$PWD/qmlbinding_p.h \
+ $$PWD/qmlbinding_p_p.h \
$$PWD/qmlmetaproperty.h \
$$PWD/qmlmoduleplugin.h \
$$PWD/qmlcomponent.h \
diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp
index feadd0f..aeda28b 100644
--- a/src/declarative/qml/qmlbinding.cpp
+++ b/src/declarative/qml/qmlbinding.cpp
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#include "qmlbinding.h"
#include "qmlbinding_p.h"
+#include "qmlbinding_p_p.h"
#include "qml.h"
#include "qmlcontext.h"
@@ -85,12 +85,14 @@ QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ct
: QmlExpression(ctxt, data, rc, obj, url, lineNumber, *new QmlBindingPrivate)
{
setParent(parent);
+ setNotifyOnValueChanged(true);
}
QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObject *parent)
: QmlExpression(ctxt, str, obj, *new QmlBindingPrivate)
{
setParent(parent);
+ setNotifyOnValueChanged(true);
}
QmlBinding::~QmlBinding()
@@ -198,17 +200,17 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags)
data->release();
}
-void QmlBinding::emitValueChanged()
+void QmlBindingPrivate::emitValueChanged()
{
- update();
- // don't bother calling valueChanged()
+ Q_Q(QmlBinding);
+ q->update();
}
void QmlBinding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags)
{
Q_D(QmlBinding);
d->bindingData()->enabled = e;
- setTrackChange(e);
+ setNotifyOnValueChanged(e);
QmlAbstractBinding::setEnabled(e, flags);
diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h
deleted file mode 100644
index 151b71c..0000000
--- a/src/declarative/qml/qmlbinding.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/****************************************************************************
-**
-** 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 QMLBINDING_H
-#define QMLBINDING_H
-
-#include "qml.h"
-#include "qmlpropertyvaluesource.h"
-#include "qmlexpression.h"
-
-#include <QtCore/QObject>
-#include <QtCore/QMetaProperty>
-
-QT_BEGIN_HEADER
-
-QT_BEGIN_NAMESPACE
-
-QT_MODULE(Declarative)
-
-class Q_DECLARATIVE_EXPORT QmlAbstractBinding
-{
-public:
- QmlAbstractBinding();
- virtual ~QmlAbstractBinding();
-
- virtual void destroy();
-
- virtual QString expression() const;
-
- void setEnabled(bool e) { setEnabled(e, QmlMetaProperty::DontRemoveBinding); }
- virtual void setEnabled(bool, QmlMetaProperty::WriteFlags) = 0;
- virtual int propertyIndex() = 0;
-
- void update() { update(QmlMetaProperty::DontRemoveBinding); }
- virtual void update(QmlMetaProperty::WriteFlags) = 0;
-
- void addToObject(QObject *);
- void removeFromObject();
-
-protected:
- void clear();
-
-private:
- friend class QmlDeclarativeData;
- friend class QmlMetaProperty;
- friend class QmlMetaPropertyPrivate;
- friend class QmlVME;
-
- QObject *m_object;
- QmlAbstractBinding **m_mePtr;
- QmlAbstractBinding **m_prevBinding;
- QmlAbstractBinding *m_nextBinding;
-};
-
-class QmlContext;
-class QmlBindingPrivate;
-class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression,
- public QmlAbstractBinding
-{
-Q_OBJECT
-public:
- QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0);
- QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, const QString &, int,
- QObject *parent);
- ~QmlBinding();
-
- void setTarget(const QmlMetaProperty &);
- QmlMetaProperty property() const;
-
- bool enabled() const;
-
- // Inherited from QmlAbstractBinding
- virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags);
- virtual int propertyIndex();
- virtual void update(QmlMetaProperty::WriteFlags flags);
- virtual QString expression() const;
-
-public Q_SLOTS:
- void update() { update(QmlMetaProperty::DontRemoveBinding); }
-
-protected:
- void emitValueChanged();
-
-private:
- Q_DECLARE_PRIVATE(QmlBinding)
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QmlBinding);
-
-QT_END_HEADER
-
-#endif // QMLBINDING_H
diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h
index b4f88b5..4594476 100644
--- a/src/declarative/qml/qmlbinding_p.h
+++ b/src/declarative/qml/qmlbinding_p.h
@@ -53,36 +53,82 @@
// We mean it.
//
-#include "qmlbinding.h"
+#include "qml.h"
+#include "qmlpropertyvaluesource.h"
+#include "qmlexpression.h"
-#include "qmlmetaproperty.h"
-#include "qmlexpression_p.h"
+#include <QtCore/QObject>
+#include <QtCore/QMetaProperty>
QT_BEGIN_NAMESPACE
-class QmlBindingData : public QmlExpressionData
+class Q_AUTOTEST_EXPORT QmlAbstractBinding
{
public:
- QmlBindingData();
- virtual ~QmlBindingData();
+ QmlAbstractBinding();
+ virtual ~QmlAbstractBinding();
- bool updating:1;
- bool enabled:1;
+ virtual void destroy();
- QmlMetaProperty property;
+ virtual QString expression() const;
- virtual void refresh();
+ void setEnabled(bool e) { setEnabled(e, QmlMetaProperty::DontRemoveBinding); }
+ virtual void setEnabled(bool, QmlMetaProperty::WriteFlags) = 0;
+ virtual int propertyIndex() = 0;
+
+ void update() { update(QmlMetaProperty::DontRemoveBinding); }
+ virtual void update(QmlMetaProperty::WriteFlags) = 0;
+
+ void addToObject(QObject *);
+ void removeFromObject();
+
+protected:
+ void clear();
+
+private:
+ friend class QmlDeclarativeData;
+ friend class QmlMetaProperty;
+ friend class QmlMetaPropertyPrivate;
+ friend class QmlVME;
+
+ QObject *m_object;
+ QmlAbstractBinding **m_mePtr;
+ QmlAbstractBinding **m_prevBinding;
+ QmlAbstractBinding *m_nextBinding;
};
-class QmlBindingPrivate : public QmlExpressionPrivate
+class QmlContext;
+class QmlBindingPrivate;
+class Q_AUTOTEST_EXPORT QmlBinding : public QmlExpression, public QmlAbstractBinding
{
- Q_DECLARE_PUBLIC(QmlBinding)
+Q_OBJECT
public:
- QmlBindingPrivate();
+ QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0);
+ QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, const QString &, int,
+ QObject *parent);
+ ~QmlBinding();
+
+ void setTarget(const QmlMetaProperty &);
+ QmlMetaProperty property() const;
+
+ bool enabled() const;
+
+ // Inherited from QmlAbstractBinding
+ virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags);
+ virtual int propertyIndex();
+ virtual void update(QmlMetaProperty::WriteFlags flags);
+ virtual QString expression() const;
+
+public Q_SLOTS:
+ void update() { update(QmlMetaProperty::DontRemoveBinding); }
+
+protected:
+ void emitValueChanged();
- QmlBindingData *bindingData() { return static_cast<QmlBindingData *>(data); }
- const QmlBindingData *bindingData() const { return static_cast<const QmlBindingData *>(data); }
+private:
+ Q_DECLARE_PRIVATE(QmlBinding)
};
+Q_DECLARE_METATYPE(QmlBinding*);
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlbinding_p_p.h b/src/declarative/qml/qmlbinding_p_p.h
new file mode 100644
index 0000000..131bacc
--- /dev/null
+++ b/src/declarative/qml/qmlbinding_p_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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 QMLBINDING_P_P_H
+#define QMLBINDING_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 "qmlbinding_p.h"
+
+#include "qmlmetaproperty.h"
+#include "qmlexpression_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlBindingData : public QmlExpressionData
+{
+public:
+ QmlBindingData();
+ virtual ~QmlBindingData();
+
+ bool updating:1;
+ bool enabled:1;
+
+ QmlMetaProperty property;
+
+ virtual void refresh();
+};
+
+class QmlBindingPrivate : public QmlExpressionPrivate
+{
+ Q_DECLARE_PUBLIC(QmlBinding)
+public:
+ QmlBindingPrivate();
+
+ QmlBindingData *bindingData() { return static_cast<QmlBindingData *>(data); }
+ const QmlBindingData *bindingData() const { return static_cast<const QmlBindingData *>(data); }
+
+ virtual void emitValueChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLBINDING_P_P_H
diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp
index a075899..db5fd61 100644
--- a/src/declarative/qml/qmlboundsignal.cpp
+++ b/src/declarative/qml/qmlboundsignal.cpp
@@ -124,7 +124,6 @@ QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val,
QMetaObject::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
m_expression = new QmlExpression(ctxt, val, scope);
- m_expression->setTrackChange(false);
}
QmlBoundSignal::~QmlBoundSignal()
@@ -157,7 +156,7 @@ QmlExpression *QmlBoundSignal::setExpression(QmlExpression *e)
{
QmlExpression *rv = m_expression;
m_expression = e;
- if (m_expression) m_expression->setTrackChange(false);
+ if (m_expression) m_expression->setNotifyOnValueChanged(false);
return rv;
}
diff --git a/src/declarative/qml/qmlcompiledbindings_p.h b/src/declarative/qml/qmlcompiledbindings_p.h
index 38fb2a3..056cc21 100644
--- a/src/declarative/qml/qmlcompiledbindings_p.h
+++ b/src/declarative/qml/qmlcompiledbindings_p.h
@@ -54,7 +54,7 @@
//
#include "qmlexpression_p.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
QT_BEGIN_HEADER
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index bbae201..10b6e4f 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -63,7 +63,7 @@
#include "qmlscriptstring.h"
#include "qmlglobal_p.h"
#include "qmlscriptparser_p.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
#include "qmlcompiledbindings_p.h"
#include <qfxperf_p_p.h>
diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp
index 87ecb8a..4ab4f70 100644
--- a/src/declarative/qml/qmlcomponent.cpp
+++ b/src/declarative/qml/qmlcomponent.cpp
@@ -49,8 +49,8 @@
#include "qmlvme_p.h"
#include "qml.h"
#include "qmlengine.h"
-#include "qmlbinding.h"
#include "qmlbinding_p.h"
+#include "qmlbinding_p_p.h"
#include "qmlglobal_p.h"
#include "qmlscriptparser_p.h"
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 97d8250..2460f52 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -51,7 +51,7 @@
#include "qmlcomponent.h"
#include "qmlmetaproperty_p.h"
#include "qmlmoduleplugin.h"
-#include "qmlbinding_p.h"
+#include "qmlbinding_p_p.h"
#include "qmlvme_p.h"
#include "qmlenginedebug_p.h"
#include "qmlstringconverters_p.h"
diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp
index 654157c..973e5e5 100644
--- a/src/declarative/qml/qmlenginedebug.cpp
+++ b/src/declarative/qml/qmlenginedebug.cpp
@@ -45,7 +45,7 @@
#include "qmlengine.h"
#include "qmlmetatype.h"
#include "qmlmetaproperty.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
#include "qmlcontext_p.h"
#include "qmlwatcher_p.h"
@@ -408,14 +408,13 @@ void QmlEngineDebugServer::messageReceived(const QByteArray &message)
QmlContext *context = qmlContext(object);
QVariant result;
if (object && context) {
- QmlExpression *exprObj = new QmlExpression(context, expr, object);
+ QmlExpression exprObj(context, expr, object);
bool undefined = false;
- QVariant value = exprObj->value(&undefined);
+ QVariant value = exprObj.value(&undefined);
if (undefined)
result = QLatin1String("<undefined>");
else
result = valueContents(value);
- delete exprObj;
} else {
result = QLatin1String("<unknown context>");
}
diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp
index 8f0c945..64b2d7f 100644
--- a/src/declarative/qml/qmlexpression.cpp
+++ b/src/declarative/qml/qmlexpression.cpp
@@ -70,7 +70,7 @@ bool QmlDelayedError::addError(QmlEnginePrivate *e)
QmlExpressionData::QmlExpressionData()
: q(0), dataRef(0), expressionFunctionValid(false), expressionRewritten(false), me(0),
- trackChange(true), isShared(false), line(-1), guardList(0), guardListLength(0)
+ trackChange(false), isShared(false), line(-1), guardList(0), guardListLength(0)
{
}
@@ -273,14 +273,6 @@ QString QmlExpression::expression() const
}
/*!
- Clear the expression.
-*/
-void QmlExpression::clearExpression()
-{
- setExpression(QString());
-}
-
-/*!
Set the expression to \a expression.
*/
void QmlExpression::setExpression(const QString &expression)
@@ -495,44 +487,34 @@ QVariant QmlExpression::value(bool *isUndefined)
}
/*!
- Returns true if the expression results in a constant value.
- QmlExpression::value() must have been invoked at least once before the
- return from this method is valid.
- */
-bool QmlExpression::isConstant() const
-{
- Q_D(const QmlExpression);
- return !d->data->guardList;
-}
-
-/*!
- Returns true if the changes are tracked in the expression's value.
+Returns true if the valueChanged() signal is emitted when the expression's evaluated
+value changes.
*/
-bool QmlExpression::trackChange() const
+bool QmlExpression::notifyOnValueChanged() const
{
Q_D(const QmlExpression);
return d->data->trackChange;
}
/*!
- Set whether changes are tracked in the expression's value to \a trackChange.
+Sets whether the valueChanged() signal is emitted when the expression's evaluated
+value changes.
- If true, the QmlExpression will monitor properties involved in the
- expression's evaluation, and call QmlExpression::valueChanged() if they have
- changed. This allows an application to ensure that any value associated
- with the result of the expression remains up to date.
+If true, the QmlExpression will monitor properties involved in the expression's
+evaluation, and emit QmlExpression::valueChanged() if they have changed. This allows
+an application to ensure that any value associated with the result of the expression
+remains up to date.
- If false, the QmlExpression will not montitor properties involved in the
- expression's evaluation, and QmlExpression::valueChanged() will never be
- called. This is more efficient if an application wants a "one off"
- evaluation of the expression.
+If false, the QmlExpression will not montitor properties involved in the expression's
+evaluation, and QmlExpression::valueChanged() will never be emitted. This is more efficient
+if an application wants a "one off" evaluation of the expression.
- By default, trackChange is true.
+By default, notifyOnChange is false.
*/
-void QmlExpression::setTrackChange(bool trackChange)
+void QmlExpression::setNotifyOnValueChanged(bool notifyOnChange)
{
Q_D(QmlExpression);
- d->data->trackChange = trackChange;
+ d->data->trackChange = notifyOnChange;
}
/*!
@@ -618,7 +600,8 @@ QmlError QmlExpression::error() const
/*! \internal */
void QmlExpression::__q_notify()
{
- emitValueChanged();
+ Q_D(QmlExpression);
+ d->emitValueChanged();
}
void QmlExpressionPrivate::clearGuards()
@@ -765,13 +748,10 @@ void QmlExpressionPrivate::updateGuards(const QPODVector<QmlEnginePrivate::Captu
calling QmlExpression::value()) before this signal will be emitted.
*/
-/*!
- Subclasses can capture the emission of the valueChanged() signal by overriding
- this function. They can choose whether to then call valueChanged().
-*/
-void QmlExpression::emitValueChanged()
+void QmlExpressionPrivate::emitValueChanged()
{
- emit valueChanged();
+ Q_Q(QmlExpression);
+ emit q->valueChanged();
}
QmlAbstractExpression::QmlAbstractExpression()
diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h
index 428eefa..61374f2 100644
--- a/src/declarative/qml/qmlexpression.h
+++ b/src/declarative/qml/qmlexpression.h
@@ -70,12 +70,10 @@ public:
QmlContext *context() const;
QString expression() const;
- void clearExpression();
- virtual void setExpression(const QString &);
- bool isConstant() const;
+ void setExpression(const QString &);
- bool trackChange() const;
- void setTrackChange(bool);
+ bool notifyOnValueChanged() const;
+ void setNotifyOnValueChanged(bool);
QString sourceFile() const;
int lineNumber() const;
@@ -87,15 +85,12 @@ public:
void clearError();
QmlError error() const;
-public Q_SLOTS:
QVariant value(bool *isUndefined = 0);
Q_SIGNALS:
void valueChanged();
protected:
- virtual void emitValueChanged();
-
QmlExpression(QmlContext *, const QString &, QObject *,
QmlExpressionPrivate &dd);
QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, const QString &,
diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h
index e52a199..e4bed05 100644
--- a/src/declarative/qml/qmlexpression_p.h
+++ b/src/declarative/qml/qmlexpression_p.h
@@ -177,6 +177,8 @@ public:
return expr->q_func();
}
+ virtual void emitValueChanged();
+
static void exceptionToError(QScriptEngine *, QmlError &);
static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QString &);
static QScriptValue evalInObjectScope(QmlContext *, QObject *, const QScriptProgram &);
diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp
index 1742c43..ac619ec 100644
--- a/src/declarative/qml/qmlmetaproperty.cpp
+++ b/src/declarative/qml/qmlmetaproperty.cpp
@@ -44,7 +44,7 @@
#include "qmlcompositetypedata_p.h"
#include "qml.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
#include "qmlcontext.h"
#include "qmlcontext_p.h"
#include "qmlboundsignal_p.h"
diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp
index 15ece1d..155a7d6 100644
--- a/src/declarative/qml/qmlobjectscriptclass.cpp
+++ b/src/declarative/qml/qmlobjectscriptclass.cpp
@@ -46,7 +46,7 @@
#include "qmldeclarativedata_p.h"
#include "qmltypenamescriptclass_p.h"
#include "qmllistscriptclass_p.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
#include "qmlguard_p.h"
#include "qmlvmemetaobject_p.h"
diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp
index a3e655b..2d087b6 100644
--- a/src/declarative/qml/qmlpropertycache.cpp
+++ b/src/declarative/qml/qmlpropertycache.cpp
@@ -42,8 +42,8 @@
#include "qmlpropertycache_p.h"
#include "qmlengine_p.h"
-#include "qmlbinding.h"
-#include "qdebug.h"
+#include "qmlbinding_p.h"
+#include <QtCore/qdebug.h>
Q_DECLARE_METATYPE(QScriptValue);
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 8655809..f8f1ff0 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -51,11 +51,11 @@
#include "qmlengine.h"
#include "qmlcontext.h"
#include "qmlcomponent.h"
-#include "qmlbinding.h"
+#include "qmlbinding_p.h"
#include "qmlengine_p.h"
#include "qmlcomponent_p.h"
#include "qmlvmemetaobject_p.h"
-#include "qmlbinding_p.h"
+#include "qmlbinding_p_p.h"
#include "qmlcontext_p.h"
#include "qmlcompiledbindings_p.h"
#include "qmlglobal_p.h"
diff --git a/src/declarative/qml/qmlwatcher.cpp b/src/declarative/qml/qmlwatcher.cpp
index 59503de..a8a94c5 100644
--- a/src/declarative/qml/qmlwatcher.cpp
+++ b/src/declarative/qml/qmlwatcher.cpp
@@ -154,6 +154,7 @@ bool QmlWatcher::addWatch(int id, quint32 objectId, const QString &expr)
QmlContext *context = qmlContext(object);
if (context) {
QmlExpression *exprObj = new QmlExpression(context, expr, object);
+ exprObj->setNotifyOnValueChanged(true);
QmlWatchProxy *proxy = new QmlWatchProxy(id, exprObj, objectId, this);
exprObj->setParent(proxy);
m_proxies[id].append(proxy);
diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp
index c044f97..6dcce58 100644
--- a/src/declarative/util/qmlanimation.cpp
+++ b/src/declarative/util/qmlanimation.cpp
@@ -793,7 +793,6 @@ void QmlScriptActionPrivate::execute()
const QString &str = scriptStr.script();
if (!str.isEmpty()) {
QmlExpression expr(scriptStr.context(), str, scriptStr.scopeObject());
- expr.setTrackChange(false);
expr.value();
}
}
diff --git a/src/declarative/util/qmlpropertychanges.cpp b/src/declarative/util/qmlpropertychanges.cpp
index 068cb4d..3abbadd 100644
--- a/src/declarative/util/qmlpropertychanges.cpp
+++ b/src/declarative/util/qmlpropertychanges.cpp
@@ -47,7 +47,7 @@
#include <qmlcustomparser_p.h>
#include <qmlparser_p.h>
#include <qmlexpression.h>
-#include <qmlbinding.h>
+#include <qmlbinding_p.h>
#include <qmlcontext.h>
#include <qmlguard_p.h>
@@ -277,14 +277,12 @@ void QmlPropertyChangesPrivate::decode()
QmlMetaProperty prop = property(name); //### better way to check for signal property?
if (prop.type() & QmlMetaProperty::SignalProperty) {
QmlExpression *expression = new QmlExpression(qmlContext(q), data.toString(), object);
- expression->setTrackChange(false);
QmlReplaceSignalHandler *handler = new QmlReplaceSignalHandler;
handler->property = prop;
handler->expression = expression;
signalReplacements << handler;
} else if (isScript) {
QmlExpression *expression = new QmlExpression(qmlContext(q), data.toString(), object);
- expression->setTrackChange(false);
expressions << qMakePair(name, expression);
} else {
properties << qMakePair(name, data);
diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp
index 4462b1f..ea99bd5 100644
--- a/src/declarative/util/qmlstate.cpp
+++ b/src/declarative/util/qmlstate.cpp
@@ -48,7 +48,7 @@
#include "qmlanimation_p.h"
#include "qmlanimation_p_p.h"
-#include <qmlbinding.h>
+#include <qmlbinding_p.h>
#include <qmlglobal_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/declarative/util/qmlstategroup.cpp b/src/declarative/util/qmlstategroup.cpp
index 4ad77c8..7a5db1b 100644
--- a/src/declarative/util/qmlstategroup.cpp
+++ b/src/declarative/util/qmlstategroup.cpp
@@ -44,7 +44,7 @@
#include "qmltransition_p.h"
#include "qmlstate_p_p.h"
-#include <qmlbinding.h>
+#include <qmlbinding_p.h>
#include <qmlglobal_p.h>
#include <QtCore/qdebug.h>
diff --git a/src/declarative/util/qmlstateoperations.cpp b/src/declarative/util/qmlstateoperations.cpp
index bd1f5f0..fff8774 100644
--- a/src/declarative/util/qmlstateoperations.cpp
+++ b/src/declarative/util/qmlstateoperations.cpp
@@ -373,7 +373,6 @@ void QmlStateChangeScript::execute()
const QString &script = d->script.script();
if (!script.isEmpty()) {
QmlExpression expr(d->script.context(), script, d->script.scopeObject());
- expr.setTrackChange(false);
expr.value();
}
}
diff --git a/src/declarative/util/qmltransitionmanager.cpp b/src/declarative/util/qmltransitionmanager.cpp
index f2a4d64..60d9a60 100644
--- a/src/declarative/util/qmltransitionmanager.cpp
+++ b/src/declarative/util/qmltransitionmanager.cpp
@@ -43,7 +43,7 @@
#include "qmlstate_p_p.h"
-#include <qmlbinding.h>
+#include <qmlbinding_p.h>
#include <qmlglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/declarative/util/qmlxmllistmodel.cpp b/src/declarative/util/qmlxmllistmodel.cpp
index e631cd9..6c9c03e 100644
--- a/src/declarative/util/qmlxmllistmodel.cpp
+++ b/src/declarative/util/qmlxmllistmodel.cpp
@@ -63,6 +63,8 @@ QT_BEGIN_NAMESPACE
QML_DEFINE_TYPE(Qt,4,6,XmlRole,QmlXmlListModelRole)
QML_DEFINE_TYPE(Qt,4,6,XmlListModel,QmlXmlListModel)
+typedef QPair<int, int> QmlXmlListRange;
+
/*!
\qmlclass XmlRole QmlXmlListModelRole
\brief The XmlRole element allows you to specify a role for an XmlListModel.
@@ -94,14 +96,26 @@ QML_DEFINE_TYPE(Qt,4,6,XmlListModel,QmlXmlListModel)
\endqml
*/
+/*!
+ \qmlproperty bool XmlRole::isKey
+ Defines whether this is a key role.
+
+ Key roles are used to to determine whether a set of values should
+ be updated or added to the XML list model when XmlListModel::reload()
+ is called.
+
+ \sa XmlListModel
+*/
+
class Q_DECLARATIVE_EXPORT QmlXmlListModelRole : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QString query READ query WRITE setQuery)
+ Q_PROPERTY(bool isKey READ isKey WRITE setIsKey)
public:
- QmlXmlListModelRole() {}
+ QmlXmlListModelRole() : m_isKey(false) {}
~QmlXmlListModelRole() {}
QString name() const { return m_name; }
@@ -117,6 +131,9 @@ public:
m_query = query;
}
+ bool isKey() const { return m_isKey; }
+ void setIsKey(bool b) { m_isKey = b; }
+
bool isValid() {
return !m_name.isEmpty() && !m_query.isEmpty();
}
@@ -124,6 +141,7 @@ public:
private:
QString m_name;
QString m_query;
+ bool m_isKey;
};
QT_END_NAMESPACE
QML_DECLARE_TYPE(QmlXmlListModelRole)
@@ -153,7 +171,6 @@ public:
int doQuery(QString query, QString namespaces, QByteArray data, QList<QmlXmlListModelRole *> *roleObjects) {
QMutexLocker locker(&m_mutex);
- m_modelData.clear();
m_size = 0;
m_data = data;
m_query = QLatin1String("doc($src)") + query;
@@ -175,6 +192,16 @@ public:
return m_modelData;
}
+ QList<QmlXmlListRange> insertedItemRanges() {
+ QMutexLocker locker(&m_mutex);
+ return m_insertedItemRanges;
+ }
+
+ QList<QmlXmlListRange> removedItemRanges() {
+ QMutexLocker locker(&m_mutex);
+ return m_removedItemRanges;
+ }
+
Q_SIGNALS:
void queryCompleted(int queryId, int size);
@@ -184,13 +211,12 @@ protected:
m_mutex.lock();
int queryId = m_queryId;
doQueryJob();
- if (m_size > 0)
- doSubQueryJob();
+ doSubQueryJob();
m_data.clear(); // no longer needed
m_mutex.unlock();
m_mutex.lock();
- if (!m_abort && m_size > 0)
+ if (!m_abort)
emit queryCompleted(queryId, m_size);
if (!m_restart)
m_condition.wait(&m_mutex);
@@ -203,6 +229,8 @@ protected:
private:
void doQueryJob();
void doSubQueryJob();
+ void getValuesOfKeyRoles(QStringList *values, QXmlQuery *query) const;
+ void addIndexToRangeList(QList<QmlXmlListRange> *ranges, int index) const;
private:
QMutex m_mutex;
@@ -218,6 +246,9 @@ private:
int m_queryId;
const QList<QmlXmlListModelRole *> *m_roleObjects;
QList<QList<QVariant> > m_modelData;
+ QStringList m_keysValues;
+ QList<QmlXmlListRange> m_insertedItemRanges;
+ QList<QmlXmlListRange> m_removedItemRanges;
};
void QmlXmlQuery::doQueryJob()
@@ -262,6 +293,40 @@ void QmlXmlQuery::doQueryJob()
m_size = count;
}
+void QmlXmlQuery::getValuesOfKeyRoles(QStringList *values, QXmlQuery *query) const
+{
+ QStringList keysQueries;
+ for (int i=0; i<m_roleObjects->count(); i++) {
+ if (m_roleObjects->at(i)->isKey())
+ keysQueries << m_roleObjects->at(i)->query();
+ }
+ QString keysQuery;
+ if (keysQueries.count() == 1)
+ keysQuery = m_prefix + keysQueries[0];
+ else if (keysQueries.count() > 1)
+ keysQuery = m_prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")");
+
+ if (!keysQuery.isEmpty()) {
+ query->setQuery(keysQuery);
+ QXmlResultItems resultItems;
+ query->evaluateTo(&resultItems);
+ QXmlItem item(resultItems.next());
+ while (!item.isNull()) {
+ values->append(item.toAtomicValue().toString());
+ item = resultItems.next();
+ }
+ }
+}
+
+void QmlXmlQuery::addIndexToRangeList(QList<QmlXmlListRange> *ranges, int index) const {
+ if (ranges->isEmpty())
+ ranges->append(qMakePair(index, 1));
+ else if (ranges->last().first + ranges->last().second == index)
+ ranges->last().second += 1;
+ else
+ ranges->append(qMakePair(index, 1));
+}
+
void QmlXmlQuery::doSubQueryJob()
{
m_modelData.clear();
@@ -272,6 +337,35 @@ void QmlXmlQuery::doSubQueryJob()
QXmlQuery subquery;
subquery.bindVariable(QLatin1String("inputDocument"), &b);
+ QStringList keysValues;
+ getValuesOfKeyRoles(&keysValues, &subquery);
+
+ // See if any values of key roles have been inserted or removed.
+ m_insertedItemRanges.clear();
+ m_removedItemRanges.clear();
+ if (m_keysValues.isEmpty()) {
+ m_insertedItemRanges << qMakePair(0, m_size);
+ } else {
+ if (keysValues != m_keysValues) {
+ QStringList temp;
+ for (int i=0; i<m_keysValues.count(); i++) {
+ if (!keysValues.contains(m_keysValues[i]))
+ addIndexToRangeList(&m_removedItemRanges, i);
+ else
+ temp << m_keysValues[i];
+ }
+
+ for (int i=0; i<keysValues.count(); i++) {
+ if (temp.count() == i || keysValues[i] != temp[i]) {
+ temp.insert(i, keysValues[i]);
+ addIndexToRangeList(&m_insertedItemRanges, i);
+ }
+ }
+ }
+ }
+ m_keysValues = keysValues;
+
+ // Get the new values for each role.
//### we might be able to condense even further (query for everything in one go)
for (int i = 0; i < m_roleObjects->size(); ++i) {
QmlXmlListModelRole *role = m_roleObjects->at(i);
@@ -283,13 +377,13 @@ void QmlXmlQuery::doSubQueryJob()
continue;
}
subquery.setQuery(m_prefix + QLatin1String("(let $v := ") + role->query() + QLatin1String(" return if ($v) then ") + role->query() + QLatin1String(" else \"\")"));
- QXmlResultItems output3;
- subquery.evaluateTo(&output3);
- QXmlItem item(output3.next());
+ QXmlResultItems resultItems;
+ subquery.evaluateTo(&resultItems);
+ QXmlItem item(resultItems.next());
QList<QVariant> resultList;
while (!item.isNull()) {
resultList << item.toAtomicValue(); //### we used to trim strings
- item = output3.next();
+ item = resultItems.next();
}
//### should warn here if things have gone wrong.
while (resultList.count() < m_size)
@@ -392,25 +486,40 @@ void QmlXmlListModelPrivate::clear_role(QmlListProperty<QmlXmlListModelRole> *li
/*!
\qmlclass XmlListModel QmlXmlListModel
- \brief The XmlListModel element allows you to specify a model using XPath expressions.
+ \brief The XmlListModel element is used to specify a model using XPath expressions.
- XmlListModel allows you to construct a model from XML data that can then be used as a data source
- for the view classes (ListView, PathView, GridView) and any other classes that interact with model
- data (like Repeater).
+ XmlListModel is used to create a model from XML data that can be used as a data source
+ for the view classes (such as ListView, PathView, GridView) and other classes that interact with model
+ data (such as Repeater).
- The following is an example of a model containing news from a Yahoo RSS feed:
+ Here is an example of a model containing news from a Yahoo RSS feed:
\qml
XmlListModel {
id: feedModel
source: "http://rss.news.yahoo.com/rss/oceania"
query: "/rss/channel/item"
XmlRole { name: "title"; query: "title/string()" }
- XmlRole { name: "link"; query: "link/string()" }
+ XmlRole { name: "pubDate"; query: "pubDate/string()" }
XmlRole { name: "description"; query: "description/string()" }
}
\endqml
- \note The model is currently static, so the above is really just a snapshot of an RSS feed. To force a
- reload of the entire model, you can call the reload function.
+
+ You can also define certain roles as "keys" so that the model only adds data
+ that contains new values for these keys when reload() is called.
+
+ For example, if the roles above were defined like this:
+
+ \qml
+ XmlRole { name: "title"; query: "title/string()"; isKey: true }
+ XmlRole { name: "pubDate"; query: "pubDate/string()"; isKey: true }
+ \endqml
+
+ Then when reload() is called, the model will only add new items with a
+ "title" and "pubDate" value combination that is not already present in
+ the model.
+
+ This is useful to provide incremental updates and avoid repainting an
+ entire model in a view.
*/
QmlXmlListModel::QmlXmlListModel(QObject *parent)
@@ -526,9 +635,9 @@ void QmlXmlListModel::setXml(const QString &xml)
}
/*!
- \qmlproperty url XmlListModel::query
+ \qmlproperty string XmlListModel::query
An absolute XPath query representing the base query for the model items. The query should start with
- a '/' or '//'.
+ '/' or '//'.
*/
QString QmlXmlListModel::query() const
{
@@ -619,8 +728,13 @@ void QmlXmlListModel::componentComplete()
/*!
\qmlmethod XmlListModel::reload()
- Reloads the model. All the existing model data will be removed, and the model
- will be rebuilt from scratch.
+ Reloads the model.
+
+ If no key roles have been specified, all existing model
+ data is removed, and the model is rebuilt from scratch.
+
+ Otherwise, items are only added if the model does not already
+ contain items with matching key role values.
*/
void QmlXmlListModel::reload()
{
@@ -632,12 +746,8 @@ void QmlXmlListModel::reload()
d->qmlXmlQuery.abort();
d->queryId = -1;
- //clear existing data
- int count = d->size;
- d->size = 0;
- d->data.clear();
- if (count > 0)
- emit itemsRemoved(0, count);
+ if (d->size < 0)
+ d->size = 0;
if (d->src.isEmpty() && d->xml.isEmpty())
return;
@@ -704,12 +814,19 @@ void QmlXmlListModel::queryCompleted(int id, int size)
Q_D(QmlXmlListModel);
if (id != d->queryId)
return;
+ bool sizeChanged = size != d->size;
d->size = size;
- if (size > 0) {
- d->data = d->qmlXmlQuery.modelData();
- emit itemsInserted(0, d->size);
+ d->data = d->qmlXmlQuery.modelData();
+
+ QList<QmlXmlListRange> removed = d->qmlXmlQuery.removedItemRanges();
+ for (int i=0; i<removed.count(); i++)
+ emit itemsRemoved(removed[i].first, removed[i].second);
+ QList<QmlXmlListRange> inserted = d->qmlXmlQuery.insertedItemRanges();
+ for (int i=0; i<inserted.count(); i++)
+ emit itemsInserted(inserted[i].first, inserted[i].second);
+
+ if (sizeChanged)
emit countChanged();
- }
}
QT_END_NAMESPACE
diff --git a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp
index ba07331..2f1a557 100644
--- a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp
+++ b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp
@@ -51,8 +51,8 @@
#include <QtDeclarative/qmlexpression.h>
#include <QtDeclarative/qmlmetatype.h>
#include <QtDeclarative/qmlmetaproperty.h>
-#include <QtDeclarative/qmlbinding.h>
+#include <private/qmlbinding_p.h>
#include <private/qmldebug_p.h>
#include <private/qmlenginedebug_p.h>
#include <private/qmldebugclient_p.h>
diff --git a/tests/auto/declarative/qmlecmascript/testtypes.h b/tests/auto/declarative/qmlecmascript/testtypes.h
index 0af72cb..f511c29 100644
--- a/tests/auto/declarative/qmlecmascript/testtypes.h
+++ b/tests/auto/declarative/qmlecmascript/testtypes.h
@@ -173,17 +173,21 @@ QML_DECLARE_TYPE(MyQmlContainer);
class MyExpression : public QmlExpression
{
+ Q_OBJECT
public:
MyExpression(QmlContext *ctxt, const QString &expr)
: QmlExpression(ctxt, expr, 0), changed(false)
{
+ QObject::connect(this, SIGNAL(valueChanged()), this, SLOT(expressionValueChanged()));
+ setNotifyOnValueChanged(true);
}
- void emitValueChanged() {
+ bool changed;
+
+public slots:
+ void expressionValueChanged() {
changed = true;
- QmlExpression::emitValueChanged();
}
- bool changed;
};
diff --git a/tests/auto/declarative/qmlgraphicslistview/tst_qmlgraphicslistview.cpp b/tests/auto/declarative/qmlgraphicslistview/tst_qmlgraphicslistview.cpp
index e535aaa..cf96ad5 100644
--- a/tests/auto/declarative/qmlgraphicslistview/tst_qmlgraphicslistview.cpp
+++ b/tests/auto/declarative/qmlgraphicslistview/tst_qmlgraphicslistview.cpp
@@ -1319,7 +1319,6 @@ T *tst_QmlGraphicsListView::findItem(QGraphicsObject *parent, const QString &obj
if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
if (index != -1) {
QmlExpression e(qmlContext(item), "index", item);
- e.setTrackChange(false);
if (e.value().toInt() == index)
return static_cast<T*>(item);
} else {
diff --git a/tests/auto/declarative/qmlgraphicspathview/tst_qmlgraphicspathview.cpp b/tests/auto/declarative/qmlgraphicspathview/tst_qmlgraphicspathview.cpp
index bb1c1af..b57142e 100644
--- a/tests/auto/declarative/qmlgraphicspathview/tst_qmlgraphicspathview.cpp
+++ b/tests/auto/declarative/qmlgraphicspathview/tst_qmlgraphicspathview.cpp
@@ -450,7 +450,6 @@ T *tst_QmlGraphicsPathView::findItem(QGraphicsObject *parent, const QString &obj
if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
if (index != -1) {
QmlExpression e(qmlContext(item), "index", item);
- e.setTrackChange(false);
if (e.value().toInt() == index)
return static_cast<T*>(item);
} else {
diff --git a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp
index c289641..540d658 100644
--- a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp
+++ b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp
@@ -43,7 +43,7 @@
#include <QtDeclarative/qmlcomponent.h>
#include <QtDeclarative/qmlmetaproperty.h>
#include <private/qguard_p.h>
-#include <QtDeclarative/qmlbinding.h>
+#include <private/qmlbinding_p.h>
#include <QtGui/QLineEdit>
class MyQmlObject : public QObject
diff --git a/tests/auto/declarative/qmlxmllistmodel/tst_qmlxmllistmodel.cpp b/tests/auto/declarative/qmlxmllistmodel/tst_qmlxmllistmodel.cpp
index df1931f..477b661 100644
--- a/tests/auto/declarative/qmlxmllistmodel/tst_qmlxmllistmodel.cpp
+++ b/tests/auto/declarative/qmlxmllistmodel/tst_qmlxmllistmodel.cpp
@@ -39,6 +39,8 @@
**
****************************************************************************/
#include <qtest.h>
+#include <QtTest/qsignalspy.h>
+#include <QtCore/qtimer.h>
#ifdef QTEST_XMLPATTERNS
#include <QtDeclarative/qmlengine.h>
@@ -46,6 +48,12 @@
#include <private/qmlxmllistmodel_p.h>
#include "../../../shared/util.h"
+typedef QPair<int, int> QmlXmlListRange;
+typedef QList<QVariantList> QmlXmlModelData;
+
+Q_DECLARE_METATYPE(QList<QmlXmlListRange>)
+Q_DECLARE_METATYPE(QmlXmlModelData)
+
class tst_qmlxmllistmodel : public QObject
{
@@ -61,8 +69,47 @@ private slots:
void roles();
void roleErrors();
void uniqueRoleNames();
+ void useKeys();
+ void useKeys_data();
+ void noKeysValueChanges();
+ void keysChanged();
private:
+ QString makeItemXmlAndData(const QString &data, QmlXmlModelData *modelData = 0) const
+ {
+ if (modelData)
+ modelData->clear();
+ QString xml;
+
+ if (!data.isEmpty()) {
+ QStringList items = data.split(";");
+ foreach(const QString &item, items) {
+ QVariantList variants;
+ xml += QLatin1String("<item>");
+ QStringList fields = item.split(",");
+ foreach(const QString &field, fields) {
+ QStringList values = field.split("=");
+ Q_ASSERT(values.count() == 2);
+ xml += QString("<%1>%2</%1>").arg(values[0], values[1]);
+ if (!modelData)
+ continue;
+ bool isNum = false;
+ int number = values[1].toInt(&isNum);
+ if (isNum)
+ variants << number;
+ else
+ variants << values[1];
+ }
+ xml += QLatin1String("</item>");
+ if (modelData)
+ modelData->append(variants);
+ }
+ }
+
+ QString decl = "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>";
+ return decl + QLatin1String("<data>") + xml + QLatin1String("</data>");
+ }
+
QmlEngine engine;
};
@@ -194,6 +241,213 @@ void tst_qmlxmllistmodel::uniqueRoleNames()
delete listModel;
}
+void tst_qmlxmllistmodel::useKeys()
+{
+ // If using incremental updates through keys, the model should only
+ // insert & remove some of the items, instead of throwing everything
+ // away and causing the view to repaint the whole view.
+
+ QFETCH(QString, oldXml);
+ QFETCH(int, oldCount);
+ QFETCH(QString, newXml);
+ QFETCH(QmlXmlModelData, newData);
+ QFETCH(QList<QmlXmlListRange>, insertRanges);
+ QFETCH(QList<QmlXmlListRange>, removeRanges);
+
+ QmlComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/roleKeys.qml"));
+ QmlXmlListModel *model = qobject_cast<QmlXmlListModel*>(component.create());
+ QVERIFY(model != 0);
+
+ model->setXml(oldXml);
+ QTRY_COMPARE(model->count(), oldCount);
+
+ QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int)));
+ QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int)));
+ QSignalSpy spyCount(model, SIGNAL(countChanged()));
+
+ model->setXml(newXml);
+
+ if (oldCount != newData.count()) {
+ QTRY_COMPARE(model->count(), newData.count());
+ QCOMPARE(spyCount.count(), 1);
+ } else {
+ QTRY_VERIFY(spyInsert.count() > 0 || spyRemove.count() > 0);
+ QCOMPARE(spyCount.count(), 0);
+ }
+
+ QList<int> roles = model->roles();
+ for (int i=0; i<model->count(); i++) {
+ for (int j=0; j<roles.count(); j++)
+ QCOMPARE(model->data(i, roles[j]), newData[i][j]);
+ }
+
+ QCOMPARE(spyInsert.count(), insertRanges.count());
+ for (int i=0; i<spyInsert.count(); i++) {
+ QCOMPARE(spyInsert[i][0].toInt(), insertRanges[i].first);
+ QCOMPARE(spyInsert[i][1].toInt(), insertRanges[i].second);
+ }
+
+ QCOMPARE(spyRemove.count(), removeRanges.count());
+ for (int i=0; i<spyRemove.count(); i++) {
+ QCOMPARE(spyRemove[i][0].toInt(), removeRanges[i].first);
+ QCOMPARE(spyRemove[i][1].toInt(), removeRanges[i].second);
+ }
+}
+
+void tst_qmlxmllistmodel::useKeys_data()
+{
+ QTest::addColumn<QString>("oldXml");
+ QTest::addColumn<int>("oldCount");
+ QTest::addColumn<QString>("newXml");
+ QTest::addColumn<QmlXmlModelData>("newData");
+ QTest::addColumn<QList<QmlXmlListRange> >("insertRanges");
+ QTest::addColumn<QList<QmlXmlListRange> >("removeRanges");
+
+ QmlXmlModelData modelData;
+
+ QTest::newRow("append 1")
+ << makeItemXmlAndData("name=A,age=25,sport=Football") << 1
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(1, 1))
+ << QList<QmlXmlListRange>();
+
+ QTest::newRow("append multiple")
+ << makeItemXmlAndData("name=A,age=25,sport=Football") << 1
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(1, 2))
+ << QList<QmlXmlListRange>();
+
+ QTest::newRow("insert in different spots")
+ << makeItemXmlAndData("name=B,age=35,sport=Athletics") << 1
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2))
+ << QList<QmlXmlListRange>();
+
+ QTest::newRow("insert in middle")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=D,age=55,sport=Golf") << 2
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(1, 2))
+ << QList<QmlXmlListRange>();
+
+ QTest::newRow("remove first")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2
+ << makeItemXmlAndData("name=B,age=35,sport=Athletics", &modelData)
+ << modelData
+ << QList<QmlXmlListRange>()
+ << (QList<QmlXmlListRange>() << qMakePair(0, 1));
+
+ QTest::newRow("remove last")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2
+ << makeItemXmlAndData("name=A,age=25,sport=Football", &modelData)
+ << modelData
+ << QList<QmlXmlListRange>()
+ << (QList<QmlXmlListRange>() << qMakePair(1, 1));
+
+ QTest::newRow("remove from multiple spots")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 5
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=C,age=45,sport=Curling", &modelData)
+ << modelData
+ << QList<QmlXmlListRange>()
+ << (QList<QmlXmlListRange>() << qMakePair(1, 1) << qMakePair(3,2));
+
+ QTest::newRow("remove all")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling") << 3
+ << makeItemXmlAndData("", &modelData)
+ << modelData
+ << QList<QmlXmlListRange>()
+ << (QList<QmlXmlListRange>() << qMakePair(0, 3));
+
+ QTest::newRow("replace item")
+ << makeItemXmlAndData("name=A,age=25,sport=Football") << 1
+ << makeItemXmlAndData("name=ZZZ,age=25,sport=Football", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(0, 1))
+ << (QList<QmlXmlListRange>() << qMakePair(0, 1));
+
+ QTest::newRow("add and remove simultaneously")
+ << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf") << 4
+ << makeItemXmlAndData("name=B,age=35,sport=Athletics;name=E,age=65,sport=Fencing", &modelData)
+ << modelData
+ << (QList<QmlXmlListRange>() << qMakePair(1, 1))
+ << (QList<QmlXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2));
+}
+
+void tst_qmlxmllistmodel::noKeysValueChanges()
+{
+ // The 'key' roles are 'name' and 'age', as defined in roleKeys.qml.
+ // If a 'sport' value is changed, the model should not be reloaded,
+ // since 'sport' is not marked as a key.
+
+ QmlComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/roleKeys.qml"));
+ QmlXmlListModel *model = qobject_cast<QmlXmlListModel*>(component.create());
+ QVERIFY(model != 0);
+
+ QString xml;
+
+ xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics");
+ model->setXml(xml);
+ QTRY_COMPARE(model->count(), 2);
+
+ QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int)));
+ QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int)));
+ QSignalSpy spyCount(model, SIGNAL(countChanged()));
+
+ xml = makeItemXmlAndData("name=A,age=25,sport=AussieRules;name=B,age=35,sport=Athletics");
+ model->setXml(xml);
+
+ // wait for the new xml data to be set, and verify no signals were emitted
+ for (int i=0; i<50; i++) {
+ QTest::qWait(100);
+ if (model->data(0, model->roles()[2]).toString() != QLatin1String("AussieRules"))
+ break;
+ }
+ QCOMPARE(model->data(0, model->roles()[2]).toString(), QLatin1String("AussieRules"));
+
+ QVERIFY(spyInsert.count() == 0);
+ QVERIFY(spyRemove.count() == 0);
+ QVERIFY(spyCount.count() == 0);
+
+ QCOMPARE(model->count(), 2);
+}
+
+void tst_qmlxmllistmodel::keysChanged()
+{
+ // If the key roles change, the next time the data is reloaded, it should
+ // delete all its data and build a clean model (i.e. same behaviour as
+ // if no keys are set).
+
+ QmlComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/roleKeys.qml"));
+ QmlXmlListModel *model = qobject_cast<QmlXmlListModel*>(component.create());
+ QVERIFY(model != 0);
+
+ QString xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics");
+ model->setXml(xml);
+ QTRY_COMPARE(model->count(), 2);
+
+ QSignalSpy spyInsert(model, SIGNAL(itemsInserted(int,int)));
+ QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int)));
+ QSignalSpy spyCount(model, SIGNAL(countChanged()));
+
+ QVERIFY(QMetaObject::invokeMethod(model, "disableNameKey"));
+ model->setXml(xml);
+
+ QTRY_VERIFY(spyInsert.count() > 0 && spyRemove.count() > 0);
+
+ QCOMPARE(spyInsert.count(), 1);
+ QCOMPARE(spyInsert[0][0].toInt(), 0);
+ QCOMPARE(spyInsert[0][1].toInt(), 2);
+
+ QCOMPARE(spyRemove.count(), 1);
+ QCOMPARE(spyRemove[0][0].toInt(), 0);
+ QCOMPARE(spyRemove[0][1].toInt(), 2);
+
+ QCOMPARE(spyCount.count(), 0);
+}
+
QTEST_MAIN(tst_qmlxmllistmodel)
#include "tst_qmlxmllistmodel.moc"