summaryrefslogtreecommitdiffstats
path: root/src/declarative/util
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-02-09 17:51:47 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-02-09 17:51:47 (GMT)
commit969b61f508294d1f683e09e78641127d0f0def05 (patch)
tree35ec77453b23327556643d6674d99b26c19e6ad6 /src/declarative/util
parent6165ab0203fa80d31f3488ead7e7f7c088c8668c (diff)
parent3071bbd9eb9833d19c6dd43b52079b6a8e1722b2 (diff)
downloadQt-969b61f508294d1f683e09e78641127d0f0def05.zip
Qt-969b61f508294d1f683e09e78641127d0f0def05.tar.gz
Qt-969b61f508294d1f683e09e78641127d0f0def05.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-qml into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-qml: (3355 commits) Get test compiling Remove unimplemented methods from header Properly insert objects into the context's object list Missed a file Compile Replace QList<>* support with QmlListProperty Remove old implicit module support. Use networkAccessManagerFactory() for worker threads too. Connect to localhost instead of QHostAddress::Any. Fixes test on Windows. Support the other validators Add empty constructor for validators. Add getter functions to QAbstractDynamicMetaObject and QmlOpenMetaObjectType Document QtObject Changed define name to reflect change in Creator. re-enable QT_USE_FAST_CONCATENATION XMLHttpRequest collection bug For local fonts, we can just addApplicationFont() rather than loading data. The virtual keyboard is now working for TextEdit and TextInput components. Fix viewport size update. Make transformOrigin Center by default ...
Diffstat (limited to 'src/declarative/util')
-rw-r--r--src/declarative/util/qfxperf.cpp67
-rw-r--r--src/declarative/util/qfxperf_p_p.h90
-rw-r--r--src/declarative/util/qmlanimation.cpp2329
-rw-r--r--src/declarative/util/qmlanimation_p.h440
-rw-r--r--src/declarative/util/qmlanimation_p_p.h383
-rw-r--r--src/declarative/util/qmlbehavior.cpp189
-rw-r--r--src/declarative/util/qmlbehavior_p.h92
-rw-r--r--src/declarative/util/qmlbind.cpp201
-rw-r--r--src/declarative/util/qmlbind_p.h95
-rw-r--r--src/declarative/util/qmlconnection.cpp287
-rw-r--r--src/declarative/util/qmlconnection_p.h93
-rw-r--r--src/declarative/util/qmldatetimeformatter.cpp372
-rw-r--r--src/declarative/util/qmldatetimeformatter_p.h117
-rw-r--r--src/declarative/util/qmleasefollow.cpp527
-rw-r--r--src/declarative/util/qmleasefollow_p.h114
-rw-r--r--src/declarative/util/qmlfontloader.cpp229
-rw-r--r--src/declarative/util/qmlfontloader_p.h95
-rw-r--r--src/declarative/util/qmllistaccessor.cpp262
-rw-r--r--src/declarative/util/qmllistaccessor_p.h85
-rw-r--r--src/declarative/util/qmllistmodel.cpp991
-rw-r--r--src/declarative/util/qmllistmodel_p.h107
-rw-r--r--src/declarative/util/qmlnullablevalue_p_p.h81
-rw-r--r--src/declarative/util/qmlnumberformatter.cpp260
-rw-r--r--src/declarative/util/qmlnumberformatter_p.h93
-rw-r--r--src/declarative/util/qmlopenmetaobject.cpp355
-rw-r--r--src/declarative/util/qmlopenmetaobject_p.h125
-rw-r--r--src/declarative/util/qmlpackage.cpp177
-rw-r--r--src/declarative/util/qmlpackage_p.h88
-rw-r--r--src/declarative/util/qmlpixmapcache.cpp605
-rw-r--r--src/declarative/util/qmlpixmapcache_p.h107
-rw-r--r--src/declarative/util/qmlpropertychanges.cpp468
-rw-r--r--src/declarative/util/qmlpropertychanges_p.h84
-rw-r--r--src/declarative/util/qmlpropertymap.cpp278
-rw-r--r--src/declarative/util/qmlpropertymap.h90
-rw-r--r--src/declarative/util/qmlspringfollow.cpp464
-rw-r--r--src/declarative/util/qmlspringfollow_p.h112
-rw-r--r--src/declarative/util/qmlstate.cpp468
-rw-r--r--src/declarative/util/qmlstate_p.h178
-rw-r--r--src/declarative/util/qmlstate_p_p.h147
-rw-r--r--src/declarative/util/qmlstategroup.cpp423
-rw-r--r--src/declarative/util/qmlstategroup_p.h95
-rw-r--r--src/declarative/util/qmlstateoperations.cpp834
-rw-r--r--src/declarative/util/qmlstateoperations_p.h184
-rw-r--r--src/declarative/util/qmlstyledtext.cpp343
-rw-r--r--src/declarative/util/qmlstyledtext_p.h63
-rw-r--r--src/declarative/util/qmlsystempalette.cpp303
-rw-r--r--src/declarative/util/qmlsystempalette_p.h122
-rw-r--r--src/declarative/util/qmltimeline.cpp941
-rw-r--r--src/declarative/util/qmltimeline_p_p.h223
-rw-r--r--src/declarative/util/qmltimer.cpp313
-rw-r--r--src/declarative/util/qmltimer_p.h109
-rw-r--r--src/declarative/util/qmltransition.cpp261
-rw-r--r--src/declarative/util/qmltransition_p.h101
-rw-r--r--src/declarative/util/qmltransitionmanager.cpp282
-rw-r--r--src/declarative/util/qmltransitionmanager_p_p.h85
-rw-r--r--src/declarative/util/qmlview.cpp586
-rw-r--r--src/declarative/util/qmlview.h113
-rw-r--r--src/declarative/util/qmlxmllistmodel.cpp728
-rw-r--r--src/declarative/util/qmlxmllistmodel_p.h136
-rw-r--r--src/declarative/util/qnumberformat.cpp225
-rw-r--r--src/declarative/util/qnumberformat_p.h174
-rw-r--r--src/declarative/util/qperformancelog.cpp181
-rw-r--r--src/declarative/util/qperformancelog_p_p.h141
-rw-r--r--src/declarative/util/util.pri72
64 files changed, 18383 insertions, 0 deletions
diff --git a/src/declarative/util/qfxperf.cpp b/src/declarative/util/qfxperf.cpp
new file mode 100644
index 0000000..f62f810
--- /dev/null
+++ b/src/declarative/util/qfxperf.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qfxperf_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DEFINE_PERFORMANCE_LOG(QmlPerf, "QmlGraphics") {
+ Q_DEFINE_PERFORMANCE_METRIC(QmlParsing, "Compilation: QML Parsing")
+ Q_DEFINE_PERFORMANCE_METRIC(Compilation, " QML Compilation")
+ Q_DEFINE_PERFORMANCE_METRIC(VMEExecution, "Execution: QML VME Execution")
+ Q_DEFINE_PERFORMANCE_METRIC(BindInit, "BindValue Initialization")
+ Q_DEFINE_PERFORMANCE_METRIC(BindValue, "BindValue execution")
+ Q_DEFINE_PERFORMANCE_METRIC(BindValueSSE, "BindValue execution SSE")
+ Q_DEFINE_PERFORMANCE_METRIC(BindValueQt, "BindValue execution QtScript")
+ Q_DEFINE_PERFORMANCE_METRIC(BindableValueUpdate, "QmlBinding::update")
+ Q_DEFINE_PERFORMANCE_METRIC(PixmapLoad, "Pixmap loading")
+ Q_DEFINE_PERFORMANCE_METRIC(FontDatabase, "Font database creation")
+ Q_DEFINE_PERFORMANCE_METRIC(QmlGraphicsPathViewPathCache, "FX Items: QmlGraphicsPathView: Path cache")
+ Q_DEFINE_PERFORMANCE_METRIC(CreateParticle, " QmlGraphicsParticles: Particle creation")
+ Q_DEFINE_PERFORMANCE_METRIC(ItemComponentComplete, " QmlGraphicsItem::componentComplete")
+ Q_DEFINE_PERFORMANCE_METRIC(ImageComponentComplete, " QmlGraphicsImage::componentComplete")
+ Q_DEFINE_PERFORMANCE_METRIC(BaseLayoutComponentComplete, " QmlGraphicsBasePositioner::componentComplete")
+ Q_DEFINE_PERFORMANCE_METRIC(TextComponentComplete, " QmlGraphicsText::componentComplete")
+ Q_DEFINE_PERFORMANCE_METRIC(QmlGraphicsText_setText, " QmlGraphicsText::setText")
+ Q_DEFINE_PERFORMANCE_METRIC(AddScript, "QmlScript::addScriptToEngine")
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qfxperf_p_p.h b/src/declarative/util/qfxperf_p_p.h
new file mode 100644
index 0000000..e3f820c
--- /dev/null
+++ b/src/declarative/util/qfxperf_p_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QFXPERF_H
+#define QFXPERF_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 "qperformancelog_p_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+Q_DECLARE_PERFORMANCE_LOG(QmlPerf) {
+ Q_DECLARE_PERFORMANCE_METRIC(QmlParsing)
+
+ Q_DECLARE_PERFORMANCE_METRIC(Compilation)
+ Q_DECLARE_PERFORMANCE_METRIC(VMEExecution)
+
+ Q_DECLARE_PERFORMANCE_METRIC(BindInit)
+ Q_DECLARE_PERFORMANCE_METRIC(BindValue)
+ Q_DECLARE_PERFORMANCE_METRIC(BindValueSSE)
+ Q_DECLARE_PERFORMANCE_METRIC(BindValueQt)
+ Q_DECLARE_PERFORMANCE_METRIC(BindableValueUpdate)
+ Q_DECLARE_PERFORMANCE_METRIC(PixmapLoad)
+ Q_DECLARE_PERFORMANCE_METRIC(FontDatabase)
+ Q_DECLARE_PERFORMANCE_METRIC(QmlGraphicsPathViewPathCache)
+ Q_DECLARE_PERFORMANCE_METRIC(CreateParticle)
+ Q_DECLARE_PERFORMANCE_METRIC(ItemComponentComplete)
+ Q_DECLARE_PERFORMANCE_METRIC(ImageComponentComplete)
+ Q_DECLARE_PERFORMANCE_METRIC(BaseLayoutComponentComplete)
+ Q_DECLARE_PERFORMANCE_METRIC(TextComponentComplete)
+ Q_DECLARE_PERFORMANCE_METRIC(QmlGraphicsText_setText)
+ Q_DECLARE_PERFORMANCE_METRIC(AddScript)
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXPERF_H
diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp
new file mode 100644
index 0000000..2d1d3b9
--- /dev/null
+++ b/src/declarative/util/qmlanimation.cpp
@@ -0,0 +1,2329 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlanimation_p.h"
+#include "qmlanimation_p_p.h"
+
+#include "qmlbehavior_p.h"
+#include "qmlstateoperations_p.h"
+
+#include <qmlpropertyvaluesource.h>
+#include <qml.h>
+#include <qmlinfo.h>
+#include <qmlexpression.h>
+#include <qmlstringconverters_p.h>
+#include <qmlglobal_p.h>
+
+#include <qvariant.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <QParallelAnimationGroup>
+#include <QSequentialAnimationGroup>
+#include <QtCore/qset.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+
+#include <private/qvariantanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QEasingCurve stringToCurve(const QString &curve, QObject *obj)
+{
+ QEasingCurve easingCurve;
+
+ QString normalizedCurve = curve;
+ bool hasParams = curve.contains(QLatin1Char('('));
+ QStringList props;
+
+ if (hasParams) {
+ QString easeName = curve.trimmed();
+ if (!easeName.endsWith(QLatin1Char(')'))) {
+ qmlInfo(obj) << obj->tr("Unmatched parenthesis in easing function \"%1\"").arg(curve);
+ return easingCurve;
+ }
+
+ int idx = easeName.indexOf(QLatin1Char('('));
+ QString prop_str =
+ easeName.mid(idx + 1, easeName.length() - 1 - idx - 1);
+ normalizedCurve = easeName.left(idx);
+ if (!normalizedCurve.startsWith(QLatin1String("ease"))) {
+ qmlInfo(obj) << obj->tr("Easing function \"%1\" must start with \"ease\"").arg(curve);
+ return easingCurve;
+ }
+
+ props = prop_str.split(QLatin1Char(','));
+ }
+
+ if (normalizedCurve.startsWith(QLatin1String("ease")))
+ normalizedCurve = normalizedCurve.mid(4);
+
+ static int index = QEasingCurve::staticMetaObject.indexOfEnumerator("Type");
+ static QMetaEnum me = QEasingCurve::staticMetaObject.enumerator(index);
+
+ int value = me.keyToValue(normalizedCurve.toUtf8().constData());
+ if (value < 0) {
+ qmlInfo(obj) << obj->tr("Unknown easing curve \"%1\"").arg(curve);
+ return easingCurve;
+ }
+ easingCurve.setType((QEasingCurve::Type)value);
+
+ if (hasParams) {
+ foreach(const QString &str, props) {
+ int sep = str.indexOf(QLatin1Char(':'));
+
+ if (sep == -1) {
+ qmlInfo(obj) << obj->tr("Improperly specified parameter in easing function \"%1\"").arg(curve);
+ continue;
+ }
+
+ QString propName = str.left(sep).trimmed();
+ bool isOk;
+ qreal propValue = str.mid(sep + 1).trimmed().toDouble(&isOk);
+
+ if (propName.isEmpty() || !isOk) {
+ qmlInfo(obj) << obj->tr("Improperly specified parameter in easing function \"%1\"").arg(curve);
+ continue;
+ }
+
+ if (propName == QLatin1String("amplitude")) {
+ easingCurve.setAmplitude(propValue);
+ } else if (propName == QLatin1String("period")) {
+ easingCurve.setPeriod(propValue);
+ } else if (propName == QLatin1String("overshoot")) {
+ easingCurve.setOvershoot(propValue);
+ } else {
+ qmlInfo(obj) << obj->tr("Unknown easing parameter \"%1\"").arg(propName);
+ continue;
+ }
+ }
+ }
+ return easingCurve;
+}
+
+QML_DEFINE_NOCREATE_TYPE(QmlAbstractAnimation)
+
+/*!
+ \qmlclass Animation QmlAbstractAnimation
+ \brief The Animation element is the base of all QML animations.
+
+ The Animation element cannot be used directly in a QML file. It exists
+ to provide a set of common properties and methods, available across all the
+ other animation types that inherit from it. Attempting to use the Animation
+ element directly will result in an error.
+*/
+
+/*!
+ \class QmlAbstractAnimation
+ \internal
+*/
+
+QmlAbstractAnimation::QmlAbstractAnimation(QObject *parent)
+: QObject(*(new QmlAbstractAnimationPrivate), parent)
+{
+}
+
+QmlAbstractAnimation::~QmlAbstractAnimation()
+{
+}
+
+QmlAbstractAnimation::QmlAbstractAnimation(QmlAbstractAnimationPrivate &dd, QObject *parent)
+: QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty bool Animation::running
+ This property holds whether the animation is currently running.
+
+ The \c running property can be set to declaratively control whether or not
+ an animation is running. The following example will animate a rectangle
+ whenever the \l MouseRegion is pressed.
+
+ \code
+ Rectangle {
+ width: 100; height: 100
+ x: NumberAnimation {
+ running: myMouse.pressed
+ from: 0; to: 100
+ }
+ MouseRegion { id: myMouse }
+ }
+ \endcode
+
+ Likewise, the \c running property can be read to determine if the animation
+ is running. In the following example the text element will indicate whether
+ or not the animation is running.
+
+ \code
+ NumberAnimation { id: myAnimation }
+ Text { text: myAnimation.running ? "Animation is running" : "Animation is not running" }
+ \endcode
+
+ Animations can also be started and stopped imperatively from JavaScript
+ using the \c start() and \c stop() methods.
+
+ By default, animations are not running.
+*/
+bool QmlAbstractAnimation::isRunning() const
+{
+ Q_D(const QmlAbstractAnimation);
+ return d->running;
+}
+
+void QmlAbstractAnimationPrivate::commence()
+{
+ Q_Q(QmlAbstractAnimation);
+
+ q->prepare(userProperty.value);
+ q->qtAnimation()->start();
+ if (q->qtAnimation()->state() != QAbstractAnimation::Running) {
+ running = false;
+ emit q->completed();
+ }
+}
+
+QmlMetaProperty QmlAbstractAnimationPrivate::createProperty(QObject *obj, const QString &str, QObject *infoObj)
+{
+ QmlMetaProperty prop = QmlMetaProperty::createProperty(obj, str, qmlContext(infoObj));
+ if (!prop.isValid()) {
+ qmlInfo(infoObj) << QmlAbstractAnimation::tr("Cannot animate non-existant property \"%1\"").arg(str);
+ return QmlMetaProperty();
+ } else if (!prop.isWritable()) {
+ qmlInfo(infoObj) << QmlAbstractAnimation::tr("Cannot animate read-only property \"%1\"").arg(str);
+ return QmlMetaProperty();
+ }
+ return prop;
+}
+
+void QmlAbstractAnimation::setRunning(bool r)
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->running == r)
+ return;
+
+ if (d->group) {
+ qWarning("QmlAbstractAnimation: setRunning() cannot be used on non-root animation nodes");
+ return;
+ }
+
+ d->running = r;
+ if (d->running) {
+ if (d->alwaysRunToEnd && d->repeat
+ && qtAnimation()->state() == QAbstractAnimation::Running) {
+ qtAnimation()->setLoopCount(-1);
+ }
+
+ if (!d->connectedTimeLine) {
+ QObject::connect(qtAnimation(), SIGNAL(finished()),
+ this, SLOT(timelineComplete()));
+ d->connectedTimeLine = true;
+ }
+ if (d->componentComplete)
+ d->commence();
+ else
+ d->startOnCompletion = true;
+ emit started();
+ } else {
+ if (d->alwaysRunToEnd) {
+ if (d->repeat)
+ qtAnimation()->setLoopCount(qtAnimation()->currentLoop()+1);
+ } else
+ qtAnimation()->stop();
+
+ emit completed();
+ }
+
+ emit runningChanged(d->running);
+}
+
+/*!
+ \qmlproperty bool Animation::paused
+ This property holds whether the animation is currently paused.
+
+ The \c paused property can be set to declaratively control whether or not
+ an animation is paused.
+
+ Animations can also be paused and resumed imperatively from JavaScript
+ using the \c pause() and \c resume() methods.
+
+ By default, animations are not paused.
+*/
+bool QmlAbstractAnimation::isPaused() const
+{
+ Q_D(const QmlAbstractAnimation);
+ return d->paused;
+}
+
+void QmlAbstractAnimation::setPaused(bool p)
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->paused == p)
+ return;
+
+ if (d->group) {
+ qWarning("QmlAbstractAnimation: setPaused() cannot be used on non-root animation nodes");
+ return;
+ }
+
+ d->paused = p;
+ if (d->paused)
+ qtAnimation()->pause();
+ else
+ qtAnimation()->resume();
+
+ emit pausedChanged(d->running);
+}
+
+void QmlAbstractAnimation::classBegin()
+{
+ Q_D(QmlAbstractAnimation);
+ d->componentComplete = false;
+}
+
+void QmlAbstractAnimation::componentComplete()
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->startOnCompletion)
+ d->commence();
+ d->componentComplete = true;
+}
+
+/*!
+ \qmlproperty bool Animation::alwaysRunToEnd
+ This property holds whether the animation should run to completion when it is stopped.
+
+ If this true the animation will complete its current iteration when it
+ is stopped - either by setting the \c running property to false, or by
+ calling the \c stop() method. The \c complete() method is not effected
+ by this value.
+
+ This behavior is most useful when the \c repeat property is set, as the
+ animation will finish playing normally but not restart.
+
+ By default, the alwaysRunToEnd property is not set.
+*/
+bool QmlAbstractAnimation::alwaysRunToEnd() const
+{
+ Q_D(const QmlAbstractAnimation);
+ return d->alwaysRunToEnd;
+}
+
+void QmlAbstractAnimation::setAlwaysRunToEnd(bool f)
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->alwaysRunToEnd == f)
+ return;
+
+ d->alwaysRunToEnd = f;
+ emit alwaysRunToEndChanged(f);
+}
+
+/*!
+ \qmlproperty bool Animation::repeat
+ This property holds whether the animation should repeat.
+
+ If set, the animation will continuously repeat until it is explicitly
+ stopped - either by setting the \c running property to false, or by calling
+ the \c stop() method.
+
+ In the following example, the rectangle will spin indefinately.
+
+ \code
+ Rectangle {
+ rotation: NumberAnimation { running: true; repeat: true; from: 0 to: 360 }
+ }
+ \endcode
+*/
+bool QmlAbstractAnimation::repeat() const
+{
+ Q_D(const QmlAbstractAnimation);
+ return d->repeat;
+}
+
+void QmlAbstractAnimation::setRepeat(bool r)
+{
+ Q_D(QmlAbstractAnimation);
+ if (r == d->repeat)
+ return;
+
+ d->repeat = r;
+ int lc = r ? -1 : 1;
+ qtAnimation()->setLoopCount(lc);
+ emit repeatChanged(r);
+}
+
+int QmlAbstractAnimation::currentTime()
+{
+ return qtAnimation()->currentLoopTime();
+}
+
+void QmlAbstractAnimation::setCurrentTime(int time)
+{
+ qtAnimation()->setCurrentTime(time);
+}
+
+QmlAnimationGroup *QmlAbstractAnimation::group() const
+{
+ Q_D(const QmlAbstractAnimation);
+ return d->group;
+}
+
+void QmlAbstractAnimation::setGroup(QmlAnimationGroup *g)
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->group == g)
+ return;
+ if (d->group)
+ static_cast<QmlAnimationGroupPrivate *>(d->group->d_func())->animations.removeAll(this);
+
+ d->group = g;
+
+ if (d->group && !static_cast<QmlAnimationGroupPrivate *>(d->group->d_func())->animations.contains(this))
+ static_cast<QmlAnimationGroupPrivate *>(d->group->d_func())->animations.append(this);
+
+ if (d->group)
+ ((QAnimationGroup*)d->group->qtAnimation())->addAnimation(qtAnimation());
+
+ //if (g) //if removed from a group, then the group should no longer be the parent
+ setParent(g);
+}
+
+/*!
+ \qmlmethod Animation::start()
+ \brief Starts the animation.
+
+ If the animation is already running, calling this method has no effect. The
+ \c running property will be true following a call to \c start().
+*/
+void QmlAbstractAnimation::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod Animation::pause()
+ \brief Pauses the animation.
+
+ If the animation is already paused, calling this method has no effect. The
+ \c paused property will be true following a call to \c pause().
+*/
+void QmlAbstractAnimation::pause()
+{
+ setPaused(true);
+}
+
+/*!
+ \qmlmethod Animation::resume()
+ \brief Resumes a paused animation.
+
+ If the animation is not paused, calling this method has no effect. The
+ \c paused property will be false following a call to \c resume().
+*/
+void QmlAbstractAnimation::resume()
+{
+ setPaused(false);
+}
+
+/*!
+ \qmlmethod Animation::stop()
+ \brief Stops the animation.
+
+ If the animation is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c stop().
+
+ Normally \c stop() stops the animation immediately, and the animation has
+ no further influence on property values. In this example animation
+ \code
+ Rectangle {
+ x: NumberAnimation { from: 0; to: 100; duration: 500 }
+ }
+ \endcode
+ was stopped at time 250ms, the \c x property will have a value of 50.
+
+ However, if the \c alwaysRunToEnd property is set, the animation will
+ continue running until it completes and then stop. The \c running property
+ will still become false immediately.
+*/
+void QmlAbstractAnimation::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod Animation::restart()
+ \brief Restarts the animation.
+
+ This is a convenience method, and is equivalent to calling \c stop() and
+ then \c start().
+*/
+void QmlAbstractAnimation::restart()
+{
+ stop();
+ start();
+}
+
+/*!
+ \qmlmethod Animation::complete()
+ \brief Stops the animation, jumping to the final property values.
+
+ If the animation is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c complete().
+
+ Unlike \c stop(), \c complete() immediately fast-forwards the animation to
+ its end. In the following example,
+ \code
+ Rectangle {
+ x: NumberAnimation { from: 0; to: 100; duration: 500 }
+ }
+ \endcode
+ calling \c stop() at time 250ms will result in the \c x property having
+ a value of 50, while calling \c complete() will set the \c x property to
+ 100, exactly as though the animation had played the whole way through.
+*/
+void QmlAbstractAnimation::complete()
+{
+ if (isRunning()) {
+ qtAnimation()->setCurrentTime(qtAnimation()->duration());
+ }
+}
+
+void QmlAbstractAnimation::setTarget(const QmlMetaProperty &p)
+{
+ Q_D(QmlAbstractAnimation);
+ if (d->userProperty.isNull)
+ d->userProperty = p;
+}
+
+//prepare is called before an animation begins
+//(when an animation is used as a simple animation, and not as part of a transition)
+void QmlAbstractAnimation::prepare(QmlMetaProperty &)
+{
+}
+
+void QmlAbstractAnimation::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(actions);
+ Q_UNUSED(modified);
+ Q_UNUSED(direction);
+}
+
+void QmlAbstractAnimation::timelineComplete()
+{
+ Q_D(QmlAbstractAnimation);
+ setRunning(false);
+ if (d->alwaysRunToEnd && d->repeat) {
+ qtAnimation()->setLoopCount(-1);
+ }
+}
+
+/*!
+ \qmlclass PauseAnimation QmlPauseAnimation
+ \inherits Animation
+ \brief The PauseAnimation element provides a pause for an animation.
+
+ When used in a SequentialAnimation, PauseAnimation is a step when
+ nothing happens, for a specified duration.
+
+ A 500ms animation sequence, with a 100ms pause between two animations:
+ \code
+ SequentialAnimation {
+ NumberAnimation { ... duration: 200 }
+ PauseAnimation { duration: 100 }
+ NumberAnimation { ... duration: 200 }
+ }
+ \endcode
+*/
+/*!
+ \internal
+ \class QmlPauseAnimation
+*/
+
+QML_DEFINE_TYPE(Qt,4,6,PauseAnimation,QmlPauseAnimation)
+QmlPauseAnimation::QmlPauseAnimation(QObject *parent)
+: QmlAbstractAnimation(*(new QmlPauseAnimationPrivate), parent)
+{
+ Q_D(QmlPauseAnimation);
+ d->init();
+}
+
+QmlPauseAnimation::~QmlPauseAnimation()
+{
+}
+
+void QmlPauseAnimationPrivate::init()
+{
+ Q_Q(QmlPauseAnimation);
+ pa = new QPauseAnimation;
+ QmlGraphics_setParent_noEvent(pa, q);
+}
+
+/*!
+ \qmlproperty int PauseAnimation::duration
+ This property holds the duration of the pause in milliseconds
+
+ The default value is 250.
+*/
+int QmlPauseAnimation::duration() const
+{
+ Q_D(const QmlPauseAnimation);
+ return d->pa->duration();
+}
+
+void QmlPauseAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QmlPauseAnimation);
+ if (d->pa->duration() == duration)
+ return;
+ d->pa->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+QAbstractAnimation *QmlPauseAnimation::qtAnimation()
+{
+ Q_D(QmlPauseAnimation);
+ return d->pa;
+}
+
+/*!
+ \qmlclass ColorAnimation QmlColorAnimation
+ \inherits PropertyAnimation
+ \brief The ColorAnimation element allows you to animate color changes.
+
+ \code
+ ColorAnimation { from: "white"; to: "#c0c0c0"; duration: 100 }
+ \endcode
+
+ When used in a transition, ColorAnimation will by default animate
+ all properties of type color that are changing. If a property or properties
+ are explicitly set for the animation, then those will be used instead.
+*/
+/*!
+ \internal
+ \class QmlColorAnimation
+*/
+
+QmlColorAnimation::QmlColorAnimation(QObject *parent)
+: QmlPropertyAnimation(parent)
+{
+ Q_D(QmlPropertyAnimation);
+ d->interpolatorType = QMetaType::QColor;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QmlColorAnimation::~QmlColorAnimation()
+{
+}
+
+/*!
+ \qmlproperty color ColorAnimation::from
+ This property holds the starting color.
+*/
+QColor QmlColorAnimation::from() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->from.value<QColor>();
+}
+
+void QmlColorAnimation::setFrom(const QColor &f)
+{
+ QmlPropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty color ColorAnimation::from
+ This property holds the ending color.
+*/
+QColor QmlColorAnimation::to() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->to.value<QColor>();
+}
+
+void QmlColorAnimation::setTo(const QColor &t)
+{
+ QmlPropertyAnimation::setTo(t);
+}
+
+QML_DEFINE_TYPE(Qt,4,6,ColorAnimation,QmlColorAnimation)
+
+/*!
+ \qmlclass ScriptAction QmlScriptAction
+ \inherits Animation
+ \brief The ScriptAction element allows scripts to be run during an animation.
+
+*/
+/*!
+ \internal
+ \class QmlScriptAction
+*/
+QmlScriptAction::QmlScriptAction(QObject *parent)
+ :QmlAbstractAnimation(*(new QmlScriptActionPrivate), parent)
+{
+ Q_D(QmlScriptAction);
+ d->init();
+}
+
+QmlScriptAction::~QmlScriptAction()
+{
+}
+
+void QmlScriptActionPrivate::init()
+{
+ Q_Q(QmlScriptAction);
+ rsa = new QActionAnimation(&proxy);
+ QmlGraphics_setParent_noEvent(rsa, q);
+}
+
+/*!
+ \qmlproperty script ScriptAction::script
+ This property holds the script to run.
+*/
+QmlScriptString QmlScriptAction::script() const
+{
+ Q_D(const QmlScriptAction);
+ return d->script;
+}
+
+void QmlScriptAction::setScript(const QmlScriptString &script)
+{
+ Q_D(QmlScriptAction);
+ d->script = script;
+}
+
+/*!
+ \qmlproperty QString ScriptAction::stateChangeScriptName
+ This property holds the the name of the StateChangeScript to run.
+
+ This property is only valid when ScriptAction is used as part of a transition.
+ If both script and stateChangeScriptName are set, stateChangeScriptName will be used.
+*/
+QString QmlScriptAction::stateChangeScriptName() const
+{
+ Q_D(const QmlScriptAction);
+ return d->name;
+}
+
+void QmlScriptAction::setStateChangeScriptName(const QString &name)
+{
+ Q_D(QmlScriptAction);
+ d->name = name;
+}
+
+void QmlScriptActionPrivate::execute()
+{
+ QmlScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
+
+ const QString &str = scriptStr.script();
+ if (!str.isEmpty()) {
+ QmlExpression expr(scriptStr.context(), str, scriptStr.scopeObject());
+ expr.setTrackChange(false);
+ expr.value();
+ }
+}
+
+void QmlScriptAction::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlScriptAction);
+ Q_UNUSED(modified);
+ Q_UNUSED(direction);
+
+ d->hasRunScriptScript = false;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+
+ if (action.event && action.event->typeName() == QLatin1String("StateChangeScript")
+ && static_cast<QmlStateChangeScript*>(action.event)->name() == d->name) {
+ //### how should we handle reverse direction?
+ d->runScriptScript = static_cast<QmlStateChangeScript*>(action.event)->script();
+ d->hasRunScriptScript = true;
+ action.actionDone = true;
+ break; //assumes names are unique
+ }
+ }
+}
+
+QAbstractAnimation *QmlScriptAction::qtAnimation()
+{
+ Q_D(QmlScriptAction);
+ return d->rsa;
+}
+
+QML_DEFINE_TYPE(Qt,4,6,ScriptAction,QmlScriptAction)
+
+/*!
+ \qmlclass PropertyAction QmlPropertyAction
+ \inherits Animation
+ \brief The PropertyAction element allows immediate property changes during animation.
+
+ Explicitly set \c theimage.smooth=true during a transition:
+ \code
+ PropertyAction { target: theimage; property: "smooth"; value: true }
+ \endcode
+
+ Set \c thewebview.url to the value set for the destination state:
+ \code
+ PropertyAction { matchTargets: thewebview; matchProperties: "url" }
+ \endcode
+
+ The PropertyAction is immediate -
+ the target property is not animated to the selected value in any way.
+*/
+/*!
+ \internal
+ \class QmlPropertyAction
+*/
+QmlPropertyAction::QmlPropertyAction(QObject *parent)
+: QmlAbstractAnimation(*(new QmlPropertyActionPrivate), parent)
+{
+ Q_D(QmlPropertyAction);
+ d->init();
+}
+
+QmlPropertyAction::~QmlPropertyAction()
+{
+}
+
+void QmlPropertyActionPrivate::init()
+{
+ Q_Q(QmlPropertyAction);
+ spa = new QActionAnimation;
+ QmlGraphics_setParent_noEvent(spa, q);
+}
+
+/*!
+ \qmlproperty Object PropertyAction::target
+ This property holds an explicit target object to animate.
+
+ The exact effect of the \c target property depends on how the animation
+ is being used. Refer to the \l animation documentation for details.
+*/
+
+QObject *QmlPropertyAction::target() const
+{
+ Q_D(const QmlPropertyAction);
+ return d->target;
+}
+
+void QmlPropertyAction::setTarget(QObject *o)
+{
+ Q_D(QmlPropertyAction);
+ if (d->target == o)
+ return;
+
+ d->target = o;
+ if (d->target && !d->propertyName.isEmpty()) {
+ d->userProperty = d->createProperty(d->target, d->propertyName, this);
+ } else {
+ d->userProperty.invalidate();
+ }
+
+ emit targetChanged(d->target, d->propertyName);
+}
+
+/*!
+ \qmlproperty string PropertyAction::property
+ This property holds an explicit property to animated.
+
+ The exact effect of the \c property property depends on how the animation
+ is being used. Refer to the \l animation documentation for details.
+*/
+
+QString QmlPropertyAction::property() const
+{
+ Q_D(const QmlPropertyAction);
+ return d->propertyName;
+}
+
+void QmlPropertyAction::setProperty(const QString &n)
+{
+ Q_D(QmlPropertyAction);
+ if (d->propertyName == n)
+ return;
+
+ d->propertyName = n;
+ if (d->target && !d->propertyName.isEmpty()) {
+ d->userProperty = d->createProperty(d->target, d->propertyName, this);
+ } else {
+ d->userProperty.invalidate();
+ }
+
+ emit targetChanged(d->target, d->propertyName);
+}
+
+/*!
+ \qmlproperty string PropertyAction::matchProperties
+ This property holds a comma-separated list of property names this action
+ will match against. These names are used in conjunction with matchTargets
+ to create a list of properties that the action will set, assuming those
+ properties have changed.
+
+ This property is typically used for an action appearing as part of a Transition.
+
+ By default, no property names will be matched.
+
+ \sa matchTargets PropertyAnimation::matchProperties
+*/
+QString QmlPropertyAction::properties() const
+{
+ Q_D(const QmlPropertyAction);
+ return d->properties;
+}
+
+void QmlPropertyAction::setProperties(const QString &p)
+{
+ Q_D(QmlPropertyAction);
+ if (d->properties == p)
+ return;
+ d->properties = p;
+ emit propertiesChanged(p);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAction::matchTargets
+ This property holds a list of objects this action will match against.
+ These objects are used in conjunction with matchProperties to create a list of properties
+ that the action will set, assuming those properties have changed.
+
+ This property is typically used for an action appearing as part of a Transition.
+
+ By default, all changing targets will be matched.
+
+ \sa exclude matchProperties PropertyAnimation::matchTargets
+*/
+QmlListProperty<QObject> QmlPropertyAction::targets()
+{
+ Q_D(QmlPropertyAction);
+ return QmlListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAction::exclude
+ This property holds the objects not to be affected by this animation.
+ \sa matchTargets
+*/
+QmlListProperty<QObject> QmlPropertyAction::exclude()
+{
+ Q_D(QmlPropertyAction);
+ return QmlListProperty<QObject>(this, d->exclude);
+}
+
+/*!
+ \qmlproperty any PropertyAction::value
+ This property holds the value to be set on the property.
+ If not set, then the value defined for the end state of the transition.
+*/
+QVariant QmlPropertyAction::value() const
+{
+ Q_D(const QmlPropertyAction);
+ return d->value;
+}
+
+void QmlPropertyAction::setValue(const QVariant &v)
+{
+ Q_D(QmlPropertyAction);
+ if (d->value.isNull || d->value != v) {
+ d->value = v;
+ emit valueChanged(v);
+ }
+}
+
+void QmlPropertyActionPrivate::doAction()
+{
+ property.write(value, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+}
+
+QAbstractAnimation *QmlPropertyAction::qtAnimation()
+{
+ Q_D(QmlPropertyAction);
+ return d->spa;
+}
+
+void QmlPropertyAction::prepare(QmlMetaProperty &p)
+{
+ Q_D(QmlPropertyAction);
+
+ if (d->userProperty.isNull)
+ d->property = p;
+ else
+ d->property = d->userProperty;
+
+ d->spa->setAnimAction(&d->proxy, QAbstractAnimation::KeepWhenStopped);
+}
+
+void QmlPropertyAction::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlPropertyAction);
+ Q_UNUSED(direction);
+
+ struct QmlSetPropertyAnimationAction : public QAbstractAnimationAction
+ {
+ QmlStateActions actions;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QmlAction &action = actions.at(ii);
+ action.property.write(action.toValue, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ }
+ }
+ };
+
+ QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
+ for (int ii = 0; ii < props.count(); ++ii)
+ props[ii] = props.at(ii).trimmed();
+
+ bool hasSelectors = !props.isEmpty() || !d->targets.isEmpty() || !d->exclude.isEmpty();
+ bool hasTarget = !d->propertyName.isEmpty() || d->target;
+
+ if (hasSelectors && hasTarget) {
+ qmlInfo(this) << tr("matchTargets/matchProperties/exclude and target/property are mutually exclusive.");
+ return;
+ }
+
+ QmlSetPropertyAnimationAction *data = new QmlSetPropertyAnimationAction;
+
+ bool hasExplicit = false;
+ if (hasTarget && d->value.isValid()) {
+ QmlAction myAction;
+ myAction.property = d->createProperty(target(), d->propertyName, this);
+ if (myAction.property.isValid()) {
+ myAction.toValue = d->value;
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+ if (action.property.object() == myAction.property.object() &&
+ myAction.property.name() == action.property.name()) {
+ modified << action.property;
+ break; //### any chance there could be multiples?
+ }
+ }
+ }
+ }
+
+ if (!hasExplicit)
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+
+ QObject *obj = action.property.object();
+ QString propertyName = action.property.name();
+ QObject *sObj = action.specifiedObject;
+ QString sPropertyName = action.specifiedProperty;
+ bool same = (obj == sObj);
+
+ if ((d->targets.isEmpty() || d->targets.contains(obj) || (!same && d->targets.contains(sObj))) &&
+ (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) &&
+ (props.contains(propertyName) || (!same && props.contains(sPropertyName)))) {
+ QmlAction myAction = action;
+
+ if (d->value.isValid())
+ myAction.toValue = d->value;
+
+ modified << action.property;
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ } else if (d->userProperty.isValid() &&
+ !hasSelectors && !hasTarget) {
+ if ((d->userProperty.value.object() == obj || (!same && d->userProperty.value.object() == sObj)) &&
+ (d->userProperty.value.name() == propertyName || (!same && d->userProperty.value.name() == sPropertyName))) {
+ //### same as above. merge
+ QmlAction myAction = action;
+
+ if (d->value.isValid())
+ myAction.toValue = d->value;
+
+ modified << action.property;
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ }
+ }
+ }
+
+ if (data->actions.count()) {
+ d->spa->setAnimAction(data, QAbstractAnimation::DeleteWhenStopped);
+ } else {
+ delete data;
+ }
+}
+
+QML_DEFINE_TYPE(Qt,4,6,PropertyAction,QmlPropertyAction)
+
+/*!
+ \qmlclass ParentAction QmlParentAction
+ \inherits Animation
+ \brief The ParentAction element allows parent changes during animation.
+
+ ParentAction provides a way to specify at what point in a Transition a ParentChange should
+ occur.
+ \qml
+ State {
+ ParentChange {
+ target: myItem
+ parent: newParent
+ }
+ }
+ Transition {
+ SequentialAnimation {
+ PropertyAnimation { ... }
+ ParentAction {} //reparent myItem now
+ PropertyAnimation { ... }
+ }
+ }
+ \endqml
+
+ It also provides a way to explicitly reparent an item during an animation.
+ \qml
+ SequentialAnimation {
+ ParentAction { target: myItem; parent: newParent }
+ PropertyAnimation {}
+ }
+ \endqml
+
+ The ParentAction is immediate - it is not animated in any way.
+*/
+
+QmlParentAction::QmlParentAction(QObject *parent)
+: QmlAbstractAnimation(*(new QmlParentActionPrivate), parent)
+{
+ Q_D(QmlParentAction);
+ d->init();
+}
+
+QmlParentAction::~QmlParentAction()
+{
+}
+
+void QmlParentActionPrivate::init()
+{
+ Q_Q(QmlParentAction);
+ cpa = new QActionAnimation;
+ QmlGraphics_setParent_noEvent(cpa, q);
+}
+
+/*!
+ \qmlproperty Item ParentAction::target
+
+ This property holds an explicit target item to reparent.
+ */
+QmlGraphicsItem *QmlParentAction::object() const
+{
+ Q_D(const QmlParentAction);
+ return d->pcTarget;
+}
+
+void QmlParentAction::setObject(QmlGraphicsItem *target)
+{
+ Q_D(QmlParentAction);
+ d->pcTarget = target;
+}
+
+/*!
+ \qmlproperty Item ParentAction::matchTarget
+ This property holds the item this action will match against -- the item
+ that the action will reparent, assuming its parent has changed.
+
+ In the following example, \c myItem will be reparented by the ParentAction, while
+ \c myOtherItem will not.
+ \qml
+ State {
+ ParentChange {
+ target: myItem
+ parent: newParent
+ }
+ ParentChange {
+ target: myOtherItem
+ parent: otherNewParent
+ }
+ }
+ Transition {
+ SequentialAnimation {
+ PropertyAnimation { ... }
+ ParentAction { matchTargets: myItem }
+ PropertyAnimation { ... }
+ }
+ }
+ \endqml
+
+ This property is typically used for an action appearing as part of a Transition.
+ */
+QmlGraphicsItem *QmlParentAction::matchTarget() const
+{
+ Q_D(const QmlParentAction);
+ return d->pcTarget;
+}
+
+void QmlParentAction::setMatchTarget(QmlGraphicsItem *target)
+{
+ Q_D(QmlParentAction);
+ d->pcMatchTarget = target;
+}
+
+/*!
+ \qmlproperty Item ParentAction::parent
+
+ The item to reparent to (i.e. the new parent).
+ */
+QmlGraphicsItem *QmlParentAction::parent() const
+{
+ Q_D(const QmlParentAction);
+ return d->pcParent;
+}
+
+void QmlParentAction::setParent(QmlGraphicsItem *parent)
+{
+ Q_D(QmlParentAction);
+ d->pcParent = parent;
+}
+
+void QmlParentActionPrivate::doAction()
+{
+ QmlParentChange pc;
+ pc.setObject(pcTarget);
+ pc.setParent(pcParent);
+ pc.execute();
+}
+
+QAbstractAnimation *QmlParentAction::qtAnimation()
+{
+ Q_D(QmlParentAction);
+ return d->cpa;
+}
+
+void QmlParentAction::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlParentAction);
+ Q_UNUSED(modified);
+ Q_UNUSED(direction);
+
+ struct QmlParentActionData : public QAbstractAnimationAction
+ {
+ QmlParentActionData(): pc(0) {}
+ ~QmlParentActionData() { delete pc; }
+
+ QmlStateActions actions;
+ bool reverse;
+ QmlParentChange *pc;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QmlAction &action = actions.at(ii);
+ if (reverse)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+ }
+ };
+
+ QmlParentActionData *data = new QmlParentActionData;
+
+ if (d->pcTarget && d->pcMatchTarget) {
+ qmlInfo(this) << tr("matchTarget and target are mutually exclusive.");
+ return;
+ }
+
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+
+ if (action.event && action.event->typeName() == QLatin1String("ParentChange")
+ && !d->pcTarget
+ && (!d->pcMatchTarget || static_cast<QmlParentChange*>(action.event)->object() == d->pcMatchTarget)) {
+ QmlAction myAction = action;
+ data->reverse = action.reverseEvent;
+ //### this logic differs from PropertyAnimation
+ // (probably a result of modified vs. done)
+ if (d->pcParent) {
+ //### should we disallow this case?
+ QmlParentChange *pc = new QmlParentChange;
+ pc->setObject(d->pcTarget);
+ pc->setParent(static_cast<QmlParentChange*>(action.event)->parent());
+ myAction.event = pc;
+ data->pc = pc;
+ data->actions << myAction;
+ break; //only match one
+ } else {
+ action.actionDone = true;
+ data->actions << myAction;
+ }
+ }
+ }
+
+ if (d->pcTarget && d->pcParent) {
+ data->reverse = false;
+ QmlAction myAction;
+ QmlParentChange *pc = new QmlParentChange;
+ pc->setObject(d->pcTarget);
+ pc->setParent(d->pcParent);
+ myAction.event = pc;
+ data->pc = pc;
+ data->actions << myAction;
+ }
+
+ if (data->actions.count()) {
+ d->cpa->setAnimAction(data, QAbstractAnimation::DeleteWhenStopped);
+ } else {
+ delete data;
+ }
+}
+
+QML_DEFINE_TYPE(Qt,4,6,ParentAction,QmlParentAction)
+
+/*!
+ \qmlclass NumberAnimation QmlNumberAnimation
+ \inherits PropertyAnimation
+ \brief The NumberAnimation element allows you to animate changes in properties of type qreal.
+
+ Animate a set of properties over 200ms, from their values in the start state to
+ their values in the end state of the transition:
+ \code
+ NumberAnimation { matchProperties: "x,y,scale"; duration: 200 }
+ \endcode
+*/
+
+/*!
+ \internal
+ \class QmlNumberAnimation
+*/
+
+QmlNumberAnimation::QmlNumberAnimation(QObject *parent)
+: QmlPropertyAnimation(parent)
+{
+ Q_D(QmlPropertyAnimation);
+ d->interpolatorType = QMetaType::QReal;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+}
+
+QmlNumberAnimation::~QmlNumberAnimation()
+{
+}
+
+/*!
+ \qmlproperty real NumberAnimation::from
+ This property holds the starting value.
+ If not set, then the value defined in the start state of the transition.
+*/
+qreal QmlNumberAnimation::from() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->from.toReal();
+}
+
+void QmlNumberAnimation::setFrom(qreal f)
+{
+ QmlPropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real NumberAnimation::to
+ This property holds the ending value.
+ If not set, then the value defined in the end state of the transition.
+*/
+qreal QmlNumberAnimation::to() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->to.toReal();
+}
+
+void QmlNumberAnimation::setTo(qreal t)
+{
+ QmlPropertyAnimation::setTo(t);
+}
+
+QML_DEFINE_TYPE(Qt,4,6,NumberAnimation,QmlNumberAnimation)
+
+/*!
+ \qmlclass Vector3dAnimation QmlVector3dAnimation
+ \inherits PropertyAnimation
+ \brief The Vector3dAnimation element allows you to animate changes in properties of type QVector3d.
+*/
+
+/*!
+ \internal
+ \class QmlVector3dAnimation
+*/
+
+QmlVector3dAnimation::QmlVector3dAnimation(QObject *parent)
+: QmlPropertyAnimation(parent)
+{
+ Q_D(QmlPropertyAnimation);
+ d->interpolatorType = QMetaType::QVector3D;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QmlVector3dAnimation::~QmlVector3dAnimation()
+{
+}
+
+/*!
+ \qmlproperty real Vector3dAnimation::from
+ This property holds the starting value.
+ If not set, then the value defined in the start state of the transition.
+*/
+QVector3D QmlVector3dAnimation::from() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->from.value<QVector3D>();
+}
+
+void QmlVector3dAnimation::setFrom(QVector3D f)
+{
+ QmlPropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real Vector3dAnimation::to
+ This property holds the ending value.
+ If not set, then the value defined in the end state of the transition.
+*/
+QVector3D QmlVector3dAnimation::to() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->to.value<QVector3D>();
+}
+
+void QmlVector3dAnimation::setTo(QVector3D t)
+{
+ QmlPropertyAnimation::setTo(t);
+}
+
+QML_DEFINE_TYPE(Qt,4,6,Vector3dAnimation,QmlVector3dAnimation)
+
+QmlAnimationGroup::QmlAnimationGroup(QObject *parent)
+: QmlAbstractAnimation(*(new QmlAnimationGroupPrivate), parent)
+{
+}
+
+QmlAnimationGroup::~QmlAnimationGroup()
+{
+}
+
+QmlList<QmlAbstractAnimation *> *QmlAnimationGroup::animations()
+{
+ Q_D(QmlAnimationGroup);
+ return &d->animations;
+}
+
+/*!
+ \qmlclass SequentialAnimation QmlSequentialAnimation
+ \inherits Animation
+ \brief The SequentialAnimation element allows you to run animations sequentially.
+
+ Animations controlled in SequentialAnimation will be run one after the other.
+
+ The following example chains two numeric animations together. The \c MyItem
+ object will animate from its current x position to 100, and then back to 0.
+
+ \code
+ SequentialAnimation {
+ NumberAnimation { target: MyItem; property: "x"; to: 100 }
+ NumberAnimation { target: MyItem; property: "x"; to: 0 }
+ }
+ \endcode
+
+ \sa ParallelAnimation
+*/
+
+QmlSequentialAnimation::QmlSequentialAnimation(QObject *parent) :
+ QmlAnimationGroup(parent)
+{
+ Q_D(QmlAnimationGroup);
+ d->ag = new QSequentialAnimationGroup(this);
+}
+
+QmlSequentialAnimation::~QmlSequentialAnimation()
+{
+}
+
+void QmlSequentialAnimation::prepare(QmlMetaProperty &p)
+{
+ Q_D(QmlAnimationGroup);
+ if (d->userProperty.isNull)
+ d->property = p;
+ else
+ d->property = d->userProperty;
+
+ for (int i = 0; i < d->animations.size(); ++i)
+ d->animations.at(i)->prepare(d->property);
+}
+
+QAbstractAnimation *QmlSequentialAnimation::qtAnimation()
+{
+ Q_D(QmlAnimationGroup);
+ return d->ag;
+}
+
+void QmlSequentialAnimation::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlAnimationGroup);
+
+ int inc = 1;
+ int from = 0;
+ if (direction == Backward) {
+ inc = -1;
+ from = d->animations.count() - 1;
+ }
+
+ //needed for Behavior
+ if (d->userProperty.isValid()) {
+ for (int i = 0; i < d->animations.count(); ++i)
+ d->animations.at(i)->setTarget(d->userProperty);
+ }
+
+ for (int ii = from; ii < d->animations.count() && ii >= 0; ii += inc) {
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+}
+
+QML_DEFINE_TYPE(Qt,4,6,SequentialAnimation,QmlSequentialAnimation)
+
+/*!
+ \qmlclass ParallelAnimation QmlParallelAnimation
+ \inherits Animation
+ \brief The ParallelAnimation element allows you to run animations in parallel.
+
+ Animations contained in ParallelAnimation will be run at the same time.
+
+ The following animation demonstrates animating the \c MyItem item
+ to (100,100) by animating the x and y properties in parallel.
+
+ \code
+ ParallelAnimation {
+ NumberAnimation { target: MyItem; property: "x"; to: 100 }
+ NumberAnimation { target: MyItem; property: "y"; to: 100 }
+ }
+ \endcode
+
+ \sa SequentialAnimation
+*/
+/*!
+ \internal
+ \class QmlParallelAnimation
+*/
+
+QmlParallelAnimation::QmlParallelAnimation(QObject *parent) :
+ QmlAnimationGroup(parent)
+{
+ Q_D(QmlAnimationGroup);
+ d->ag = new QParallelAnimationGroup(this);
+}
+
+QmlParallelAnimation::~QmlParallelAnimation()
+{
+}
+
+void QmlParallelAnimation::prepare(QmlMetaProperty &p)
+{
+ Q_D(QmlAnimationGroup);
+ if (d->userProperty.isNull)
+ d->property = p;
+ else
+ d->property = d->userProperty;
+
+ for (int i = 0; i < d->animations.size(); ++i)
+ d->animations.at(i)->prepare(d->property);
+}
+
+QAbstractAnimation *QmlParallelAnimation::qtAnimation()
+{
+ Q_D(QmlAnimationGroup);
+ return d->ag;
+}
+
+void QmlParallelAnimation::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlAnimationGroup);
+
+ //needed for Behavior
+ if (d->userProperty.isValid()) {
+ for (int i = 0; i < d->animations.count(); ++i)
+ d->animations.at(i)->setTarget(d->userProperty);
+ }
+
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+}
+
+QML_DEFINE_TYPE(Qt,4,6,ParallelAnimation,QmlParallelAnimation)
+
+//convert a variant from string type to another animatable type
+void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type)
+{
+ if (variant.userType() != QVariant::String) {
+ variant.convert((QVariant::Type)type);
+ return;
+ }
+
+ switch (type) {
+ case QVariant::Rect: {
+ variant.setValue(QmlStringConverters::rectFFromString(variant.toString()).toRect());
+ break;
+ }
+ case QVariant::RectF: {
+ variant.setValue(QmlStringConverters::rectFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Point: {
+ variant.setValue(QmlStringConverters::pointFFromString(variant.toString()).toPoint());
+ break;
+ }
+ case QVariant::PointF: {
+ variant.setValue(QmlStringConverters::pointFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Size: {
+ variant.setValue(QmlStringConverters::sizeFFromString(variant.toString()).toSize());
+ break;
+ }
+ case QVariant::SizeF: {
+ variant.setValue(QmlStringConverters::sizeFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Color: {
+ variant.setValue(QmlStringConverters::colorFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Vector3D: {
+ variant.setValue(QmlStringConverters::vector3DFromString(variant.toString()));
+ break;
+ }
+ default:
+ if ((uint)type >= QVariant::UserType) {
+ QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type);
+ if (converter)
+ variant = converter(variant.toString());
+ } else
+ variant.convert((QVariant::Type)type);
+ break;
+ }
+}
+
+/*!
+ \qmlclass PropertyAnimation QmlPropertyAnimation
+ \inherits Animation
+ \brief The PropertyAnimation element allows you to animate property changes.
+
+ Animate theObject's size property over 200ms, from its current size to 20-by-20:
+ \code
+ PropertyAnimation { target: theObject; property: "size"; to: "20x20"; duration: 200 }
+ \endcode
+
+ For an introduction to animation in QML, see \l{QML Animation}.
+*/
+
+QmlPropertyAnimation::QmlPropertyAnimation(QObject *parent)
+: QmlAbstractAnimation(*(new QmlPropertyAnimationPrivate), parent)
+{
+ Q_D(QmlPropertyAnimation);
+ d->init();
+}
+
+QmlPropertyAnimation::~QmlPropertyAnimation()
+{
+}
+
+void QmlPropertyAnimationPrivate::init()
+{
+ Q_Q(QmlPropertyAnimation);
+ va = new QmlTimeLineValueAnimator;
+ QmlGraphics_setParent_noEvent(va, q);
+}
+
+/*!
+ \qmlproperty int PropertyAnimation::duration
+ This property holds the duration of the transition, in milliseconds.
+
+ The default value is 250.
+*/
+int QmlPropertyAnimation::duration() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->va->duration();
+}
+
+void QmlPropertyAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QmlPropertyAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+/*!
+ \qmlproperty real PropertyAnimation::from
+ This property holds the starting value.
+ If not set, then the value defined in the start state of the transition.
+*/
+QVariant QmlPropertyAnimation::from() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->from;
+}
+
+void QmlPropertyAnimation::setFrom(const QVariant &f)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->fromIsDefined && f == d->from)
+ return;
+ d->from = f;
+ d->fromIsDefined = f.isValid();
+ emit fromChanged(f);
+}
+
+/*!
+ \qmlproperty real PropertyAnimation::to
+ This property holds the ending value.
+ If not set, then the value defined in the end state of the transition.
+*/
+QVariant QmlPropertyAnimation::to() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->to;
+}
+
+void QmlPropertyAnimation::setTo(const QVariant &t)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->toIsDefined && t == d->to)
+ return;
+ d->to = t;
+ d->toIsDefined = t.isValid();
+ emit toChanged(t);
+}
+
+/*!
+ \qmlproperty string PropertyAnimation::easing
+ \brief the easing curve used for the transition.
+
+ Available values are:
+
+ \table
+ \row
+ \o \c easeLinear
+ \o Easing curve for a linear (t) function: velocity is constant.
+ \o \inlineimage qeasingcurve-linear.png
+ \row
+ \o \c easeInQuad
+ \o Easing curve for a quadratic (t^2) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquad.png
+ \row
+ \o \c easeOutQuad
+ \o Easing curve for a quadratic (t^2) function: decelerating to zero velocity.
+ \o \inlineimage qeasingcurve-outquad.png
+ \row
+ \o \c easeInOutQuad
+ \o Easing curve for a quadratic (t^2) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquad.png
+ \row
+ \o \c easeOutInQuad
+ \o Easing curve for a quadratic (t^2) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquad.png
+ \row
+ \o \c easeInCubic
+ \o Easing curve for a cubic (t^3) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incubic.png
+ \row
+ \o \c easeOutCubic
+ \o Easing curve for a cubic (t^3) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcubic.png
+ \row
+ \o \c easeInOutCubic
+ \o Easing curve for a cubic (t^3) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcubic.png
+ \row
+ \o \c easeOutInCubic
+ \o Easing curve for a cubic (t^3) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincubic.png
+ \row
+ \o \c easeInQuart
+ \o Easing curve for a quartic (t^4) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquart.png
+ \row
+ \o \c easeOutQuart
+ \o Easing curve for a cubic (t^4) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquart.png
+ \row
+ \o \c easeInOutQuart
+ \o Easing curve for a cubic (t^4) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquart.png
+ \row
+ \o \c easeOutInQuart
+ \o Easing curve for a cubic (t^4) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquart.png
+ \row
+ \o \c easeInQuint
+ \o Easing curve for a quintic (t^5) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquint.png
+ \row
+ \o \c easeOutQuint
+ \o Easing curve for a cubic (t^5) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquint.png
+ \row
+ \o \c easeInOutQuint
+ \o Easing curve for a cubic (t^5) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquint.png
+ \row
+ \o \c easeOutInQuint
+ \o Easing curve for a cubic (t^5) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquint.png
+ \row
+ \o \c easeInSine
+ \o Easing curve for a sinusoidal (sin(t)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-insine.png
+ \row
+ \o \c easeOutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outsine.png
+ \row
+ \o \c easeInOutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutsine.png
+ \row
+ \o \c easeOutInSine
+ \o Easing curve for a sinusoidal (sin(t)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinsine.png
+ \row
+ \o \c easeInExpo
+ \o Easing curve for an exponential (2^t) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inexpo.png
+ \row
+ \o \c easeOutExpo
+ \o Easing curve for an exponential (2^t) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outexpo.png
+ \row
+ \o \c easeInOutExpo
+ \o Easing curve for an exponential (2^t) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutexpo.png
+ \row
+ \o \c easeOutInExpo
+ \o Easing curve for an exponential (2^t) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinexpo.png
+ \row
+ \o \c easeInCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incirc.png
+ \row
+ \o \c easeOutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcirc.png
+ \row
+ \o \c easeInOutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcirc.png
+ \row
+ \o \c easeOutInCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincirc.png
+ \row
+ \o \c easeInElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: accelerating from zero velocity.
+ \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
+ \o \inlineimage qeasingcurve-inelastic.png
+ \row
+ \o \c easeOutElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: decelerating from zero velocity.
+ \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
+ \o \inlineimage qeasingcurve-outelastic.png
+ \row
+ \o \c easeInOutElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutelastic.png
+ \row
+ \o \c easeOutInElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinelastic.png
+ \row
+ \o \c easeInBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inback.png
+ \row
+ \o \c easeOutBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing out: decelerating to zero velocity.
+ \o \inlineimage qeasingcurve-outback.png
+ \row
+ \o \c easeInOutBack
+ \o Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutback.png
+ \row
+ \o \c easeOutInBack
+ \o Easing curve for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinback.png
+ \row
+ \o \c easeInBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inbounce.png
+ \row
+ \o \c easeOutBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outbounce.png
+ \row
+ \o \c easeInOutBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function easing in/out: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutbounce.png
+ \row
+ \o \c easeOutInBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function easing out/in: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinbounce.png
+ \endtable
+
+*/
+QString QmlPropertyAnimation::easing() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->easing;
+}
+
+void QmlPropertyAnimation::setEasing(const QString &e)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->easing == e)
+ return;
+
+ d->easing = e;
+ d->va->setEasingCurve(stringToCurve(d->easing, this));
+ emit easingChanged(e);
+}
+
+/*!
+ \qmlproperty Object PropertyAnimation::target
+ This property holds an explicit target object to animate.
+
+ target is used in conjunction with property to determine
+ what property should be animated.
+
+ \sa property matchTargets
+*/
+
+QObject *QmlPropertyAnimation::target() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->target;
+}
+
+void QmlPropertyAnimation::setTarget(QObject *o)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->target == o)
+ return;
+
+ d->target = o;
+ if (d->target && !d->propertyName.isEmpty()) {
+ d->userProperty = d->createProperty(d->target, d->propertyName, this);
+ } else {
+ d->userProperty.invalidate();
+ }
+
+ emit targetChanged(d->target, d->propertyName);
+}
+
+/*!
+ \qmlproperty string PropertyAnimation::property
+ This property holds an explicit property name to animate.
+
+ property is used in conjunction with target to determine
+ what property should be animated.
+
+ \sa target matchProperties
+*/
+
+QString QmlPropertyAnimation::property() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->propertyName;
+}
+
+void QmlPropertyAnimation::setProperty(const QString &n)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->propertyName == n)
+ return;
+
+ d->propertyName = n;
+ if (d->target && !d->propertyName.isEmpty()) {
+ d->userProperty = d->createProperty(d->target, d->propertyName, this);
+ } else {
+ d->userProperty.invalidate();
+ }
+
+ emit targetChanged(d->target, d->propertyName);
+}
+
+/*!
+ \qmlproperty string PropertyAnimation::matchProperties
+ This property holds a comma-separated list of property names this animation
+ will match against. These names are used in conjunction with matchTargets
+ to create a list of properties that the animation will animate, assuming those
+ properties have changed.
+
+ In the following example, the change in 'x' will be animated by the transition, while
+ the change in 'y' will not.
+ \qml
+ State {
+ PropertyChanges {
+ target: myItem
+ x: 15; y: 15
+ }
+ }
+ Transition {
+ PropertyAnimation {
+ matchProperties: "x"
+ }
+ }
+ \endqml
+
+ This property is typically used for an animation appearing as part of a Transition.
+
+ By default, no property names will be matched.
+
+ \sa matchTargets PropertyAction::matchTargets
+*/
+QString QmlPropertyAnimation::properties() const
+{
+ Q_D(const QmlPropertyAnimation);
+ return d->properties;
+}
+
+void QmlPropertyAnimation::setProperties(const QString &prop)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->properties == prop)
+ return;
+
+ d->properties = prop;
+ emit propertiesChanged(prop);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAnimation::matchTargets
+ This property holds a list of objects this animation will match against.
+ These objects are used in conjunction with matchProperties to create a list of properties
+ that the animation will animate, assuming those properties have changed.
+
+ In the following example, the changes to \c myItem will be animated by the transition, while
+ the changes to \c myOtherItem will not.
+ \qml
+ State {
+ PropertyChanges {
+ target: myItem
+ x: 15; y: 15
+ }
+ PropertyChanges {
+ target: myOtherItem
+ x: 30; y: 30
+ }
+ }
+ Transition {
+ PropertyAnimation {
+ matchTargets: myItem
+ matchProperties: "x,y"
+ }
+ }
+ \endqml
+
+ This property is typically used for an animation appearing as part of a Transition.
+
+ By default, all changing targets will be matched.
+
+ \sa exclude matchProperties
+*/
+QmlListProperty<QObject> QmlPropertyAnimation::targets()
+{
+ Q_D(QmlPropertyAnimation);
+ return QmlListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> PropertyAnimation::exclude
+ This property holds the items not to be affected by this animation.
+ \sa matchTargets
+*/
+QmlListProperty<QObject> QmlPropertyAnimation::exclude()
+{
+ Q_D(QmlPropertyAnimation);
+ return QmlListProperty<QObject>(this, d->exclude);
+}
+
+void QmlPropertyAnimationPrivate::valueChanged(qreal r)
+{
+ if (!fromSourced) {
+ if (!fromIsDefined) {
+ from = property.read();
+ convertVariant(from, interpolatorType ? interpolatorType : property.propertyType());
+ //### check for invalid variant if using property type
+ }
+ fromSourced = true;
+ }
+
+ if (r == 1.) {
+ property.write(to, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ } else {
+ if (interpolator)
+ property.write(interpolator(from.constData(), to.constData(), r), QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ }
+}
+
+QAbstractAnimation *QmlPropertyAnimation::qtAnimation()
+{
+ Q_D(QmlPropertyAnimation);
+ return d->va;
+}
+
+void QmlPropertyAnimation::prepare(QmlMetaProperty &p)
+{
+ Q_D(QmlPropertyAnimation);
+ if (d->userProperty.isNull)
+ d->property = p;
+ else
+ d->property = d->userProperty;
+
+ if (!d->rangeIsSet) {
+ d->va->setStartValue(qreal(0));
+ d->va->setEndValue(qreal(1));
+ d->rangeIsSet = true;
+ }
+
+ int propType = d->property.propertyType();
+ d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : propType);
+ if (d->fromIsDefined)
+ d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : propType);
+
+ if (!d->interpolatorType) {
+ //### check for invalid variants
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(propType);
+ }
+
+ d->fromSourced = false;
+ d->value.QmlTimeLineValue::setValue(0.);
+ d->va->setAnimValue(&d->value, QAbstractAnimation::KeepWhenStopped);
+ d->va->setFromSourcedValue(&d->fromSourced);
+}
+
+void QmlPropertyAnimation::transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QmlPropertyAnimation);
+ Q_UNUSED(direction);
+
+ struct PropertyUpdater : public QmlTimeLineValue
+ {
+ QmlStateActions actions;
+ int interpolatorType; //for Number/ColorAnimation
+ int prevInterpolatorType; //for generic
+ QVariantAnimation::Interpolator interpolator;
+ bool reverse;
+ bool *wasDeleted;
+ PropertyUpdater() : wasDeleted(0) {}
+ ~PropertyUpdater() { if (wasDeleted) *wasDeleted = true; }
+ void setValue(qreal v)
+ {
+ bool deleted = false;
+ wasDeleted = &deleted;
+ if (reverse) //QVariantAnimation sends us 1->0 when reversed, but we are expecting 0->1
+ v = 1 - v;
+ QmlTimeLineValue::setValue(v);
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+
+ if (v == 1.)
+ action.property.write(action.toValue, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ else {
+ if (action.fromValue.isNull()) {
+ action.fromValue = action.property.read();
+ if (interpolatorType)
+ QmlPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType);
+ }
+ if (!interpolatorType) {
+ int propType = action.property.propertyType();
+ if (!prevInterpolatorType || prevInterpolatorType != propType) {
+ prevInterpolatorType = propType;
+ interpolator = QVariantAnimationPrivate::getInterpolator(prevInterpolatorType);
+ }
+ }
+ if (interpolator)
+ action.property.write(interpolator(action.fromValue.constData(), action.toValue.constData(), v), QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ }
+ if (deleted)
+ return;
+ }
+ wasDeleted = 0;
+ }
+ };
+
+ QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
+ for (int ii = 0; ii < props.count(); ++ii)
+ props[ii] = props.at(ii).trimmed();
+
+ bool hasSelectors = !props.isEmpty() || !d->targets.isEmpty() || !d->exclude.isEmpty();
+ bool hasTarget = !d->propertyName.isEmpty() || d->target;
+
+ if (hasSelectors && hasTarget) {
+ qmlInfo(this) << tr("matchTargets/matchProperties/exclude and target/property are mutually exclusive.");
+ return;
+ }
+
+ bool useType = (props.isEmpty() && d->propertyName.isEmpty() && d->defaultToInterpolatorType) ? true : false;
+
+ PropertyUpdater *data = new PropertyUpdater;
+ data->interpolatorType = d->interpolatorType;
+ data->interpolator = d->interpolator;
+ data->reverse = direction == Backward ? true : false;
+
+ bool hasExplicit = false;
+ //an explicit animation has been specified
+ if (hasTarget && d->toIsDefined) {
+ QmlAction myAction;
+ myAction.property = d->createProperty(target(), d->propertyName, this);
+ if (myAction.property.isValid()) {
+ if (d->fromIsDefined) {
+ d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ myAction.fromValue = d->from;
+ }
+ d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ myAction.toValue = d->to;
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+ if (action.property.object() == myAction.property.object() &&
+ myAction.property.name() == action.property.name()) {
+ modified << action.property;
+ break; //### any chance there could be multiples?
+ }
+ }
+ }
+ }
+
+ if (!hasExplicit)
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QmlAction &action = actions[ii];
+
+ QObject *obj = action.property.object();
+ QString propertyName = action.property.name();
+ QObject *sObj = action.specifiedObject;
+ QString sPropertyName = action.specifiedProperty;
+ bool same = (obj == sObj);
+
+ if ((d->targets.isEmpty() || d->targets.contains(obj) || (!same && d->targets.contains(sObj))) &&
+ (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) &&
+ (props.contains(propertyName) || (!same && props.contains(sPropertyName))
+ || (useType && action.property.propertyType() == d->interpolatorType))) {
+ QmlAction myAction = action;
+
+ if (d->fromIsDefined)
+ myAction.fromValue = d->from;
+ else
+ myAction.fromValue = QVariant();
+ if (d->toIsDefined)
+ myAction.toValue = d->to;
+
+ d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+
+ modified << action.property;
+
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ } else if (d->userProperty.isValid() &&
+ !hasSelectors && !hasTarget) {
+ if ((d->userProperty.value.object() == obj || (!same && d->userProperty.value.object() == sObj)) &&
+ (d->userProperty.value.name() == propertyName || (!same && d->userProperty.value.name() == sPropertyName))) {
+ //### same as above. merge
+ QmlAction myAction = action;
+
+ if (d->fromIsDefined)
+ myAction.fromValue = d->from;
+ else
+ myAction.fromValue = QVariant();
+ if (d->toIsDefined)
+ myAction.toValue = d->to;
+
+ d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+
+ modified << action.property;
+
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ }
+ }
+ }
+
+ 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);
+ } else {
+ delete data;
+ }
+}
+
+QML_DEFINE_TYPE(Qt,4,6,PropertyAnimation,QmlPropertyAnimation)
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h
new file mode 100644
index 0000000..a566074
--- /dev/null
+++ b/src/declarative/util/qmlanimation_p.h
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLANIMATION_H
+#define QMLANIMATION_H
+
+#include "qmltransition_p.h"
+#include "qmlstate_p.h"
+#include <QtGui/qvector3d.h>
+
+#include <qmlpropertyvaluesource.h>
+#include <qml.h>
+#include <qmlscriptstring.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/QAbstractAnimation>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlAbstractAnimationPrivate;
+class QmlAnimationGroup;
+class Q_AUTOTEST_EXPORT QmlAbstractAnimation : public QObject, public QmlPropertyValueSource, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlAbstractAnimation)
+
+ Q_INTERFACES(QmlParserStatus)
+ Q_INTERFACES(QmlPropertyValueSource)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
+ Q_PROPERTY(bool alwaysRunToEnd READ alwaysRunToEnd WRITE setAlwaysRunToEnd NOTIFY alwaysRunToEndChanged())
+ Q_PROPERTY(bool repeat READ repeat WRITE setRepeat NOTIFY repeatChanged)
+ Q_CLASSINFO("DefaultMethod", "start()")
+
+public:
+ QmlAbstractAnimation(QObject *parent=0);
+ virtual ~QmlAbstractAnimation();
+
+ bool isRunning() const;
+ void setRunning(bool);
+ bool isPaused() const;
+ void setPaused(bool);
+ bool alwaysRunToEnd() const;
+ void setAlwaysRunToEnd(bool);
+ bool repeat() const;
+ void setRepeat(bool);
+
+ int currentTime();
+ void setCurrentTime(int);
+
+ QmlAnimationGroup *group() const;
+ void setGroup(QmlAnimationGroup *);
+
+ virtual void setTarget(const QmlMetaProperty &);
+
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void started();
+ void completed();
+ void runningChanged(bool);
+ void pausedChanged(bool);
+ void repeatChanged(bool);
+ void alwaysRunToEndChanged(bool);
+
+public Q_SLOTS:
+ void restart();
+ void start();
+ void pause();
+ void resume();
+ void stop();
+ void complete();
+
+protected:
+ QmlAbstractAnimation(QmlAbstractAnimationPrivate &dd, QObject *parent);
+
+public:
+ enum TransitionDirection { Forward, Backward };
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual void prepare(QmlMetaProperty &);
+ virtual QAbstractAnimation *qtAnimation() = 0;
+
+private Q_SLOTS:
+ void timelineComplete();
+};
+
+class QmlPauseAnimationPrivate;
+class Q_AUTOTEST_EXPORT QmlPauseAnimation : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPauseAnimation)
+
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+
+public:
+ QmlPauseAnimation(QObject *parent=0);
+ virtual ~QmlPauseAnimation();
+
+ int duration() const;
+ void setDuration(int);
+
+Q_SIGNALS:
+ void durationChanged(int);
+
+protected:
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QmlScriptActionPrivate;
+class QmlScriptAction : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlScriptAction)
+
+ Q_PROPERTY(QmlScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString stateChangeScriptName READ stateChangeScriptName WRITE setStateChangeScriptName)
+
+public:
+ QmlScriptAction(QObject *parent=0);
+ virtual ~QmlScriptAction();
+
+ QmlScriptString script() const;
+ void setScript(const QmlScriptString &);
+
+ QString stateChangeScriptName() const;
+ void setStateChangeScriptName(const QString &);
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QmlPropertyActionPrivate;
+class QmlPropertyAction : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyAction)
+
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY targetChanged)
+ Q_PROPERTY(QString matchProperties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QmlListProperty<QObject> matchTargets READ targets)
+ Q_PROPERTY(QmlListProperty<QObject> exclude READ exclude)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ QmlPropertyAction(QObject *parent=0);
+ virtual ~QmlPropertyAction();
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QmlListProperty<QObject> targets();
+ QmlListProperty<QObject> exclude();
+
+ QVariant value() const;
+ void setValue(const QVariant &);
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &);
+ void propertiesChanged(const QString &);
+ void targetChanged(QObject *, const QString &);
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+ virtual void prepare(QmlMetaProperty &);
+};
+
+class QmlGraphicsItem;
+class QmlParentActionPrivate;
+class QmlParentAction : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlParentAction)
+
+ Q_PROPERTY(QmlGraphicsItem *target READ object WRITE setObject)
+ Q_PROPERTY(QmlGraphicsItem *matchTarget READ matchTarget WRITE setMatchTarget)
+ Q_PROPERTY(QmlGraphicsItem *parent READ parent WRITE setParent)
+
+public:
+ QmlParentAction(QObject *parent=0);
+ virtual ~QmlParentAction();
+
+ QmlGraphicsItem *object() const;
+ void setObject(QmlGraphicsItem *);
+
+ QmlGraphicsItem *matchTarget() const;
+ void setMatchTarget(QmlGraphicsItem *);
+
+ QmlGraphicsItem *parent() const;
+ void setParent(QmlGraphicsItem *);
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QmlPropertyAnimationPrivate;
+class Q_AUTOTEST_EXPORT QmlPropertyAnimation : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyAnimation)
+
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(QVariant from READ from WRITE setFrom NOTIFY fromChanged)
+ Q_PROPERTY(QVariant to READ to WRITE setTo NOTIFY toChanged)
+ Q_PROPERTY(QString easing READ easing WRITE setEasing NOTIFY easingChanged)
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY targetChanged)
+ Q_PROPERTY(QString matchProperties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QmlListProperty<QObject> matchTargets READ targets)
+ Q_PROPERTY(QmlListProperty<QObject> exclude READ exclude)
+
+public:
+ QmlPropertyAnimation(QObject *parent=0);
+ virtual ~QmlPropertyAnimation();
+
+ int duration() const;
+ void setDuration(int);
+
+ QVariant from() const;
+ void setFrom(const QVariant &);
+
+ QVariant to() const;
+ void setTo(const QVariant &);
+
+ QString easing() const;
+ void setEasing(const QString &);
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QmlListProperty<QObject> targets();
+ QmlListProperty<QObject> exclude();
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+ virtual void prepare(QmlMetaProperty &);
+
+Q_SIGNALS:
+ void durationChanged(int);
+ void fromChanged(QVariant);
+ void toChanged(QVariant);
+ void easingChanged(const QString &);
+ void propertiesChanged(const QString &);
+ void targetChanged(QObject *, const QString &);
+};
+
+class Q_AUTOTEST_EXPORT QmlColorAnimation : public QmlPropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyAnimation)
+ Q_PROPERTY(QColor from READ from WRITE setFrom NOTIFY fromChanged)
+ Q_PROPERTY(QColor to READ to WRITE setTo NOTIFY toChanged)
+
+public:
+ QmlColorAnimation(QObject *parent=0);
+ virtual ~QmlColorAnimation();
+
+ QColor from() const;
+ void setFrom(const QColor &);
+
+ QColor to() const;
+ void setTo(const QColor &);
+};
+
+class Q_AUTOTEST_EXPORT QmlNumberAnimation : public QmlPropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyAnimation)
+
+ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged)
+ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged)
+
+public:
+ QmlNumberAnimation(QObject *parent=0);
+ virtual ~QmlNumberAnimation();
+
+ qreal from() const;
+ void setFrom(qreal);
+
+ qreal to() const;
+ void setTo(qreal);
+};
+
+class Q_AUTOTEST_EXPORT QmlVector3dAnimation : public QmlPropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyAnimation)
+
+ Q_PROPERTY(QVector3D from READ from WRITE setFrom NOTIFY fromChanged)
+ Q_PROPERTY(QVector3D to READ to WRITE setTo NOTIFY toChanged)
+
+public:
+ QmlVector3dAnimation(QObject *parent=0);
+ virtual ~QmlVector3dAnimation();
+
+ QVector3D from() const;
+ void setFrom(QVector3D);
+
+ QVector3D to() const;
+ void setTo(QVector3D);
+};
+
+class QmlAnimationGroupPrivate;
+class QmlAnimationGroup : public QmlAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlAnimationGroup)
+
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_PROPERTY(QmlList<QmlAbstractAnimation *> *animations READ animations)
+
+public:
+ QmlAnimationGroup(QObject *parent);
+ virtual ~QmlAnimationGroup();
+
+ QmlList<QmlAbstractAnimation *>* animations();
+ friend class QmlAbstractAnimation;
+};
+
+class QmlSequentialAnimation : public QmlAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlAnimationGroup)
+
+public:
+ QmlSequentialAnimation(QObject *parent=0);
+ virtual ~QmlSequentialAnimation();
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+ virtual void prepare(QmlMetaProperty &);
+};
+
+class QmlParallelAnimation : public QmlAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlAnimationGroup)
+
+public:
+ QmlParallelAnimation(QObject *parent=0);
+ virtual ~QmlParallelAnimation();
+
+protected:
+ virtual void transition(QmlStateActions &actions,
+ QmlMetaProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+ virtual void prepare(QmlMetaProperty &);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlAbstractAnimation)
+QML_DECLARE_TYPE(QmlPauseAnimation)
+QML_DECLARE_TYPE(QmlScriptAction)
+QML_DECLARE_TYPE(QmlPropertyAction)
+QML_DECLARE_TYPE(QmlParentAction)
+QML_DECLARE_TYPE(QmlPropertyAnimation)
+QML_DECLARE_TYPE(QmlColorAnimation)
+QML_DECLARE_TYPE(QmlNumberAnimation)
+QML_DECLARE_TYPE(QmlSequentialAnimation)
+QML_DECLARE_TYPE(QmlParallelAnimation)
+QML_DECLARE_TYPE(QmlVector3dAnimation)
+
+QT_END_HEADER
+
+#endif // QMLANIMATION_H
diff --git a/src/declarative/util/qmlanimation_p_p.h b/src/declarative/util/qmlanimation_p_p.h
new file mode 100644
index 0000000..2f911b4
--- /dev/null
+++ b/src/declarative/util/qmlanimation_p_p.h
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLANIMATION_P_H
+#define QMLANIMATION_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 "qmlanimation_p.h"
+
+#include "qmlnullablevalue_p_p.h"
+#include "qmltimeline_p_p.h"
+
+#include <qml.h>
+#include <qmlcontext.h>
+
+#include <QtCore/QPauseAnimation>
+#include <QtCore/QVariantAnimation>
+#include <QtCore/QAnimationGroup>
+#include <QtGui/QColor>
+#include <QDebug>
+
+#include <private/qobject_p.h>
+#include <private/qvariantanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//interface for classes that provide animation actions for QActionAnimation
+class QAbstractAnimationAction
+{
+public:
+ virtual ~QAbstractAnimationAction() {}
+ virtual void doAction() = 0;
+};
+
+//templated animation action
+//allows us to specify an action that calls a function of a class.
+//(so that class doesn't have to inherit QmlAbstractAnimationAction)
+template<class T, void (T::*method)()>
+class QAnimationActionProxy : public QAbstractAnimationAction
+{
+public:
+ QAnimationActionProxy(T *p) : m_p(p) {}
+ virtual void doAction() { (m_p->*method)(); }
+
+private:
+ T *m_p;
+};
+
+//performs an action of type QAbstractAnimationAction
+class QActionAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+public:
+ QActionAnimation(QObject *parent = 0) : QAbstractAnimation(parent), animAction(0), policy(KeepWhenStopped), running(false) {}
+ QActionAnimation(QAbstractAnimationAction *action, QObject *parent = 0)
+ : QAbstractAnimation(parent), animAction(action), policy(KeepWhenStopped), running(false) {}
+ ~QActionAnimation() { if (policy == DeleteWhenStopped) { delete animAction; animAction = 0; } }
+ virtual int duration() const { return 0; }
+ void setAnimAction(QAbstractAnimationAction *action, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ animAction = action;
+ policy = p;
+ }
+protected:
+ virtual void updateCurrentTime(int) {}
+
+ virtual void updateState(State newState, State /*oldState*/)
+ {
+ if (newState == Running) {
+ if (animAction) {
+ running = true;
+ animAction->doAction();
+ running = false;
+ if (state() == Stopped && policy == DeleteWhenStopped) {
+ delete animAction;
+ animAction = 0;
+ }
+ }
+ } else if (newState == Stopped && policy == DeleteWhenStopped) {
+ if (!running) {
+ delete animAction;
+ animAction = 0;
+ }
+ }
+ }
+
+private:
+ QAbstractAnimationAction *animAction;
+ DeletionPolicy policy;
+ bool running;
+};
+
+//animates QmlTimeLineValue (assumes start and end values will be reals or compatible)
+class QmlTimeLineValueAnimator : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ QmlTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {}
+ ~QmlTimeLineValueAnimator() { if (policy == DeleteWhenStopped) { delete animValue; animValue = 0; } }
+ void setAnimValue(QmlTimeLineValue *value, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ animValue = value;
+ policy = p;
+ }
+ void setFromSourcedValue(bool *value)
+ {
+ fromSourced = value;
+ }
+protected:
+ virtual void updateCurrentValue(const QVariant &value)
+ {
+ if (animValue)
+ animValue->setValue(value.toReal());
+ }
+ virtual void updateState(State newState, State oldState)
+ {
+ QVariantAnimation::updateState(newState, oldState);
+ if (newState == Running) {
+ //check for new from every loop
+ if (fromSourced)
+ *fromSourced = false;
+ } else if (newState == Stopped && policy == DeleteWhenStopped) {
+ delete animValue;
+ animValue = 0;
+ }
+ }
+
+private:
+ QmlTimeLineValue *animValue;
+ bool *fromSourced;
+ DeletionPolicy policy;
+};
+
+//an animation that just gives a tick
+template<class T, void (T::*method)(int)>
+class QTickAnimationProxy : public QAbstractAnimation
+{
+ //Q_OBJECT //doesn't work with templating
+public:
+ QTickAnimationProxy(T *p, QObject *parent = 0) : QAbstractAnimation(parent), m_p(p) {}
+ virtual int duration() const { return -1; }
+protected:
+ virtual void updateCurrentTime(int msec) { (m_p->*method)(msec); }
+
+private:
+ T *m_p;
+};
+
+class QmlAbstractAnimationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlAbstractAnimation)
+public:
+ QmlAbstractAnimationPrivate()
+ : running(false), paused(false), alwaysRunToEnd(false), repeat(false),
+ connectedTimeLine(false), componentComplete(true), startOnCompletion(false),
+ group(0) {}
+
+ bool running:1;
+ bool paused:1;
+ bool alwaysRunToEnd:1;
+ bool repeat:1;
+ bool connectedTimeLine:1;
+
+ bool componentComplete:1;
+ bool startOnCompletion:1;
+
+ void commence();
+
+ QmlNullableValue<QmlMetaProperty> userProperty;
+
+ QmlMetaProperty property;
+ QmlAnimationGroup *group;
+
+ static QmlMetaProperty createProperty(QObject *obj, const QString &str, QObject *infoObj);
+};
+
+class QmlPauseAnimationPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPauseAnimation)
+public:
+ QmlPauseAnimationPrivate()
+ : QmlAbstractAnimationPrivate(), pa(0) {}
+
+ void init();
+
+ QPauseAnimation *pa;
+};
+
+class QmlScriptActionPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlScriptAction)
+public:
+ QmlScriptActionPrivate()
+ : QmlAbstractAnimationPrivate(), hasRunScriptScript(false), proxy(this), rsa(0) {}
+
+ void init();
+
+ QmlScriptString script;
+ QString name;
+ QmlScriptString runScriptScript;
+ bool hasRunScriptScript;
+
+ void execute();
+
+ QAnimationActionProxy<QmlScriptActionPrivate,
+ &QmlScriptActionPrivate::execute> proxy;
+ QActionAnimation *rsa;
+};
+
+class QmlPropertyActionPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPropertyAction)
+public:
+ QmlPropertyActionPrivate()
+ : QmlAbstractAnimationPrivate(), target(0), proxy(this), spa(0) {}
+
+ void init();
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+
+ QmlNullableValue<QVariant> value;
+
+ void doAction();
+
+ QAnimationActionProxy<QmlPropertyActionPrivate,
+ &QmlPropertyActionPrivate::doAction> proxy;
+ QActionAnimation *spa;
+};
+
+class QmlParentActionPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlParentAction)
+public:
+ QmlParentActionPrivate()
+ : QmlAbstractAnimationPrivate(), pcTarget(0), pcMatchTarget(0), pcParent(0) {}
+
+ void init();
+
+ QmlGraphicsItem *pcTarget;
+ QmlGraphicsItem *pcMatchTarget;
+ QmlGraphicsItem *pcParent;
+
+ void doAction();
+ QActionAnimation *cpa;
+};
+
+class QmlAnimationGroupPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlAnimationGroup)
+public:
+ QmlAnimationGroupPrivate()
+ : QmlAbstractAnimationPrivate(), animations(this), ag(0) {}
+
+ struct AnimationList : public QmlConcreteList<QmlAbstractAnimation *>
+ {
+ AnimationList(QmlAnimationGroupPrivate *p)
+ : anim(p) {}
+ virtual void append(QmlAbstractAnimation *a) {
+ QmlConcreteList<QmlAbstractAnimation *>::append(a);
+ a->setGroup(anim->q_func());
+ }
+ virtual void clear()
+ {
+ for (int i = 0; i < count(); ++i)
+ at(i)->setGroup(0);
+ QmlConcreteList<QmlAbstractAnimation *>::clear();
+ }
+ virtual void removeAt(int i)
+ {
+ at(i)->setGroup(0);
+ QmlConcreteList<QmlAbstractAnimation *>::removeAt(i);
+ }
+ virtual void insert(int i, QmlAbstractAnimation *a)
+ {
+ QmlConcreteList<QmlAbstractAnimation *>::insert(i, a);
+ a->setGroup(anim->q_func());
+ }
+
+ QmlAnimationGroupPrivate *anim;
+ };
+
+ AnimationList animations;
+ QAnimationGroup *ag;
+};
+
+class QmlPropertyAnimationPrivate : public QmlAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPropertyAnimation)
+public:
+ QmlPropertyAnimationPrivate()
+ : QmlAbstractAnimationPrivate(), target(0), fromSourced(false), fromIsDefined(false), toIsDefined(false),
+ rangeIsSet(false), defaultToInterpolatorType(0), interpolatorType(0), interpolator(0), va(0),
+ value(this, &QmlPropertyAnimationPrivate::valueChanged) {}
+
+ void init();
+
+ QVariant from;
+ QVariant to;
+
+ QString easing;
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+
+ bool fromSourced;
+ bool fromIsDefined:1;
+ bool toIsDefined:1;
+ bool rangeIsSet:1;
+ bool defaultToInterpolatorType:1;
+ int interpolatorType;
+ QVariantAnimation::Interpolator interpolator;
+
+ QmlTimeLineValueAnimator *va;
+ virtual void valueChanged(qreal);
+
+ QmlTimeLineValueProxy<QmlPropertyAnimationPrivate> value;
+
+ static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress);
+ static void convertVariant(QVariant &variant, int type);
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLANIMATION_P_H
diff --git a/src/declarative/util/qmlbehavior.cpp b/src/declarative/util/qmlbehavior.cpp
new file mode 100644
index 0000000..b9c77f5
--- /dev/null
+++ b/src/declarative/util/qmlbehavior.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlbehavior_p.h"
+
+#include "qmlanimation_p.h"
+#include "qmltransition_p.h"
+
+#include <qmlcontext.h>
+#include <qmlinfo.h>
+
+#include <QtCore/qparallelanimationgroup.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,Behavior,QmlBehavior)
+
+class QmlBehaviorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlBehavior)
+public:
+ QmlBehaviorPrivate() : animation(0), enabled(true) {}
+
+ QmlMetaProperty property;
+ QVariant currentValue;
+ QmlAbstractAnimation *animation;
+ bool enabled;
+};
+
+/*!
+ \qmlclass Behavior QmlBehavior
+ \brief The Behavior element allows you to specify a default animation for a property change.
+
+ Behaviors provide one way to specify \l{qmlanimation.html}{animations} in QML.
+
+ In the example below, the rect will use a bounce easing curve over 200 millisecond for any changes to its y property:
+ \code
+ Rectangle {
+ width: 20; height: 20
+ color: "#00ff00"
+ y: 200 //initial value
+ y: Behavior {
+ NumberAnimation {
+ easing: "easeOutBounce(amplitude:100)"
+ duration: 200
+ }
+ }
+ }
+ \endcode
+
+ Currently only a single Behavior may be specified for a property;
+ this Behavior can be enabled and disabled via the \l{enabled} property.
+*/
+
+
+QmlBehavior::QmlBehavior(QObject *parent)
+ : QObject(*(new QmlBehaviorPrivate), parent)
+{
+}
+
+QmlBehavior::~QmlBehavior()
+{
+}
+
+/*!
+ \qmlproperty Animation Behavior::animation
+ \default
+
+ The animation to use when the behavior is triggered.
+*/
+
+QmlAbstractAnimation *QmlBehavior::animation()
+{
+ Q_D(QmlBehavior);
+ return d->animation;
+}
+
+void QmlBehavior::setAnimation(QmlAbstractAnimation *animation)
+{
+ Q_D(QmlBehavior);
+ if (d->animation) {
+ qmlInfo(this) << tr("Can't change the animation assigned to a Behavior.");
+ return;
+ }
+
+ d->animation = animation;
+ if (d->animation)
+ d->animation->setTarget(d->property);
+}
+
+/*!
+ \qmlproperty bool Behavior::enabled
+ Whether the Behavior will be triggered when the property it is tracking changes.
+
+ By default a Behavior is enabled.
+*/
+
+bool QmlBehavior::enabled() const
+{
+ Q_D(const QmlBehavior);
+ return d->enabled;
+}
+
+void QmlBehavior::setEnabled(bool enabled)
+{
+ Q_D(QmlBehavior);
+ if (d->enabled == enabled)
+ return;
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+void QmlBehavior::write(const QVariant &value)
+{
+ Q_D(QmlBehavior);
+ if (!d->animation || !d->enabled) {
+ d->property.write(value, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ return;
+ }
+
+ d->currentValue = d->property.read();
+
+ d->animation->qtAnimation()->stop();
+
+ QmlStateOperation::ActionList actions;
+ QmlAction action;
+ action.property = d->property;
+ action.fromValue = d->currentValue;
+ action.toValue = value;
+ actions << action;
+
+ QList<QmlMetaProperty> after;
+ if (d->animation)
+ d->animation->transition(actions, after, QmlAbstractAnimation::Forward);
+ d->animation->qtAnimation()->start();
+ if (!after.contains(d->property))
+ d->property.write(value, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+}
+
+void QmlBehavior::setTarget(const QmlMetaProperty &property)
+{
+ Q_D(QmlBehavior);
+ d->property = property;
+ d->currentValue = property.read();
+ if (d->animation)
+ d->animation->setTarget(property);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlbehavior_p.h b/src/declarative/util/qmlbehavior_p.h
new file mode 100644
index 0000000..da3b40f
--- /dev/null
+++ b/src/declarative/util/qmlbehavior_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLBEHAVIOR_H
+#define QMLBEHAVIOR_H
+
+#include "qmlstate_p.h"
+
+#include <qmlpropertyvaluesource.h>
+#include <qmlpropertyvalueinterceptor.h>
+#include <qml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlAbstractAnimation;
+class QmlBehaviorPrivate;
+class Q_DECLARATIVE_EXPORT QmlBehavior : public QObject, public QmlPropertyValueInterceptor
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlBehavior)
+
+ Q_INTERFACES(QmlPropertyValueInterceptor)
+ Q_CLASSINFO("DefaultProperty", "animation")
+ Q_PROPERTY(QmlAbstractAnimation *animation READ animation WRITE setAnimation)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+
+public:
+ QmlBehavior(QObject *parent=0);
+ ~QmlBehavior();
+
+ virtual void setTarget(const QmlMetaProperty &);
+ virtual void write(const QVariant &value);
+
+ QmlAbstractAnimation *animation();
+ void setAnimation(QmlAbstractAnimation *);
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+Q_SIGNALS:
+ void enabledChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlBehavior)
+
+QT_END_HEADER
+
+#endif // QMLBEHAVIOR_H
diff --git a/src/declarative/util/qmlbind.cpp b/src/declarative/util/qmlbind.cpp
new file mode 100644
index 0000000..c68cef2
--- /dev/null
+++ b/src/declarative/util/qmlbind.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlbind_p.h"
+
+#include "qmlnullablevalue_p_p.h"
+
+#include <qmlengine.h>
+#include <qmlcontext.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptengine.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlBindPrivate : public QObjectPrivate
+{
+public:
+ QmlBindPrivate() : when(true), componentComplete(false), obj(0) {}
+
+ bool when : 1;
+ bool componentComplete : 1;
+ QObject *obj;
+ QString prop;
+ QmlNullableValue<QVariant> value;
+};
+
+QML_DEFINE_TYPE(Qt,4,6,Binding,QmlBind)
+/*!
+ \qmlclass Binding QmlBind
+ \brief The Binding element allows arbitrary property bindings to be created.
+
+ Sometimes it is necessary to bind to a property of an object that wasn't
+ directly instantiated by QML - generally a property of a class exported
+ to QML by C++. In these cases, regular property binding doesn't work. Binding
+ allows you to bind any value to any property.
+
+ For example, imagine a C++ application that maps an "app.enteredText"
+ property into QML. You could use Binding to update the enteredText property
+ like this.
+ \code
+ TextEdit { id: myTextField; text: "Please type here..." }
+ Binding { target: app; property: "enteredText"; value: myTextField.text }
+ \endcode
+ Whenever the text in the TextEdit is updated, the C++ property will be
+ updated also.
+
+ If the binding target or binding property is changed, the bound value is
+ immediately pushed onto the new target.
+ */
+/*!
+ \internal
+ \class QmlBind
+ \ingroup group_utility
+ \brief The QmlBind class allows arbitrary property bindings to be created.
+
+ Simple bindings are usually earier to do in-place rather than creating a
+ QmlBind item. For that reason, QmlBind is usually used to transfer property information
+ from Qml to C++.
+
+ \sa cppqml
+ */
+QmlBind::QmlBind(QObject *parent)
+ : QObject(*(new QmlBindPrivate), parent)
+{
+}
+
+QmlBind::~QmlBind()
+{
+}
+
+bool QmlBind::when() const
+{
+ Q_D(const QmlBind);
+ return d->when;
+}
+
+void QmlBind::setWhen(bool v)
+{
+ Q_D(QmlBind);
+ d->when = v;
+ eval();
+}
+
+/*!
+ \qmlproperty Object Binding::target
+
+ The object to be updated.
+*/
+QObject *QmlBind::object()
+{
+ Q_D(const QmlBind);
+ return d->obj;
+}
+
+void QmlBind::setObject(QObject *obj)
+{
+ Q_D(QmlBind);
+ d->obj = obj;
+ eval();
+}
+
+/*!
+ \qmlproperty string Binding::property
+
+ The property to be updated.
+*/
+QString QmlBind::property() const
+{
+ Q_D(const QmlBind);
+ return d->prop;
+}
+
+void QmlBind::setProperty(const QString &p)
+{
+ Q_D(QmlBind);
+ d->prop = p;
+ eval();
+}
+
+/*!
+ \qmlproperty any Binding::value
+
+ The value to be set on the target object and property. This can be a
+ constant (which isn't very useful), or a bound expression.
+*/
+QVariant QmlBind::value() const
+{
+ Q_D(const QmlBind);
+ return d->value.value;
+}
+
+void QmlBind::setValue(const QVariant &v)
+{
+ Q_D(QmlBind);
+ d->value.value = v;
+ d->value.isNull = false;
+ eval();
+}
+
+void QmlBind::componentComplete()
+{
+ Q_D(QmlBind);
+ d->componentComplete = true;
+ eval();
+}
+
+void QmlBind::eval()
+{
+ Q_D(QmlBind);
+ if (!d->obj || d->value.isNull || !d->when || !d->componentComplete)
+ return;
+
+ QmlMetaProperty prop(d->obj, d->prop);
+ prop.write(d->value.value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlbind_p.h b/src/declarative/util/qmlbind_p.h
new file mode 100644
index 0000000..4d7cd1f
--- /dev/null
+++ b/src/declarative/util/qmlbind_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLBIND_H
+#define QMLBIND_H
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlBindPrivate;
+class Q_DECLARATIVE_EXPORT QmlBind : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlBind)
+ Q_INTERFACES(QmlParserStatus)
+ Q_PROPERTY(QObject *target READ object WRITE setObject)
+ Q_PROPERTY(QString property READ property WRITE setProperty)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(bool when READ when WRITE setWhen)
+
+public:
+ QmlBind(QObject *parent=0);
+ ~QmlBind();
+
+ bool when() const;
+ void setWhen(bool);
+
+ QObject *object();
+ void setObject(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QVariant value() const;
+ void setValue(const QVariant &);
+
+protected:
+ virtual void componentComplete();
+
+private:
+ void eval();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlBind)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmlconnection.cpp b/src/declarative/util/qmlconnection.cpp
new file mode 100644
index 0000000..800fd6b
--- /dev/null
+++ b/src/declarative/util/qmlconnection.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlconnection_p.h"
+
+#include <qmlexpression.h>
+#include <qmlboundsignal_p.h>
+#include <qmlcontext.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlConnectionPrivate : public QObjectPrivate
+{
+public:
+ QmlConnectionPrivate() : boundsignal(0), signalSender(0), scriptset(false), componentcomplete(false) {}
+
+ QmlBoundSignal *boundsignal;
+ QObject *signalSender;
+ QmlScriptString script;
+ bool scriptset;
+ QString signal;
+ bool componentcomplete;
+};
+
+/*!
+ \qmlclass Connection QmlConnection
+ \brief A Connection object describes generalized connections to signals.
+
+ When connecting to signals in QML, the usual way is to create an
+ "on<Signal>" handler that reacts when a signal is received, like this:
+
+ \qml
+ MouseRegion {
+ onClicked: { foo(x+123,y+456) }
+ }
+ \endqml
+
+ However, in some cases, it is not possible to connect to a signal in this
+ way. For example, JavaScript-in-HTML style signal properties do not allow:
+
+ \list
+ \i connecting to signals with the same name but different parameters
+ \i conformance checking that parameters are correctly named
+ \i multiple connections to the same signal
+ \i connections outside the scope of the signal sender
+ \i signals in classes with coincidentally-named on<Signal> properties
+ \endlist
+
+ When any of these are needed, the Connection object can be used instead.
+
+ For example, the above code can be changed to use a Connection object,
+ like this:
+
+ \qml
+ MouseRegion {
+ Connection {
+ signal: "clicked(x,y)"
+ script: { foo(x+123,y+456) }
+ }
+ }
+ \endqml
+
+ More generally, the Connection object can be a child of some other object than
+ the sender of the signal, and the script is the default attribute:
+
+ \qml
+ MouseRegion {
+ id: mr
+ }
+ ...
+ Connection {
+ sender: mr
+ signal: "clicked(x,y)"
+ script: { foo(x+123,y+456) }
+ }
+ \endqml
+*/
+
+/*!
+ \internal
+ \class QmlConnection
+ \brief The QmlConnection class describes generalized connections to signals.
+
+*/
+QmlConnection::QmlConnection(QObject *parent) :
+ QObject(*(new QmlConnectionPrivate), parent)
+{
+}
+
+QmlConnection::~QmlConnection()
+{
+ Q_D(QmlConnection);
+ delete d->boundsignal;
+}
+
+/*!
+ \qmlproperty Object Connection::sender
+ This property holds the object that sends the signal.
+
+ By default, the sender is assumed to be the parent of the Connection.
+*/
+QObject *QmlConnection::signalSender() const
+{
+ Q_D(const QmlConnection);
+ return d->signalSender ? d->signalSender : parent();
+}
+
+void QmlConnection::setSignalSender(QObject *obj)
+{
+ Q_D(QmlConnection);
+ if (d->signalSender == obj)
+ return;
+ disconnectIfValid();
+ d->signalSender = obj;
+ connectIfValid();
+}
+
+void QmlConnection::connectIfValid()
+{
+ Q_D(QmlConnection);
+ if (!d->componentcomplete)
+ return;
+ // boundsignal must not exist
+ if ((d->signalSender || parent()) && !d->signal.isEmpty() && d->scriptset) {
+ // create
+ // XXX scope?
+ int sigIdx = -1;
+ int lparen = d->signal.indexOf(QLatin1Char('('));
+ QList<QByteArray> sigparams;
+ if (lparen >= 0 && d->signal.length() > lparen+2) {
+ QStringList l = d->signal.mid(lparen+1,d->signal.length()-lparen-2).split(QLatin1Char(','));
+ foreach (const QString &s, l) {
+ sigparams.append(s.trimmed().toUtf8());
+ }
+ }
+ QString signalname = d->signal.left(lparen);
+ QObject *sender = d->signalSender ? d->signalSender : parent();
+ const QMetaObject *mo = sender->metaObject();
+ int methods = mo->methodCount();
+ for (int ii = 0; ii < methods; ++ii) {
+ QMetaMethod method = mo->method(ii);
+ QString methodName = QString::fromUtf8(method.signature());
+ int idx = methodName.indexOf(QLatin1Char('('));
+ methodName = methodName.left(idx);
+ if (methodName == signalname && (lparen<0 || method.parameterNames() == sigparams)) {
+ sigIdx = ii;
+ break;
+ }
+ }
+ if (sigIdx < 0) {
+ // Cannot usefully warn, since could be in middle of
+ // changing sender and signal.
+ // XXX need state change transactions to do better
+ return;
+ }
+
+ d->boundsignal = new QmlBoundSignal(qmlContext(this), d->script.script(), sender, mo->method(sigIdx), this);
+ }
+}
+
+void QmlConnection::disconnectIfValid()
+{
+ Q_D(QmlConnection);
+ if (!d->componentcomplete)
+ return;
+ if ((d->signalSender || parent()) && !d->signal.isEmpty() && d->scriptset) {
+ // boundsignal must exist
+ // destroy
+ delete d->boundsignal;
+ d->boundsignal = 0;
+ }
+}
+
+void QmlConnection::componentComplete()
+{
+ Q_D(QmlConnection);
+ d->componentcomplete=true;
+ connectIfValid();
+}
+
+
+/*!
+ \qmlproperty script Connection::script
+ This property holds the JavaScript executed whenever the signal is sent.
+
+ This is the default attribute of Connection.
+*/
+QmlScriptString QmlConnection::script() const
+{
+ Q_D(const QmlConnection);
+ return d->script;
+}
+
+void QmlConnection::setScript(const QmlScriptString& script)
+{
+ Q_D(QmlConnection);
+ if ((d->signalSender || parent()) && !d->signal.isEmpty()) {
+ if (!d->scriptset) {
+ // mustn't exist - create
+ d->scriptset = true;
+ d->script = script;
+ connectIfValid();
+ } else {
+ // must exist - update
+ d->script = script;
+ d->boundsignal->expression()->setExpression(script.script());
+ }
+ } else {
+ d->scriptset = true;
+ d->script = script;
+ }
+}
+
+/*!
+ \qmlproperty string Connection::signal
+ This property holds the signal from the sender to which the script is attached.
+
+ The signal's formal parameter names must be given in parentheses:
+
+ \qml
+Connection {
+ signal: "clicked(x,y)"
+ script: { ... }
+}
+ \endqml
+*/
+QString QmlConnection::signal() const
+{
+ Q_D(const QmlConnection);
+ return d->signal;
+}
+
+void QmlConnection::setSignal(const QString& sig)
+{
+ Q_D(QmlConnection);
+ if (d->signal == sig)
+ return;
+ disconnectIfValid();
+ d->signal = sig;
+ connectIfValid();
+}
+
+QML_DEFINE_TYPE(Qt,4,6,Connection,QmlConnection)
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlconnection_p.h b/src/declarative/util/qmlconnection_p.h
new file mode 100644
index 0000000..52bc247
--- /dev/null
+++ b/src/declarative/util/qmlconnection_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLCONNECTION_H
+#define QMLCONNECTION_H
+
+#include <qml.h>
+#include <qmlscriptstring.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlBoundSignal;
+class QmlContext;
+class QmlConnectionPrivate;
+class Q_DECLARATIVE_EXPORT QmlConnection : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlConnection)
+
+ Q_INTERFACES(QmlParserStatus)
+ Q_PROPERTY(QObject *sender READ signalSender WRITE setSignalSender)
+ Q_PROPERTY(QmlScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString signal READ signal WRITE setSignal)
+
+public:
+ QmlConnection(QObject *parent=0);
+ ~QmlConnection();
+
+ QObject *signalSender() const;
+ void setSignalSender(QObject *);
+ QmlScriptString script() const;
+ void setScript(const QmlScriptString&);
+ QString signal() const;
+ void setSignal(const QString&);
+
+private:
+ void disconnectIfValid();
+ void connectIfValid();
+ void componentComplete();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlConnection)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmldatetimeformatter.cpp b/src/declarative/util/qmldatetimeformatter.cpp
new file mode 100644
index 0000000..9d216cf
--- /dev/null
+++ b/src/declarative/util/qmldatetimeformatter.cpp
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmldatetimeformatter_p.h"
+
+#include <QtCore/qlocale.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//TODO: may need optimisation as the QDateTime member may not be needed?
+// be able to set a locale?
+
+class QmlDateTimeFormatterPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlDateTimeFormatter)
+public:
+ QmlDateTimeFormatterPrivate() : locale(QLocale::system()), longStyle(false), componentComplete(true) {}
+
+ void updateText();
+
+ QDateTime dateTime;
+ QDate date;
+ QTime time;
+ QLocale locale;
+ QString dateTimeText;
+ QString dateText;
+ QString timeText;
+ QString dateTimeFormat; //set for convienience?
+ QString dateFormat;
+ QString timeFormat;
+ bool longStyle;
+ bool componentComplete;
+};
+
+/*!
+ \qmlclass DateTimeFormatter QmlDateTimeFormatter
+ \brief The DateTimeFormatter allows you to control the format of a date string.
+
+ \code
+ DateTimeFormatter { id: formatter; date: System.date }
+ Text { text: formatter.dateText }
+ \endcode
+
+ By default, the text properties (dateText, timeText, and dateTimeText) will return the
+ date and time using the current system locale's format.
+*/
+
+/*!
+ \internal
+ \class QmlDateTimeFormatter
+ \ingroup group_utility
+ \brief The QmlDateTimeFormatter class allows you to format a date string.
+*/
+
+QmlDateTimeFormatter::QmlDateTimeFormatter(QObject *parent)
+: QObject(*(new QmlDateTimeFormatterPrivate), parent)
+{
+}
+
+QmlDateTimeFormatter::~QmlDateTimeFormatter()
+{
+}
+
+/*!
+ \qmlproperty string DateTimeFormatter::dateText
+ \qmlproperty string DateTimeFormatter::timeText
+ \qmlproperty string DateTimeFormatter::dateTimeText
+
+ Formatted text representations of the \c date, \c time,
+ and \c {date and time}, respectively.
+
+ If there is no explictly specified format the DateTimeFormatter
+ will use the system locale's default 'short' setting.
+
+ \code
+ // specify source date (assuming today is February 19, 2009)
+ DateTimeFormatter { id: formatter; dateTime: Today.date }
+
+ // display the full date and time
+ Text { text: formatter.dateText }
+ \endcode
+
+ Would be equivalent to the following for a US English locale:
+
+ \code
+ // display the date
+ Text { text: "2/19/09" }
+ \endcode
+*/
+QString QmlDateTimeFormatter::dateTimeText() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->dateTimeText;
+}
+
+QString QmlDateTimeFormatter::dateText() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->dateText;
+}
+
+QString QmlDateTimeFormatter::timeText() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->timeText;
+}
+
+/*!
+ \qmlproperty date DateTimeFormatter::date
+ \qmlproperty time DateTimeFormatter::time
+ \qmlproperty datetime DateTimeFormatter::dateTime
+
+ The source date and time to be used by the formatter.
+
+ \code
+ // setting the date and time
+ DateTimeFormatter { date: System.date; time: System.time }
+ \endcode
+
+ For convienience it is possible to set the datetime property to set both the date and the time.
+ \code
+ // setting the datetime
+ DateTimeFormatter { dateTime: System.dateTime }
+ \endcode
+
+ There can only be one instance of date and time per formatter; if date, time, and dateTime are all
+ set the actual date and time used is not guaranteed.
+
+ \note If no date is set, dateTimeText will be just the date;
+ If no time is set, the dateTimeText will be just the time.
+
+*/
+QDate QmlDateTimeFormatter::date() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->date;
+}
+
+QTime QmlDateTimeFormatter::time() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->time;
+}
+
+QDateTime QmlDateTimeFormatter::dateTime() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->dateTime;
+}
+
+/*!
+ \qmlproperty string DateTimeFormatter::dateFormat
+ \qmlproperty string DateTimeFormatter::timeFormat
+ \qmlproperty string DateTimeFormatter::dateTimeFormat
+
+ Specifies a custom format which the DateTime Formatter can use.
+
+ If there is no explictly specified format the DateTimeFormatter
+ will use the system locale's default 'short' setting.
+
+ The text's format may be modified by setting:
+ \list
+ \i \c dateFormat
+ \i \c timeFormat
+ \i \c dateTimeFormat
+ \endlist
+
+ If only the format for date is defined, the time and dateTime formats will be defined
+ as the system locale default and likewise for the others.
+
+ Syntax for the format is based on the QDateTime::toString() formatting options.
+
+ \code
+ // Format the date such that the dateText is: '1997-12-12'
+ DateTimeFormatter { id: formatter; dateTime: Today.dateTime; formatDate: "yyyy-MM-d" }
+ \endcode
+
+ Assigning an empty string to a particular format will reset it.
+*/
+QString QmlDateTimeFormatter::dateTimeFormat() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->dateTimeFormat;
+}
+
+QString QmlDateTimeFormatter::dateFormat() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->dateFormat;
+}
+
+QString QmlDateTimeFormatter::timeFormat() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->timeFormat;
+}
+
+/*!
+ \qmlproperty bool DateTimeFormatter::longStyle
+
+ This property causes the formatter to use the system locale's long format rather than short format
+ by default.
+
+ This setting is off by default.
+*/
+bool QmlDateTimeFormatter::longStyle() const
+{
+ Q_D(const QmlDateTimeFormatter);
+ return d->longStyle;
+}
+
+void QmlDateTimeFormatter::setDateTime(const QDateTime &dateTime)
+{
+ Q_D(QmlDateTimeFormatter);
+ if (d->dateTime == dateTime)
+ return;
+ d->dateTime = dateTime;
+ d->date = d->dateTime.date();
+ d->time = d->dateTime.time();
+ d->updateText();
+}
+
+void QmlDateTimeFormatter::setTime(const QTime &time)
+{
+ Q_D(QmlDateTimeFormatter);
+ if (d->dateTime.time() == time)
+ return;
+ d->time = time;
+ d->dateTime.setTime(time);
+ d->updateText();
+}
+
+void QmlDateTimeFormatter::setDate(const QDate &date)
+{
+ Q_D(QmlDateTimeFormatter);
+ if (d->dateTime.date() == date)
+ return;
+ d->date = date;
+ bool clearTime = d->dateTime.time().isValid() ? false : true; //because setting date generates default time
+ d->dateTime.setDate(date);
+ if (clearTime)
+ d->dateTime.setTime(QTime());
+ d->updateText();
+}
+
+//DateTime formatting may be a combination of date and time?
+void QmlDateTimeFormatter::setDateTimeFormat(const QString &format)
+{
+ Q_D(QmlDateTimeFormatter);
+ //no format checking
+ d->dateTimeFormat = format;
+ d->updateText();
+}
+
+void QmlDateTimeFormatter::setDateFormat(const QString &format)
+{
+ Q_D(QmlDateTimeFormatter);
+ //no format checking
+ d->dateFormat = format;
+ d->updateText();
+}
+
+void QmlDateTimeFormatter::setTimeFormat(const QString &format)
+{
+ Q_D(QmlDateTimeFormatter);
+ //no format checking
+ d->timeFormat = format;
+ d->updateText();
+}
+
+void QmlDateTimeFormatter::setLongStyle(bool longStyle)
+{
+ Q_D(QmlDateTimeFormatter);
+ d->longStyle = longStyle;
+ d->updateText();
+}
+
+void QmlDateTimeFormatterPrivate::updateText()
+{
+ Q_Q(QmlDateTimeFormatter);
+ if (!componentComplete)
+ return;
+
+ QString str;
+ QString str1;
+ QString str2;
+
+ Qt::DateFormat defaultFormat = longStyle ? Qt::SystemLocaleLongDate : Qt::SystemLocaleShortDate;
+
+ if (dateFormat.isEmpty())
+ str1 = date.toString(defaultFormat);
+ else
+ str1 = date.toString(dateFormat);
+
+ if (timeFormat.isEmpty())
+ str2 = time.toString(defaultFormat);
+ else
+ str2 = time.toString(timeFormat);
+
+ if (dateTimeFormat.isEmpty())
+ str = dateTime.toString(defaultFormat);
+ //else if (!formatTime.isEmpty() && !formatDate.isEmpty())
+ // str = str1 + QLatin1Char(' ') + str2;
+ else
+ str = dateTime.toString(dateTimeFormat);
+
+ if (dateTimeText == str && dateText == str1 && timeText == str2)
+ return;
+
+ dateTimeText = str;
+ dateText = str1;
+ timeText = str2;
+
+ emit q->textChanged();
+}
+
+void QmlDateTimeFormatter::classBegin()
+{
+ Q_D(QmlDateTimeFormatter);
+ d->componentComplete = false;
+}
+
+void QmlDateTimeFormatter::componentComplete()
+{
+ Q_D(QmlDateTimeFormatter);
+ d->componentComplete = true;
+ d->updateText();
+}
+
+QML_DEFINE_TYPE(Qt,4,6,DateTimeFormatter,QmlDateTimeFormatter)
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmldatetimeformatter_p.h b/src/declarative/util/qmldatetimeformatter_p.h
new file mode 100644
index 0000000..c90ee8c
--- /dev/null
+++ b/src/declarative/util/qmldatetimeformatter_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLDATETIMEFORMATTER_H
+#define QMLDATETIMEFORMATTER_H
+
+#include <qml.h>
+
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlDateTimeFormatterPrivate;
+class Q_DECLARATIVE_EXPORT QmlDateTimeFormatter : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QmlParserStatus)
+
+ Q_PROPERTY(QString dateText READ dateText NOTIFY textChanged)
+ Q_PROPERTY(QString timeText READ timeText NOTIFY textChanged)
+ Q_PROPERTY(QString dateTimeText READ dateTimeText NOTIFY textChanged)
+ Q_PROPERTY(QDate date READ date WRITE setDate)
+ Q_PROPERTY(QTime time READ time WRITE setTime)
+ Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime)
+ Q_PROPERTY(QString dateFormat READ dateFormat WRITE setDateFormat)
+ Q_PROPERTY(QString timeFormat READ timeFormat WRITE setTimeFormat)
+ Q_PROPERTY(QString dateTimeFormat READ dateTimeFormat WRITE setDateTimeFormat)
+ Q_PROPERTY(bool longStyle READ longStyle WRITE setLongStyle)
+public:
+ QmlDateTimeFormatter(QObject *parent=0);
+ ~QmlDateTimeFormatter();
+
+ QString dateTimeText() const;
+ QString dateText() const;
+ QString timeText() const;
+
+ QDate date() const;
+ void setDate(const QDate &);
+
+ QTime time() const;
+ void setTime(const QTime &);
+
+ QDateTime dateTime() const;
+ void setDateTime(const QDateTime &);
+
+ QString dateTimeFormat() const;
+ void setDateTimeFormat(const QString &);
+
+ QString dateFormat() const;
+ void setDateFormat(const QString &);
+
+ QString timeFormat() const;
+ void setTimeFormat(const QString &);
+
+ bool longStyle() const;
+ void setLongStyle(bool);
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void textChanged();
+
+private:
+ Q_DISABLE_COPY(QmlDateTimeFormatter)
+ Q_DECLARE_PRIVATE(QmlDateTimeFormatter)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlDateTimeFormatter)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmleasefollow.cpp b/src/declarative/util/qmleasefollow.cpp
new file mode 100644
index 0000000..e3153b1
--- /dev/null
+++ b/src/declarative/util/qmleasefollow.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmleasefollow_p.h"
+
+#include "qmlanimation_p_p.h"
+
+#include <qmlmetaproperty.h>
+
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,EaseFollow,QmlEaseFollow);
+
+class QmlEaseFollowPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlEaseFollow)
+public:
+ QmlEaseFollowPrivate()
+ : source(0), velocity(200), duration(-1), maximumEasingTime(-1),
+ reversingMode(QmlEaseFollow::Eased), initialVelocity(0),
+ initialValue(0), invert(false), enabled(true), trackVelocity(0), clockOffset(0),
+ lastTick(0), clock(this)
+ {}
+
+ qreal source;
+ qreal velocity;
+ qreal duration;
+ qreal maximumEasingTime;
+ QmlEaseFollow::ReversingMode reversingMode;
+
+ qreal initialVelocity;
+ qreal initialValue;
+ bool invert;
+ bool enabled;
+
+ qreal trackVelocity;
+
+ QmlMetaProperty target;
+
+ int clockOffset;
+ int lastTick;
+ void tick(int);
+ void clockStart();
+ void clockStop();
+ QTickAnimationProxy<QmlEaseFollowPrivate, &QmlEaseFollowPrivate::tick> clock;
+
+ void restart();
+
+ // Parameters for use in tick()
+ qreal a; // Acceleration
+ qreal d; // Deceleration
+ qreal tf; // Total time
+ qreal tp; // Time at which peak velocity occurs
+ qreal td; // Time at which decelleration begins
+ qreal vp; // Velocity at tp
+ qreal sp; // Displacement at tp
+ qreal sd; // Displacement at td
+ qreal vi; // "Normalized" initialvelocity
+ bool recalc();
+};
+
+bool QmlEaseFollowPrivate::recalc()
+{
+ qreal s = source - initialValue;
+ vi = initialVelocity;
+
+ s = (invert?-1.0:1.0) * s;
+ vi = (invert?-1.0:1.0) * vi;
+
+ if (duration > 0 && velocity > 0) {
+ tf = s / velocity;
+ if (tf > (duration / 1000.)) tf = (duration / 1000.);
+ } else if (duration > 0) {
+ tf = duration / 1000.;
+ } else if (velocity > 0) {
+ tf = s / velocity;
+ } else {
+ return false;
+ }
+
+ if (maximumEasingTime == 0) {
+ a = 0;
+ d = 0;
+ tp = 0;
+ td = tf;
+ vp = velocity;
+ sp = 0;
+ sd = s;
+ } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) {
+
+ qreal met = maximumEasingTime / 1000.;
+ td = tf - met;
+
+ qreal c1 = td;
+ qreal c2 = (tf - td) * vi - tf * velocity;
+ qreal c3 = -0.5 * (tf - td) * vi * vi;
+
+ qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+ // qreal vp2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+
+ vp = vp1;
+ a = vp / met;
+ d = a;
+ tp = (vp - vi) / a;
+ sp = vi * tp + 0.5 * a * tp * tp;
+ sd = sp + (td - tp) * vp;
+ } else {
+
+ qreal c1 = 0.25 * tf * tf;
+ qreal c2 = 0.5 * vi * tf - s;
+ qreal c3 = -0.25 * vi * vi;
+
+ qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+ //qreal a2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
+
+ qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
+ //qreal tp2 = 0.5 * tf - 0.5 * vi / a2;
+ qreal vp1 = a1 * tp1 + vi;
+ //qreal vp2 = a2 * tp2 + vi;
+
+ qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
+ //qreal sp2 = 0.5 * a2 * tp2 * tp2 + vi * tp2;
+
+ a = a1;
+ d = a1;
+ tp = tp1;
+ td = tp1;
+ vp = vp1;
+ sp = sp1;
+ sd = sp1;
+ }
+
+ /*
+ qWarning() << "a:" << a << "tf:" << tf << "tp:" << tp << "vp:"
+ << vp << "sp:" << sp << "vi:" << vi << "invert:" << invert;
+ */
+ return true;
+}
+
+void QmlEaseFollowPrivate::clockStart()
+{
+ if (clock.state() == QAbstractAnimation::Running) {
+ clockOffset = lastTick;
+ return;
+ } else {
+ clockOffset = 0;
+ lastTick = 0;
+ clock.start();
+ }
+}
+
+void QmlEaseFollowPrivate::clockStop()
+{
+ clockOffset = 0;
+ lastTick = 0;
+ clock.stop();
+}
+
+void QmlEaseFollowPrivate::tick(int t)
+{
+ lastTick = t;
+ t -= clockOffset;
+
+ qreal time_seconds = qreal(t) / 1000.;
+
+ qreal out = 0;
+ if (time_seconds < tp) {
+
+ trackVelocity = vi + time_seconds * a;
+ trackVelocity = (invert?-1.0:1.0) * trackVelocity;
+
+ qreal value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
+ value = (invert?-1.0:1.0) * value;
+ target.write(initialValue + value);
+ out = initialValue + value;
+ } else if (time_seconds < td) {
+
+ time_seconds -= tp;
+ trackVelocity = (invert?-1.0:1.0) * vp;
+ qreal value = sp + time_seconds * vp;
+ value = (invert?-1.0:1.0) * value;
+
+ target.write(initialValue + value);
+
+ out = initialValue + value;
+ } else if (time_seconds < tf) {
+
+ time_seconds -= td;
+
+ trackVelocity = vp - time_seconds * a;
+ trackVelocity = (invert?-1.0:1.0) * trackVelocity;
+
+ qreal value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
+ value = (invert?-1.0:1.0) * value;
+
+ target.write(initialValue + value);
+
+ out = initialValue + value;
+ } else {
+
+ clock.stop();
+
+ trackVelocity = 0;
+ target.write(source);
+ }
+
+ //qWarning() << out << trackVelocity << t << a;
+}
+
+/*!
+ \qmlclass EaseFollow QmlEaseFollow
+ \brief The EaseFollow element allows a property to smoothly track a value.
+
+ The EaseFollow smoothly animates a property's value to a set target value
+ using an ease in/out quad easing curve. If the target value changes while
+ the animation is in progress, the easing curves used to animate to the old
+ and the new target values are spliced together to avoid any obvious visual
+ glitches.
+
+ The property animation is configured by setting the velocity at which the
+ animation should occur, or the duration that the animation should take.
+ If both a velocity and a duration are specified, the one that results in
+ the quickest animation is chosen for each change in the target value.
+
+ For example, animating from 0 to 800 will take 4 seconds if a velocity
+ of 200 is set, will take 8 seconds with a duration of 8000 set, and will
+ take 4 seconds with both a velocity of 200 and a duration of 8000 set.
+ Animating from 0 to 20000 will take 10 seconds if a velocity of 200 is set,
+ will take 8 seconds with a duration of 8000 set, and will take 8 seconds
+ with both a velocity of 200 and a duration of 8000 set.
+
+ The follow example shows one rectangle tracking the position of another.
+\code
+import Qt 4.6
+
+Rectangle {
+ width: 800; height: 600; color: "blue"
+
+ Rectangle {
+ color: "green"
+ width: 60; height: 60;
+ x: -5; y: -5;
+ x: EaseFollow { source: rect1.x - 5; velocity: 200 }
+ y: EaseFollow { source: rect1.y - 5; velocity: 200 }
+ }
+
+ Rectangle {
+ id: rect1
+ color: "red"
+ width: 50; height: 50;
+ }
+
+ focus: true
+ Keys.onRightPressed: rect1.x = rect1.x + 100
+ Keys.onLeftPressed: rect1.x = rect1.x - 100
+ Keys.onUpPressed: rect1.y = rect1.y - 100
+ Keys.onDownPressed: rect1.y = rect1.y + 100
+}
+\endcode
+
+ \sa SpringFollow
+*/
+
+QmlEaseFollow::QmlEaseFollow(QObject *parent)
+: QObject(*(new QmlEaseFollowPrivate), parent)
+{
+}
+
+QmlEaseFollow::~QmlEaseFollow()
+{
+}
+
+/*!
+ \qmlproperty qreal EaseFollow::source
+ This property holds the source value which will be tracked.
+
+ Bind to a property in order to track its changes.
+*/
+qreal QmlEaseFollow::sourceValue() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->source;
+}
+
+/*!
+ \qmlproperty enumeration EaseFollow::reversingMode
+
+ Sets how the EaseFollow behaves if an animation direction is reversed.
+
+ If reversing mode is \c Eased, the animation will smoothly decelerate, and
+ then reverse direction. If the reversing mode is \c Immediate, the
+ animation will immediately begin accelerating in the reverse direction,
+ begining with a velocity of 0. If the reversing mode is \c Sync, the
+ property is immediately set to the target value.
+*/
+QmlEaseFollow::ReversingMode QmlEaseFollow::reversingMode() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->reversingMode;
+}
+
+void QmlEaseFollow::setReversingMode(ReversingMode m)
+{
+ Q_D(QmlEaseFollow);
+ if (d->reversingMode == m)
+ return;
+
+ d->reversingMode = m;
+ emit reversingModeChanged();
+}
+
+void QmlEaseFollowPrivate::restart()
+{
+ if (!enabled || velocity == 0) {
+ clockStop();
+ return;
+ }
+
+ initialValue = target.read().toReal();
+
+ if (source == initialValue) {
+ clockStop();
+ return;
+ }
+
+ bool hasReversed = trackVelocity != 0. &&
+ ((trackVelocity > 0) == ((initialValue - source) > 0));
+
+ if (hasReversed) {
+ switch (reversingMode) {
+ default:
+ case QmlEaseFollow::Eased:
+ break;
+ case QmlEaseFollow::Sync:
+ target.write(source);
+ return;
+ case QmlEaseFollow::Immediate:
+ initialVelocity = 0;
+ clockStop();
+ break;
+ }
+ }
+
+ trackVelocity = initialVelocity;
+
+ invert = (source < initialValue);
+
+ if (!recalc()) {
+ target.write(source);
+ clockStop();
+ return;
+ }
+
+ clockStart();
+}
+
+void QmlEaseFollow::setSourceValue(qreal s)
+{
+ Q_D(QmlEaseFollow);
+
+ if (d->clock.state() == QAbstractAnimation::Running && d->source == s)
+ return;
+
+ d->source = s;
+ d->initialVelocity = d->trackVelocity;
+ d->restart();
+
+ emit sourceChanged();
+}
+
+/*!
+ \qmlproperty qreal EaseFollow::duration
+
+ This property holds the animation duration used when tracking the source.
+
+ Setting this to -1 disables the duration value.
+*/
+qreal QmlEaseFollow::duration() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->duration;
+}
+
+void QmlEaseFollow::setDuration(qreal v)
+{
+ Q_D(QmlEaseFollow);
+ if (d->duration == v)
+ return;
+
+ d->duration = v;
+ d->trackVelocity = 0;
+
+ if (d->clock.state() == QAbstractAnimation::Running)
+ d->restart();
+
+ emit durationChanged();
+}
+
+qreal QmlEaseFollow::velocity() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->velocity;
+}
+
+/*!
+ \qmlproperty qreal EaseFollow::velocity
+
+ This property holds the average velocity allowed when tracking the source.
+
+ Setting this to -1 disables the velocity value.
+*/
+void QmlEaseFollow::setVelocity(qreal v)
+{
+ Q_D(QmlEaseFollow);
+ if (d->velocity == v)
+ return;
+
+ d->velocity = v;
+ d->trackVelocity = 0;
+
+ if (d->clock.state() == QAbstractAnimation::Running)
+ d->restart();
+
+ emit velocityChanged();
+}
+
+/*!
+ \qmlproperty bool EaseFollow::enabled
+ This property holds whether the target will track the source.
+*/
+bool QmlEaseFollow::enabled() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->enabled;
+}
+
+void QmlEaseFollow::setEnabled(bool enabled)
+{
+ Q_D(QmlEaseFollow);
+ if (d->enabled == enabled)
+ return;
+
+ d->enabled = enabled;
+ if (enabled)
+ d->restart();
+ else
+ d->clockStop();
+
+ emit enabledChanged();
+}
+
+void QmlEaseFollow::setTarget(const QmlMetaProperty &t)
+{
+ Q_D(QmlEaseFollow);
+ d->target = t;
+}
+
+/*!
+\qmlproperty qreal EaseFollow::maximumEasingTime
+
+This property specifies the maximum time an "eases" during the follow should take.
+Setting this property causes the velocity to "level out" after at a time. Setting
+a negative value reverts to the normal mode of easing over the entire animation
+duration.
+
+The default value is -1.
+*/
+qreal QmlEaseFollow::maximumEasingTime() const
+{
+ Q_D(const QmlEaseFollow);
+ return d->maximumEasingTime;
+}
+
+void QmlEaseFollow::setMaximumEasingTime(qreal v)
+{
+ Q_D(QmlEaseFollow);
+ d->maximumEasingTime = v;
+
+ if (d->clock.state() == QAbstractAnimation::Running)
+ d->restart();
+
+ emit maximumEasingTimeChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmleasefollow_p.h b/src/declarative/util/qmleasefollow_p.h
new file mode 100644
index 0000000..ef095a3
--- /dev/null
+++ b/src/declarative/util/qmleasefollow_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLEASEFOLLOW_H
+#define QMLEASEFOLLOW_H
+
+#include <qml.h>
+#include <qmlpropertyvaluesource.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlMetaProperty;
+class QmlEaseFollowPrivate;
+class Q_DECLARATIVE_EXPORT QmlEaseFollow : public QObject,
+ public QmlPropertyValueSource
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlEaseFollow)
+ Q_INTERFACES(QmlPropertyValueSource)
+ Q_ENUMS(ReversingMode)
+
+ Q_PROPERTY(qreal source READ sourceValue WRITE setSourceValue NOTIFY sourceChanged)
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(qreal duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged)
+
+public:
+ enum ReversingMode { Eased, Immediate, Sync };
+
+ QmlEaseFollow(QObject *parent = 0);
+ ~QmlEaseFollow();
+
+ ReversingMode reversingMode() const;
+ void setReversingMode(ReversingMode);
+
+ qreal sourceValue() const;
+ void setSourceValue(qreal);
+
+ qreal velocity() const;
+ void setVelocity(qreal);
+
+ qreal duration() const;
+ void setDuration(qreal);
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ qreal maximumEasingTime() const;
+ void setMaximumEasingTime(qreal);
+
+ virtual void setTarget(const QmlMetaProperty &);
+
+Q_SIGNALS:
+ void sourceChanged();
+ void velocityChanged();
+ void durationChanged();
+ void reversingModeChanged();
+ void enabledChanged();
+ void maximumEasingTimeChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlEaseFollow);
+
+QT_END_HEADER
+
+#endif // QMLEASEFOLLOW_H
diff --git a/src/declarative/util/qmlfontloader.cpp b/src/declarative/util/qmlfontloader.cpp
new file mode 100644
index 0000000..b56043b
--- /dev/null
+++ b/src/declarative/util/qmlfontloader.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlfontloader_p.h"
+
+#include <qmlcontext.h>
+#include <qmlengine.h>
+
+#include <QUrl>
+#include <QDebug>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QFile>
+#include <QFontDatabase>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlFontLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlFontLoader)
+
+public:
+ QmlFontLoaderPrivate() : reply(0), status(QmlFontLoader::Null) {}
+
+ void addFontToDatabase(const QByteArray &);
+
+ QUrl url;
+ QString name;
+ QNetworkReply *reply;
+ QmlFontLoader::Status status;
+};
+
+QML_DEFINE_TYPE(Qt,4,6,FontLoader,QmlFontLoader)
+
+/*!
+ \qmlclass FontLoader QmlFontLoader
+ \ingroup group_utility
+ \brief This item allows using fonts by name or url.
+
+ Example:
+ \qml
+ FontLoader { id: fixedFont; name: "Courier" }
+ FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
+
+ Text { text: "Fixed-size font"; font.family: fixedFont.name }
+ Text { text: "Fancy font"; font.family: webFont.name }
+ \endqml
+*/
+QmlFontLoader::QmlFontLoader(QObject *parent)
+ : QObject(*(new QmlFontLoaderPrivate), parent)
+{
+}
+
+QmlFontLoader::~QmlFontLoader()
+{
+}
+
+static QString toLocalFileOrQrc(const QUrl& url)
+{
+ QString r = url.toLocalFile();
+ if (r.isEmpty() && url.scheme() == QLatin1String("qrc"))
+ r = QLatin1Char(':') + url.path();
+ return r;
+}
+
+
+/*!
+ \qmlproperty url FontLoader::source
+ The url of the font to load.
+*/
+QUrl QmlFontLoader::source() const
+{
+ Q_D(const QmlFontLoader);
+ return d->url;
+}
+
+void QmlFontLoader::setSource(const QUrl &url)
+{
+ Q_D(QmlFontLoader);
+ if (url == d->url)
+ return;
+ d->url = qmlContext(this)->resolvedUrl(url);
+
+ d->status = Loading;
+ emit statusChanged();
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = toLocalFileOrQrc(d->url);
+ if (!lf.isEmpty()) {
+ int id = QFontDatabase::addApplicationFont(lf);
+ if (id != -1) {
+ d->name = QFontDatabase::applicationFontFamilies(id).at(0);
+ emit nameChanged();
+ d->status = QmlFontLoader::Ready;
+ } else {
+ d->status = QmlFontLoader::Error;
+ qWarning() << "Cannot load font:" << url;
+ }
+ emit statusChanged();
+ } else
+#endif
+ {
+ QNetworkRequest req(d->url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ d->reply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+ }
+}
+
+/*!
+ \qmlproperty string FontLoader::name
+
+ This property holds the name of the font family.
+ It is set automatically when a font is loaded using the \c url property.
+
+ Use this to set the \c font.family property of a \c Text item.
+
+ Example:
+ \qml
+ FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
+ Text { text: "Fancy font"; font.family: webFont.name }
+ \endqml
+*/
+QString QmlFontLoader::name() const
+{
+ Q_D(const QmlFontLoader);
+ return d->name;
+}
+
+void QmlFontLoader::setName(const QString &name)
+{
+ Q_D(QmlFontLoader);
+ if (d->name == name )
+ return;
+ d->name = name;
+ emit nameChanged();
+ d->status = Ready;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enum FontLoader::status
+
+ This property holds the status of font loading. It can be one of:
+ \list
+ \o Null - no font has been set
+ \o Ready - the font has been loaded
+ \o Loading - the font is currently being loaded
+ \o Error - an error occurred while loading the font
+ \endlist
+*/
+QmlFontLoader::Status QmlFontLoader::status() const
+{
+ Q_D(const QmlFontLoader);
+ return d->status;
+}
+
+void QmlFontLoader::replyFinished()
+{
+ Q_D(QmlFontLoader);
+ if (d->reply) {
+ if (!d->reply->error()) {
+ QByteArray ba = d->reply->readAll();
+ d->addFontToDatabase(ba);
+ } else {
+ d->status = Error;
+ emit statusChanged();
+ }
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+}
+
+void QmlFontLoaderPrivate::addFontToDatabase(const QByteArray &ba)
+{
+ Q_Q(QmlFontLoader);
+
+ int id = QFontDatabase::addApplicationFontFromData(ba);
+ if (id != -1) {
+ name = QFontDatabase::applicationFontFamilies(id).at(0);
+ emit q->nameChanged();
+ status = QmlFontLoader::Ready;
+ } else {
+ status = QmlFontLoader::Error;
+ qWarning() << "Cannot load font:" << url;
+ }
+ emit q->statusChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlfontloader_p.h b/src/declarative/util/qmlfontloader_p.h
new file mode 100644
index 0000000..aac8a71
--- /dev/null
+++ b/src/declarative/util/qmlfontloader_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLFONTLOADER_H
+#define QMLFONTLOADER_H
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlFontLoaderPrivate;
+class Q_DECLARATIVE_EXPORT QmlFontLoader : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlFontLoader)
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+
+public:
+ enum Status { Null = 0, Ready, Loading, Error };
+
+ QmlFontLoader(QObject *parent = 0);
+ ~QmlFontLoader();
+
+ QUrl source() const;
+ void setSource(const QUrl &url);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ Status status() const;
+
+private Q_SLOTS:
+ void replyFinished();
+
+Q_SIGNALS:
+ void nameChanged();
+ void statusChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlFontLoader)
+
+QT_END_HEADER
+
+#endif // QMLFONTLOADER_H
+
diff --git a/src/declarative/util/qmllistaccessor.cpp b/src/declarative/util/qmllistaccessor.cpp
new file mode 100644
index 0000000..e060097
--- /dev/null
+++ b/src/declarative/util/qmllistaccessor.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmllistaccessor_p.h"
+
+#include <qmlmetatype.h>
+
+#include <QStringList>
+#include <QtCore/qdebug.h>
+
+// ### Remove me
+#include <qmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QmlListAccessor::QmlListAccessor()
+: m_type(Invalid)
+{
+}
+
+QmlListAccessor::~QmlListAccessor()
+{
+}
+
+QVariant QmlListAccessor::list() const
+{
+ return d;
+}
+
+void QmlListAccessor::setList(const QVariant &v, QmlEngine *engine)
+{
+ d = v;
+
+ QmlEnginePrivate *enginePrivate = engine?QmlEnginePrivate::get(engine):0;
+
+ if (!d.isValid()) {
+ m_type = Invalid;
+ } else if (d.userType() == QVariant::StringList) {
+ m_type = StringList;
+ } else if (d.userType() == QMetaType::QVariantList) {
+ m_type = VariantList;
+ } else if (d.canConvert(QVariant::Int)) {
+ m_type = Integer;
+ } else if ((!enginePrivate && QmlMetaType::isObject(d.userType())) ||
+ (enginePrivate && enginePrivate->isObject(d.userType()))) {
+ QObject *data = 0;
+ data = *(QObject **)v.constData();
+ d = QVariant::fromValue(data);
+ m_type = Instance;
+ } else if ((!enginePrivate && QmlMetaType::isQmlList(d.userType())) ||
+ (enginePrivate && enginePrivate->isQmlList(d.userType()))) {
+ m_type = QmlList;
+ } else if (QmlMetaType::isList(d.userType())) {
+ m_type = ListProperty;
+ } else {
+ m_type = Instance;
+ }
+}
+
+int QmlListAccessor::count() const
+{
+ switch(m_type) {
+ case StringList:
+ return qvariant_cast<QStringList>(d).count();
+ case VariantList:
+ return qvariant_cast<QVariantList>(d).count();
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ return li->count();
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->count) return li->count(li);
+ else return 0;
+ }
+ case Instance:
+ return 1;
+ case Integer:
+ return d.toInt();
+ default:
+ case Invalid:
+ return 0;
+ }
+}
+
+QVariant QmlListAccessor::at(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < count());
+ switch(m_type) {
+ case StringList:
+ return QVariant::fromValue(qvariant_cast<QStringList>(d).at(idx));
+ case VariantList:
+ return qvariant_cast<QVariantList>(d).at(idx);
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ void *ptr[1];
+ li->at(idx, ptr);
+ return QVariant::fromValue((QObject*)ptr[0]);
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->at) return QVariant::fromValue((QObject *)li->at(li, idx));
+ else return QVariant();
+ }
+ case Instance:
+ return d;
+ case Integer:
+ return QVariant(idx);
+ default:
+ case Invalid:
+ return QVariant();
+ }
+}
+
+bool QmlListAccessor::append(const QVariant &value)
+{
+ switch(m_type) {
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ li->append(const_cast<void *>(value.constData())); //XXX Typesafety
+ return true;
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->append) li->append(li, *(void **)value.constData()); // XXX Typesafety
+ return true;
+ }
+ case StringList:
+ case VariantList:
+ case Invalid:
+ case Instance:
+ case Integer:
+ default:
+ return false;
+ }
+}
+
+bool QmlListAccessor::insert(int index, const QVariant &value)
+{
+ switch(m_type) {
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ li->insert(index, const_cast<void *>(value.constData())); //XXX Typesafety
+ return true;
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->insert) li->insert(li, index, *(void **)value.constData()); // XXX Typesafety
+ return true;
+ }
+ case StringList:
+ case VariantList:
+ case Invalid:
+ case Instance:
+ case Integer:
+ default:
+ return false;
+ }
+}
+
+bool QmlListAccessor::removeAt(int index)
+{
+ switch(m_type) {
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ li->removeAt(index);
+ return true;
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->removeAt) li->removeAt(li, index);
+ return true;
+ }
+ case StringList:
+ case VariantList:
+ case Invalid:
+ case Instance:
+ case Integer:
+ default:
+ return false;
+ }
+}
+
+bool QmlListAccessor::clear()
+{
+ switch(m_type) {
+ case QmlList:
+ {
+ QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)d.constData();
+ li->clear();
+ return true;
+ }
+ case ListProperty:
+ {
+ QmlListProperty<void> *li = (QmlListProperty<void>*)d.constData();
+ if (li->clear) li->clear(li);
+ return true;
+ }
+ case StringList:
+ case VariantList:
+ case Invalid:
+ case Instance:
+ case Integer:
+ default:
+ return false;
+ }
+}
+
+bool QmlListAccessor::isValid() const
+{
+ return m_type != Invalid;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmllistaccessor_p.h b/src/declarative/util/qmllistaccessor_p.h
new file mode 100644
index 0000000..6866150
--- /dev/null
+++ b/src/declarative/util/qmllistaccessor_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLLISTACCESSOR_H
+#define QMLLISTACCESSOR_H
+
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlEngine;
+class Q_DECLARATIVE_EXPORT QmlListAccessor
+{
+public:
+ QmlListAccessor();
+ ~QmlListAccessor();
+
+ QVariant list() const;
+ void setList(const QVariant &, QmlEngine * = 0);
+
+ bool isValid() const;
+
+ int count() const;
+ QVariant at(int) const;
+
+ bool append(const QVariant &);
+ bool insert(int, const QVariant &);
+ bool removeAt(int);
+ bool clear();
+
+ enum Type { Invalid, StringList, VariantList, QmlList, ListProperty, Instance, Integer };
+ Type type() const { return m_type; }
+
+private:
+ Type m_type;
+ QVariant d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLLISTACCESSOR_H
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
new file mode 100644
index 0000000..0b19574
--- /dev/null
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -0,0 +1,991 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmllistmodel_p.h"
+
+#include "qmlopenmetaobject_p.h"
+
+#include <qmlcustomparser_p.h>
+#include <qmlparser_p.h>
+#include <qmlengine_p.h>
+#include <qmlcontext.h>
+#include <qmlinfo.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstack.h>
+#include <QXmlStreamReader>
+#include <QtScript/qscriptvalueiterator.h>
+
+Q_DECLARE_METATYPE(QListModelInterface *)
+
+QT_BEGIN_NAMESPACE
+
+#define DATA_ROLE_ID 1
+#define DATA_ROLE_NAME "data"
+
+struct ListInstruction
+{
+ enum { Push, Pop, Value, Set } type;
+ int dataIdx;
+};
+
+struct ListModelData
+{
+ int dataOffset;
+ int instrCount;
+ ListInstruction *instructions() const { return (ListInstruction *)((char *)this + sizeof(ListModelData)); }
+};
+
+static void dump(ModelNode *node, int ind);
+
+/*!
+ \qmlclass ListModel QmlListModel
+ \brief The ListModel element defines a free-form list data source.
+
+ The ListModel is a simple hierarchy of elements containing data roles. The contents can
+ be defined dynamically, or explicitly in QML:
+
+ For example:
+
+ \code
+ ListModel {
+ id: fruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3.25
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ }
+ }
+ \endcode
+
+ Roles (properties) must begin with a lower-case letter. The above example defines a
+ ListModel containing three elements, with the roles "name" and "cost".
+
+ The defined model can be used in views such as ListView:
+ \code
+ Component {
+ id: fruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+ }
+ }
+
+ ListView {
+ model: fruitModel
+ delegate: fruitDelegate
+ anchors.fill: parent
+ }
+ \endcode
+
+ It is possible for roles to contain list data. In the example below we create a list of fruit attributes:
+
+ \code
+ ListModel {
+ id: fruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ attributes: [
+ ListElement { description: "Core" },
+ ListElement { description: "Deciduous" }
+ ]
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3.25
+ attributes: [
+ ListElement { description: "Citrus" }
+ ]
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ attributes: [
+ ListElement { description: "Tropical" },
+ ListElement { description: "Seedless" }
+ ]
+ }
+ }
+ \endcode
+
+ The delegate below will list all the fruit attributes:
+ \code
+ Component {
+ id: fruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { id: name; text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+ Row {
+ anchors.top: name.bottom
+ spacing: 5
+ Text { text: "Attributes:" }
+ Repeater {
+ dataSource: attributes
+ Component { Text { text: description } }
+ }
+ }
+ }
+ }
+ \endcode
+
+ The content of a ListModel may be created and modified using the clear(),
+ append(), and set() methods. For example:
+
+ \code
+ Component {
+ id: fruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+
+ // Double the price when clicked.
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: fruitModel.set(index, "cost", cost*2)
+ }
+ }
+ }
+ \endcode
+
+ When creating content dynamically, note that the set of available properties cannot be changed
+ except by first clearing the model - whatever properties are first added are then the
+ only permitted properties in the model.
+
+ \sa {qmlmodels}{Data Models}
+*/
+
+class ModelObject : public QObject
+{
+ Q_OBJECT
+public:
+ ModelObject();
+
+ void setValue(const QByteArray &name, const QVariant &val)
+ {
+ _mo->setValue(name, val);
+ }
+
+private:
+ QmlOpenMetaObject *_mo;
+};
+
+struct ModelNode
+{
+ ModelNode();
+ ~ModelNode();
+
+ QList<QVariant> values;
+ QHash<QString, ModelNode *> properties;
+
+ QmlListModel *model(const QmlListModel *parent) {
+ if (!modelCache) {
+ modelCache = new QmlListModel;
+ QmlEngine::setContextForObject(modelCache,QmlEngine::contextForObject(parent));
+
+ modelCache->_root = this;
+ }
+ return modelCache;
+ }
+
+ ModelObject *object(const QmlListModel *parent) {
+ if (!objectCache) {
+ objectCache = new ModelObject();
+ QHash<QString, ModelNode *>::iterator it;
+ for (it = properties.begin(); it != properties.end(); ++it) {
+ objectCache->setValue(it.key().toUtf8(), parent->valueForNode(*it));
+ }
+ }
+ return objectCache;
+ }
+
+ void setObjectValue(const QScriptValue& valuemap);
+ void setListValue(const QScriptValue& valuelist);
+
+ 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);
+ }
+
+ QmlListModel *modelCache;
+ ModelObject *objectCache;
+ bool isArray;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(ModelNode *)
+
+QT_BEGIN_NAMESPACE
+
+void ModelNode::setObjectValue(const QScriptValue& valuemap) {
+ QScriptValueIterator it(valuemap);
+ while (it.hasNext()) {
+ it.next();
+ ModelNode *value = new ModelNode;
+ QScriptValue v = it.value();
+ if (v.isArray()) {
+ value->isArray = true;
+ value->setListValue(v);
+ } else {
+ value->values << v.toVariant();
+ }
+ 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));
+
+ }
+}
+
+
+ModelObject::ModelObject()
+: _mo(new QmlOpenMetaObject(this))
+{
+}
+
+QmlListModel::QmlListModel(QObject *parent)
+: QListModelInterface(parent), _rolesOk(false), _root(0)
+{
+}
+
+QmlListModel::~QmlListModel()
+{
+ delete _root;
+}
+
+void QmlListModel::checkRoles() const
+{
+ if (_rolesOk || !_root)
+ return;
+
+ 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);
+ }
+ }
+
+ _rolesOk = true;
+}
+
+void QmlListModel::addRole(const QString &role) const
+{
+ if (!roleStrings.contains(role))
+ roleStrings << role;
+}
+
+QList<int> QmlListModel::roles() const
+{
+ checkRoles();
+ QList<int> rv;
+ for (int ii = 0; ii < roleStrings.count(); ++ii)
+ rv << ii;
+ return rv;
+}
+
+QString QmlListModel::toString(int role) const
+{
+ checkRoles();
+ if (role < roleStrings.count())
+ return roleStrings.at(role);
+ else
+ return QString();
+}
+
+QVariant QmlListModel::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();
+}
+
+QHash<int,QVariant> QmlListModel::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 rv;
+}
+
+QVariant QmlListModel::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 rv;
+}
+
+/*!
+ \qmlproperty int ListModel::count
+ The number of data entries in the model.
+*/
+int QmlListModel::count() const
+{
+ if (!_root) return 0;
+ return _root->values.count();
+}
+
+/*!
+ \qmlmethod ListModel::clear()
+
+ Deletes all content from the model. The properties are cleared such that
+ different properties may be set on subsequent additions.
+
+ \sa append() remove()
+*/
+void QmlListModel::clear()
+{
+ int cleared = count();
+ _rolesOk = false;
+ delete _root;
+ _root = 0;
+ roleStrings.clear();
+ emit itemsRemoved(0,cleared);
+ emit countChanged(0);
+}
+
+/*!
+ \qmlmethod ListModel::remove(int index)
+
+ Deletes the content at \a index from the model.
+
+ \sa clear()
+*/
+void QmlListModel::remove(int index)
+{
+ if (!_root || index < 0 || index >= _root->values.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());
+}
+
+/*!
+ \qmlmethod ListModel::insert(int index, jsobject dict)
+
+ Adds a new item to the list model at position \a index, with the
+ values in \a dict.
+
+ \code
+ FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be to an existing item in the list, or one past
+ the end of the list (equivalent to append).
+
+ \sa set() append()
+*/
+void QmlListModel::insert(int index, const QScriptValue& valuemap)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ 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);
+ return;
+ }
+ ModelNode *mn = new ModelNode;
+ mn->setObjectValue(valuemap);
+ _root->values.insert(index,qVariantFromValue(mn));
+ emit itemsInserted(index,1);
+ emit countChanged(_root->values.count());
+}
+
+/*!
+ \qmlmethod ListModel::move(int from, int to, int n)
+
+ Moves \a n items \a from one position \a to another.
+
+ The from and to ranges must exist; for example, to move the first 3 items
+ to the end of the list:
+
+ \code
+ FruitModel.move(0,FruitModel.count-3,3)
+ \endcode
+
+ \sa append()
+*/
+void QmlListModel::move(int from, int to, int n)
+{
+ if (n==0 || from==to)
+ return;
+ if (from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0) {
+ 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;
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ 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);
+}
+
+/*!
+ \qmlmethod ListModel::append(jsobject dict)
+
+ Adds a new item to the end of the list model, with the
+ values in \a dict.
+
+ \code
+ FruitModel.append({"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ \sa set() remove()
+*/
+void QmlListModel::append(const QScriptValue& valuemap)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ 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());
+}
+
+/*!
+ \qmlmethod object ListModel::get(int index)
+
+ Returns the item at \a index in the list model.
+
+ \code
+ FruitModel.append({"cost": 5.95, "name":"Jackfruit"})
+ FruitModel.get(0).cost
+ \endcode
+
+ The \a index must be an element in the list.
+
+ Note that properties of the returned object that are themselves objects
+ will also be models, and this get() method is used to access elements:
+
+ \code
+ FruitModel.append(..., "attributes":
+ [{"name":"spikes","value":"7mm"},
+ {"name":"color","value":"green"}]);
+ FruitModel.get(0).attributes.get(1).value; // == "green"
+ \endcode
+
+ \sa append()
+*/
+QScriptValue QmlListModel::get(int index) const
+{
+ if (index >= count() || index < 0) {
+ qmlInfo(this) << tr("get: index %1 out of range").arg(index);
+ return 0;
+ }
+
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ if (!node)
+ return 0;
+ QmlEngine *eng = qmlEngine(this);
+ if (!eng) {
+ qWarning("Cannot call QmlListModel::get() without a QmlEngine");
+ return 0;
+ }
+ return QmlEnginePrivate::qmlScriptObject(node->object(this), eng);
+}
+
+/*!
+ \qmlmethod ListModel::set(int index, jsobject dict)
+
+ Changes the item at \a index in the list model with the
+ values in \a dict. Properties not appearing in \a valuemap
+ are left unchanged.
+
+ \code
+ FruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ The \a index must be an element in the list.
+
+ \sa append()
+*/
+void QmlListModel::set(int index, const QScriptValue& valuemap)
+{
+ if (!valuemap.isObject() || valuemap.isArray()) {
+ qmlInfo(this) << tr("set: value is not an object");
+ return;
+ }
+ if ( !_root || index > _root->values.count() || index < 0) {
+ qmlInfo(this) << tr("set: index %1 out of range").arg(index);
+ return;
+ }
+ if (index == _root->values.count())
+ append(valuemap);
+ else {
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ 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);
+ }
+}
+
+/*!
+ \qmlmethod ListModel::setProperty(int index, string property, variant value)
+
+ Changes the \a property of the item at \a index in the list model to \a value.
+
+ \code
+ FruitModel.set(3, "cost", 5.95)
+ \endcode
+
+ The \a index must be an element in the list.
+
+ \sa append()
+*/
+void QmlListModel::setProperty(int index, const QString& property, const QVariant& value)
+{
+ if ( !_root || index >= _root->values.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 (node)
+ node->setProperty(property,value);
+ emit itemsChanged(index,1,roles);
+}
+
+class QmlListModelParser : public QmlCustomParser
+{
+public:
+ QByteArray compile(const QList<QmlCustomParserProperty> &);
+ bool compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data);
+ void setCustomData(QObject *, const QByteArray &);
+
+private:
+ bool definesEmptyList(const QString &);
+};
+
+bool QmlListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data)
+{
+ QList<QVariant> values = prop.assignedValues();
+ for(int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if(value.userType() == qMetaTypeId<QmlCustomParserNode>()) {
+ QmlCustomParserNode node =
+ qvariant_cast<QmlCustomParserNode>(value);
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Push;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ QList<QmlCustomParserProperty> props = node.properties();
+ for(int jj = 0; jj < props.count(); ++jj) {
+ const QmlCustomParserProperty &nodeProp = props.at(jj);
+ if (nodeProp.name() == "") {
+ error(nodeProp, QmlListModel::tr("ListElement: cannot use default property"));
+ return false;
+ }
+ if (nodeProp.name() == "id") {
+ error(nodeProp, QmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
+ return false;
+ }
+
+ ListInstruction li;
+ int ref = data.count();
+ data.append(nodeProp.name());
+ data.append('\0');
+ li.type = ListInstruction::Set;
+ li.dataIdx = ref;
+ instr << li;
+
+ if(!compileProperty(nodeProp, instr, data))
+ return false;
+
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ } else {
+
+ QmlParser::Variant variant =
+ qvariant_cast<QmlParser::Variant>(value);
+
+ int ref = data.count();
+ QByteArray d = variant.asScript().toUtf8();
+ d.append('\0');
+ data.append(d);
+
+ ListInstruction li;
+ li.type = ListInstruction::Value;
+ li.dataIdx = ref;
+ instr << li;
+
+ }
+ }
+
+ return true;
+}
+
+QByteArray QmlListModelParser::compile(const QList<QmlCustomParserProperty> &customProps)
+{
+ QList<ListInstruction> instr;
+ QByteArray data;
+
+ for(int ii = 0; ii < customProps.count(); ++ii) {
+ const QmlCustomParserProperty &prop = customProps.at(ii);
+ if(prop.name() != "") { // isn't default property
+ error(prop, QmlListModel::tr("ListModel: undefined property '%1'").arg(QString::fromUtf8(prop.name())));
+ return QByteArray();
+ }
+
+ if(!compileProperty(prop, instr, data)) {
+ return QByteArray();
+ }
+ }
+
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
+ data.count();
+
+ QByteArray rv;
+ rv.resize(size);
+
+ ListModelData *lmd = (ListModelData *)rv.data();
+ lmd->dataOffset = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction);
+ lmd->instrCount = instr.count();
+ for (int ii = 0; ii < instr.count(); ++ii)
+ lmd->instructions()[ii] = instr.at(ii);
+ ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
+
+ return rv;
+}
+
+void QmlListModelParser::setCustomData(QObject *obj, const QByteArray &d)
+{
+ QmlListModel *rv = static_cast<QmlListModel *>(obj);
+
+ ModelNode *root = new ModelNode;
+ rv->_root = root;
+ QStack<ModelNode *> nodes;
+ nodes << root;
+
+ bool processingSet = false;
+
+ const ListModelData *lmd = (const ListModelData *)d.constData();
+ const char *data = ((const char *)lmd) + lmd->dataOffset;
+
+ for (int ii = 0; ii < lmd->instrCount; ++ii) {
+ const ListInstruction &instr = lmd->instructions()[ii];
+
+ switch(instr.type) {
+ case ListInstruction::Push:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode;
+ n->values << qVariantFromValue(n2);
+ nodes.push(n2);
+ if (processingSet)
+ n->isArray = true;
+ }
+ break;
+
+ case ListInstruction::Pop:
+ nodes.pop();
+ break;
+
+ case ListInstruction::Value:
+ {
+ ModelNode *n = nodes.top();
+ QString s = QString::fromUtf8(QByteArray(data + instr.dataIdx));
+
+ bool isEmptyList = false;
+ if (!n->isArray)
+ isEmptyList = definesEmptyList(s);
+ if (isEmptyList)
+ n->isArray = true;
+ else
+ n->values.append(s);
+
+ processingSet = false;
+ }
+ break;
+
+ case ListInstruction::Set:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode;
+ n->properties.insert(QString::fromUtf8(data + instr.dataIdx), n2);
+ nodes.push(n2);
+ processingSet = true;
+ }
+ break;
+ }
+ }
+}
+
+bool QmlListModelParser::definesEmptyList(const QString &s)
+{
+ if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
+ bool isEmptyList = true;
+ for (int i=1; i<s.length()-1; i++) {
+ if (!s[i].isSpace())
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+QML_DEFINE_CUSTOM_TYPE(Qt, 4,6, ListModel, QmlListModel, QmlListModelParser)
+
+/*!
+ \qmlclass ListElement
+ \brief The ListElement element defines a data item in a ListModel.
+
+ \sa ListModel
+*/
+// ### FIXME
+class QmlListElement : public QObject
+{
+Q_OBJECT
+};
+QML_DEFINE_TYPE(Qt,4,6,ListElement,QmlListElement)
+
+static void dump(ModelNode *node, int ind)
+{
+ QByteArray indentBa(ind * 4, ' ');
+ const char *indent = indentBa.constData();
+
+ for (int ii = 0; ii < node->values.count(); ++ii) {
+ ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(ii));
+ if (subNode) {
+ qWarning().nospace() << indent << "Sub-node " << ii;
+ dump(subNode, ind + 1);
+ } else {
+ qWarning().nospace() << indent << "Sub-node " << ii << ": " << node->values.at(ii).toString();
+ }
+ }
+
+ for (QHash<QString, ModelNode *>::ConstIterator iter = node->properties.begin(); iter != node->properties.end(); ++iter) {
+ qWarning().nospace() << indent << "Property " << iter.key() << ':';
+ dump(iter.value(), ind + 1);
+ }
+}
+
+ModelNode::ModelNode()
+: modelCache(0), objectCache(0), isArray(false)
+{
+}
+
+ModelNode::~ModelNode()
+{
+ 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; }
+}
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlListElement)
+
+#include <qmllistmodel.moc>
diff --git a/src/declarative/util/qmllistmodel_p.h b/src/declarative/util/qmllistmodel_p.h
new file mode 100644
index 0000000..e18d3fd
--- /dev/null
+++ b/src/declarative/util/qmllistmodel_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLLISTMODEL_H
+#define QMLLISTMODEL_H
+
+#include <qml.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include "../3rdparty/qlistmodelinterface_p.h"
+#include <QtScript/qscriptvalue.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct ModelNode;
+class Q_DECLARATIVE_EXPORT QmlListModel : public QListModelInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+
+public:
+ QmlListModel(QObject *parent=0);
+ ~QmlListModel();
+
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+ virtual int count() const;
+ virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const;
+ virtual QVariant data(int index, int role) const;
+
+ Q_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_SIGNALS:
+ void countChanged(int);
+
+private:
+ QVariant valueForNode(ModelNode *) const;
+ mutable QStringList roleStrings;
+ friend class QmlListModelParser;
+ friend struct ModelNode;
+
+ void checkRoles() const;
+ void addRole(const QString &) const;
+ mutable bool _rolesOk;
+ ModelNode *_root;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlListModel)
+
+QT_END_HEADER
+
+#endif // QMLLISTMODEL_H
diff --git a/src/declarative/util/qmlnullablevalue_p_p.h b/src/declarative/util/qmlnullablevalue_p_p.h
new file mode 100644
index 0000000..151a3d4
--- /dev/null
+++ b/src/declarative/util/qmlnullablevalue_p_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLNULLABLEVALUE_P_H
+#define QMLNULLABLEVALUE_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+struct QmlNullableValue
+{
+ QmlNullableValue()
+ : isNull(true), value(T()) {}
+ QmlNullableValue(const QmlNullableValue<T> &o)
+ : isNull(o.isNull), value(o.value) {}
+ QmlNullableValue(const T &t)
+ : isNull(false), value(t) {}
+ QmlNullableValue<T> &operator=(const T &t)
+ { isNull = false; value = t; return *this; }
+ QmlNullableValue<T> &operator=(const QmlNullableValue<T> &o)
+ { isNull = o.isNull; value = o.value; return *this; }
+ operator T() const { return value; }
+
+ void invalidate() { isNull = true; }
+ bool isValid() const { return !isNull; }
+ bool isNull;
+ T value;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLNULLABLEVALUE_P_H
diff --git a/src/declarative/util/qmlnumberformatter.cpp b/src/declarative/util/qmlnumberformatter.cpp
new file mode 100644
index 0000000..073dc68
--- /dev/null
+++ b/src/declarative/util/qmlnumberformatter.cpp
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlnumberformatter_p.h"
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//TODO: set locale
+// docs
+// this is a wrapper around qnumberformat (test integration)
+// if number or format haven't been explictly set, text should be an empty string
+
+class QmlNumberFormatterPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlNumberFormatter)
+public:
+ QmlNumberFormatterPrivate() : locale(QLocale::system()), number(0), componentComplete(true) {}
+
+ void updateText();
+
+ QLocale locale;
+ QString format;
+ QNumberFormat numberFormat;
+ QString text;
+ qreal number;
+ bool componentComplete;
+};
+/*!
+ \qmlclass NumberFormatter
+ \brief The NumberFormatter allows you to control the format of a number string.
+
+ The format property documentation has more details on how the format can be manipulated.
+
+ In the following example, the text element will display the text "1,234.57".
+ \code
+ NumberFormatter { id: formatter; number: 1234.5678; format: "##,##0.##" }
+ Text { text: formatter.text }
+ \endcode
+
+ */
+/*!
+ \internal
+ \class QmlNumberFormatter
+ \ingroup group_utility
+ \brief The QmlNumberFormatter class allows you to format a number to a particular string format/locale specific number format.
+*/
+
+QmlNumberFormatter::QmlNumberFormatter(QObject *parent)
+: QObject(*(new QmlNumberFormatterPrivate), parent)
+{
+}
+
+QmlNumberFormatter::~QmlNumberFormatter()
+{
+}
+
+/*!
+ \qmlproperty string NumberFormatter::text
+
+ The number in the specified format.
+
+ If no format is specified the text will be empty.
+*/
+
+QString QmlNumberFormatter::text() const
+{
+ Q_D(const QmlNumberFormatter);
+ return d->text;
+}
+
+/*!
+ \qmlproperty real NumberFormatter::number
+
+ A single point precision number. (Doubles are not yet supported)
+
+*/
+qreal QmlNumberFormatter::number() const
+{
+ Q_D(const QmlNumberFormatter);
+ return d->number;
+}
+
+/*!
+ \qmlproperty string NumberFormatter::format
+
+ The particular format the number will adhere to during the conversion to text.
+
+ The format syntax follows a style similar to the Unicode Standard (UTS35).
+
+ The table below shows the characters, patterns that can be used in the format.
+
+ \table
+ \header
+ \o Character
+ \o Meaning
+ \row
+ \o #
+ \o Any digit(s), zero shows as absent (for leading/trailing zeroes).
+ \row
+ \o 0
+ \o Implicit digit. Zero will show in the case that the input number is too small.
+ \row
+ \o .
+ \o Decimal separator. Output decimal seperator will be dependant on system locale.
+ \row
+ \o ,
+ \o Grouping separator. The number of digits (either #, or 0) between the grouping separator and the decimal (or the rightmost digit) will determine the groupingSize).
+ \row
+ \o other
+ \o Any other character will be taken as a string literal and placed directly into the output string.
+ \endtable
+
+ Invalid formats will not guarantee a meaningful text output.
+
+ \note Input numbers that are too long for the given format will be rounded dependent on precison based on the position of the decimal point.
+
+ The following table illustrates the output text created by applying some examples of numeric formats to the formatter.
+
+ \table
+ \header
+ \o Format
+ \o Number
+ \o Output
+ \row
+ \o ###
+ \o 123456
+ \o 123456
+ \row
+ \o 000
+ \o 123456
+ \o 123456
+ \row
+ \o ######
+ \o 1234
+ \o 1234
+ \row
+ \o 000000
+ \o 1234
+ \o 001234
+ \row
+ \o ##,##0.##
+ \o 1234.456
+ \o 1,234.46 (for US locale)
+ \codeline 1 234,46 (for FR locale)
+ \row
+ \o 000000,000.#
+ \o 123456
+ \o 000,123,456 (for US locale)
+ \codeline 000 123 456 (for FR locale)
+ \row
+ \o 0.0###
+ \o 0.999997
+ \o 1.0
+ \row
+ \o (000) 000 - 000
+ \o 12345678
+ \o (012) 345 - 678
+ \row
+ \o #A
+ \o 12
+ \o 12A
+ \endtable
+
+*/
+QString QmlNumberFormatter::format() const
+{
+ Q_D(const QmlNumberFormatter);
+ return d->format;
+}
+
+void QmlNumberFormatter::setNumber(const qreal &number)
+{
+ Q_D(QmlNumberFormatter);
+ if (d->number == number)
+ return;
+ d->number = number;
+ d->updateText();
+}
+
+void QmlNumberFormatter::setFormat(const QString &format)
+{
+ Q_D(QmlNumberFormatter);
+ //no format checking
+ if (format.isEmpty())
+ d->format = QString::null;
+ else
+ d->format = format;
+ d->updateText();
+}
+
+void QmlNumberFormatterPrivate::updateText()
+{
+ Q_Q(QmlNumberFormatter);
+ if (!componentComplete)
+ return;
+
+ QNumberFormat tempFormat;
+ tempFormat.setFormat(format);
+ tempFormat.setNumber(number);
+
+ text = tempFormat.text();
+
+ emit q->textChanged();
+}
+
+void QmlNumberFormatter::classBegin()
+{
+ Q_D(QmlNumberFormatter);
+ d->componentComplete = false;
+}
+
+void QmlNumberFormatter::componentComplete()
+{
+ Q_D(QmlNumberFormatter);
+ d->componentComplete = true;
+ d->updateText();
+}
+QML_DEFINE_TYPE(Qt,4,6,NumberFormatter,QmlNumberFormatter);
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlnumberformatter_p.h b/src/declarative/util/qmlnumberformatter_p.h
new file mode 100644
index 0000000..71fceb2
--- /dev/null
+++ b/src/declarative/util/qmlnumberformatter_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLNUMBERFORMATTER_H
+#define QMLNUMBERFORMATTER_H
+
+#include "qnumberformat_p.h"
+
+#include <qml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlNumberFormatterPrivate;
+class Q_DECLARATIVE_EXPORT QmlNumberFormatter : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QmlParserStatus)
+
+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
+ Q_PROPERTY(QString format READ format WRITE setFormat)
+ Q_PROPERTY(qreal number READ number WRITE setNumber)
+public:
+ QmlNumberFormatter(QObject *parent=0);
+ ~QmlNumberFormatter();
+
+ QString text() const;
+
+ qreal number() const;
+ void setNumber(const qreal &);
+
+ QString format() const;
+ void setFormat(const QString &);
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void textChanged();
+
+private:
+ Q_DISABLE_COPY(QmlNumberFormatter)
+ Q_DECLARE_PRIVATE(QmlNumberFormatter)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlNumberFormatter)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmlopenmetaobject.cpp b/src/declarative/util/qmlopenmetaobject.cpp
new file mode 100644
index 0000000..1be81de
--- /dev/null
+++ b/src/declarative/util/qmlopenmetaobject.cpp
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlopenmetaobject_p.h"
+#include "qmlpropertycache_p.h"
+#include "qmldeclarativedata_p.h"
+#include <qmetaobjectbuilder_p.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QmlOpenMetaObjectTypePrivate
+{
+public:
+ QmlOpenMetaObjectTypePrivate() : mem(0), cache(0), engine(0) {}
+
+ void init(const QMetaObject *metaObj);
+
+ int propertyOffset;
+ int signalOffset;
+ QHash<QByteArray, int> names;
+ QMetaObjectBuilder mob;
+ QMetaObject *mem;
+ QmlPropertyCache *cache;
+ QmlEngine *engine;
+ QSet<QmlOpenMetaObject*> referers;
+};
+
+QmlOpenMetaObjectType::QmlOpenMetaObjectType(const QMetaObject *base, QmlEngine *engine)
+ : d(new QmlOpenMetaObjectTypePrivate)
+{
+ d->engine = engine;
+ d->init(base);
+}
+
+QmlOpenMetaObjectType::~QmlOpenMetaObjectType()
+{
+ if (d->mem)
+ qFree(d->mem);
+ if (d->cache)
+ d->cache->release();
+ delete d;
+}
+
+
+int QmlOpenMetaObjectType::propertyOffset() const
+{
+ return d->propertyOffset;
+}
+
+int QmlOpenMetaObjectType::signalOffset() const
+{
+ return d->signalOffset;
+}
+
+int QmlOpenMetaObjectType::createProperty(const QByteArray &name)
+{
+ int id = d->mob.propertyCount();
+ d->mob.addSignal("__" + QByteArray::number(id) + "()");
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
+ build.setDynamic(true);
+ propertyCreated(id, build);
+ qFree(d->mem);
+ d->mem = d->mob.toMetaObject();
+ d->names.insert(name, id);
+ QSet<QmlOpenMetaObject*>::iterator it = d->referers.begin();
+ while (it != d->referers.end()) {
+ QmlOpenMetaObject *omo = *it;
+ *static_cast<QMetaObject *>(omo) = *d->mem;
+ if (d->cache)
+ d->cache->update(d->engine, omo);
+ ++it;
+ }
+
+ return d->propertyOffset + id;
+}
+
+void QmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
+{
+ if (d->referers.count())
+ (*d->referers.begin())->propertyCreated(id, builder);
+}
+
+void QmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
+{
+ if (!mem) {
+ mob.setSuperClass(metaObj);
+ mob.setClassName(metaObj->className());
+ mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ mem = mob.toMetaObject();
+
+ propertyOffset = mem->propertyOffset();
+ signalOffset = mem->methodOffset();
+ }
+}
+
+//----------------------------------------------------------------------------
+
+class QmlOpenMetaObjectPrivate
+{
+public:
+ QmlOpenMetaObjectPrivate(QmlOpenMetaObject *_q)
+ : q(_q), parent(0), type(0), cacheProperties(false) {}
+
+ inline QVariant &getData(int idx) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ if (!prop.second) {
+ prop.first = q->initialValue(idx);
+ prop.second = true;
+ }
+ return prop.first;
+ }
+
+ inline void writeData(int idx, const QVariant &value) {
+ while (data.count() <= idx)
+ data << QPair<QVariant, bool>(QVariant(), false);
+ QPair<QVariant, bool> &prop = data[idx];
+ prop.first = value;
+ prop.second = true;
+ }
+
+ bool autoCreate;
+ QmlOpenMetaObject *q;
+ QAbstractDynamicMetaObject *parent;
+ QList<QPair<QVariant, bool> > data;
+ QObject *object;
+ QmlOpenMetaObjectType *type;
+ bool cacheProperties;
+};
+
+QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, bool automatic)
+: d(new QmlOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = new QmlOpenMetaObjectType(obj->metaObject(), 0);
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QmlOpenMetaObject::QmlOpenMetaObject(QObject *obj, QmlOpenMetaObjectType *type, bool automatic)
+: d(new QmlOpenMetaObjectPrivate(this))
+{
+ d->autoCreate = automatic;
+ d->object = obj;
+
+ d->type = type;
+ d->type->addref();
+ d->type->d->referers.insert(this);
+
+ QObjectPrivate *op = QObjectPrivate::get(obj);
+ *static_cast<QMetaObject *>(this) = *d->type->d->mem;
+ op->metaObject = this;
+}
+
+QmlOpenMetaObject::~QmlOpenMetaObject()
+{
+ if (d->parent)
+ delete d->parent;
+ d->type->d->referers.remove(this);
+ d->type->release();
+ delete d;
+}
+
+QmlOpenMetaObjectType *QmlOpenMetaObject::type() const
+{
+ return d->type;
+}
+
+int QmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a)
+{
+ if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty)
+ && id >= d->type->d->propertyOffset) {
+ int propId = id - d->type->d->propertyOffset;
+ if (c == QMetaObject::ReadProperty) {
+ propertyRead(propId);
+ *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId);
+ } else if (c == QMetaObject::WriteProperty) {
+ if (d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) {
+ propertyWrite(propId);
+ d->writeData(propId, *reinterpret_cast<QVariant *>(a[0]));
+ activate(d->object, d->type->d->signalOffset + propId, 0);
+ }
+ }
+ return -1;
+ } else {
+ if (d->parent)
+ return d->parent->metaCall(c, id, a);
+ else
+ return d->object->qt_metacall(c, id, a);
+ }
+}
+
+QAbstractDynamicMetaObject *QmlOpenMetaObject::parent() const
+{
+ return d->parent;
+}
+
+QVariant QmlOpenMetaObject::value(int id) const
+{
+ return d->getData(id);
+}
+
+void QmlOpenMetaObject::setValue(int id, const QVariant &value)
+{
+ d->writeData(id, value);
+ activate(d->object, id + d->type->d->signalOffset, 0);
+}
+
+QVariant QmlOpenMetaObject::value(const QByteArray &name) const
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ if (iter == d->type->d->names.end())
+ return QVariant();
+
+ return d->getData(*iter);
+}
+
+QVariant &QmlOpenMetaObject::operator[](const QByteArray &name)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+ Q_ASSERT(iter != d->type->d->names.end());
+
+ return d->getData(*iter);
+}
+
+void QmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val)
+{
+ QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.find(name);
+
+ int id = -1;
+ if (iter == d->type->d->names.end()) {
+ id = d->type->createProperty(name.constData()) - d->type->d->propertyOffset;
+ } else {
+ id = *iter;
+ }
+
+ QVariant &dataVal = d->getData(id);
+ if (dataVal == val)
+ return;
+
+ dataVal = val;
+ activate(d->object, id + d->type->d->signalOffset, 0);
+}
+
+void QmlOpenMetaObject::setCached(bool c)
+{
+ if (c == d->cacheProperties || !d->type->d->engine)
+ return;
+
+ d->cacheProperties = c;
+
+ QmlDeclarativeData *qmldata = QmlDeclarativeData::get(d->object, true);
+ if (d->cacheProperties) {
+ if (!d->type->d->cache)
+ d->type->d->cache = QmlPropertyCache::create(d->type->d->engine, this);
+ qmldata->propertyCache = d->type->d->cache;
+ d->type->d->cache->addref();
+ } else {
+ if (d->type->d->cache)
+ d->type->d->cache->release();
+ qmldata->propertyCache = 0;
+ }
+}
+
+
+int QmlOpenMetaObject::createProperty(const char *name, const char *)
+{
+ if (d->autoCreate)
+ return d->type->createProperty(name);
+ else
+ return -1;
+}
+
+void QmlOpenMetaObject::propertyRead(int)
+{
+}
+
+void QmlOpenMetaObject::propertyWrite(int)
+{
+}
+
+void QmlOpenMetaObject::propertyCreated(int, QMetaPropertyBuilder &)
+{
+}
+
+QVariant QmlOpenMetaObject::initialValue(int)
+{
+ return QVariant();
+}
+
+int QmlOpenMetaObject::count() const
+{
+ return d->type->d->names.count();
+}
+
+QByteArray QmlOpenMetaObject::name(int idx) const
+{
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+
+ return d->type->d->mob.property(idx).name();
+}
+
+QObject *QmlOpenMetaObject::object() const
+{
+ return d->object;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlopenmetaobject_p.h b/src/declarative/util/qmlopenmetaobject_p.h
new file mode 100644
index 0000000..c6da71a
--- /dev/null
+++ b/src/declarative/util/qmlopenmetaobject_p.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLOPENMETAOBJECT_H
+#define QMLOPENMETAOBJECT_H
+
+#include <private/qmlrefcount_p.h>
+#include <QtCore/QMetaObject>
+#include <QtCore/QObject>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlEngine;
+class QMetaPropertyBuilder;
+class QmlOpenMetaObjectTypePrivate;
+class Q_DECLARATIVE_EXPORT QmlOpenMetaObjectType : public QmlRefCount
+{
+public:
+ QmlOpenMetaObjectType(const QMetaObject *base, QmlEngine *engine);
+ ~QmlOpenMetaObjectType();
+
+ int createProperty(const QByteArray &name);
+
+ int propertyOffset() const;
+ int signalOffset() const;
+
+protected:
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+private:
+ QmlOpenMetaObjectTypePrivate *d;
+ friend class QmlOpenMetaObject;
+ friend class QmlOpenMetaObjectPrivate;
+};
+
+class QmlOpenMetaObjectPrivate;
+class Q_DECLARATIVE_EXPORT QmlOpenMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QmlOpenMetaObject(QObject *, bool = true);
+ QmlOpenMetaObject(QObject *, QmlOpenMetaObjectType *, bool = true);
+ ~QmlOpenMetaObject();
+
+ QVariant value(const QByteArray &) const;
+ void setValue(const QByteArray &, const QVariant &);
+ QVariant value(int) const;
+ void setValue(int, const QVariant &);
+ QVariant &operator[](const QByteArray &);
+
+ int count() const;
+ QByteArray name(int) const;
+
+ QObject *object() const;
+ virtual QVariant initialValue(int);
+
+ // Be careful - once setCached(true) is called createProperty() is no
+ // longer automatically called for new properties.
+ void setCached(bool);
+
+ QmlOpenMetaObjectType *type() const;
+
+protected:
+ virtual int metaCall(QMetaObject::Call _c, int _id, void **_a);
+ virtual int createProperty(const char *, const char *);
+
+ virtual void propertyRead(int);
+ virtual void propertyWrite(int);
+ virtual void propertyCreated(int, QMetaPropertyBuilder &);
+
+ QAbstractDynamicMetaObject *parent() const;
+
+private:
+ QmlOpenMetaObjectPrivate *d;
+ friend class QmlOpenMetaObjectType;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLOPENMETAOBJECT_H
diff --git a/src/declarative/util/qmlpackage.cpp b/src/declarative/util/qmlpackage.cpp
new file mode 100644
index 0000000..3214dc8
--- /dev/null
+++ b/src/declarative/util/qmlpackage.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlpackage_p.h"
+
+#include <private/qobject_p.h>
+#include "private/qmlguard_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlPackagePrivate : public QObjectPrivate
+{
+public:
+ QmlPackagePrivate() {}
+
+ class DataList;
+ struct DataGuard : public QmlGuard<QObject>
+ {
+ DataGuard(QObject *obj, DataList *l) : list(l) { (QmlGuard<QObject>&)*this = obj; }
+ DataList *list;
+ void objectDestroyed(QObject *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+
+ class DataList : public QList<DataGuard>, public QmlList<QObject*>
+ {
+ public:
+ virtual void append(QObject* v) { QList<DataGuard>::append(DataGuard(v, this)); }
+ virtual void insert(int i, QObject* v) { QList<DataGuard>::insert(i, DataGuard(v, this)); }
+ virtual void clear() { QList<DataGuard>::clear(); }
+ virtual QObject* at(int i) const { return QList<DataGuard>::at(i); }
+ virtual void removeAt(int i) { QList<DataGuard>::removeAt(i); }
+ virtual int count() const { return QList<DataGuard>::count(); }
+ };
+ DataList dataList;
+};
+
+class QmlPackageAttached : public QObject
+{
+Q_OBJECT
+Q_PROPERTY(QString name READ name WRITE setName)
+public:
+ QmlPackageAttached(QObject *parent);
+ virtual ~QmlPackageAttached();
+
+ QString name() const;
+ void setName(const QString &n);
+
+ static QHash<QObject *, QmlPackageAttached *> attached;
+private:
+ QString _name;
+};
+
+QHash<QObject *, QmlPackageAttached *> QmlPackageAttached::attached;
+
+QmlPackageAttached::QmlPackageAttached(QObject *parent)
+: QObject(parent)
+{
+ attached.insert(parent, this);
+}
+
+QmlPackageAttached::~QmlPackageAttached()
+{
+ attached.remove(parent());
+}
+
+QString QmlPackageAttached::name() const
+{
+ return _name;
+}
+
+void QmlPackageAttached::setName(const QString &n)
+{
+ _name = n;
+}
+
+QmlPackage::QmlPackage(QObject *parent)
+ : QObject(*(new QmlPackagePrivate), parent)
+{
+}
+
+QmlPackage::~QmlPackage()
+{
+ Q_D(QmlPackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ obj->setParent(this);
+ }
+}
+
+QmlList<QObject *> *QmlPackage::data()
+{
+ Q_D(QmlPackage);
+ return &d->dataList;
+}
+
+bool QmlPackage::hasPart(const QString &name)
+{
+ Q_D(QmlPackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ QmlPackageAttached *a = QmlPackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return true;
+ }
+ return false;
+}
+
+QObject *QmlPackage::part(const QString &name)
+{
+ Q_D(QmlPackage);
+ if (name.isEmpty() && !d->dataList.isEmpty())
+ return d->dataList.at(0);
+
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ QmlPackageAttached *a = QmlPackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return obj;
+ }
+
+ if (name == QLatin1String("default") && !d->dataList.isEmpty())
+ return d->dataList.at(0);
+
+ return 0;
+}
+
+QmlPackageAttached *QmlPackage::qmlAttachedProperties(QObject *o)
+{
+ return new QmlPackageAttached(o);
+}
+
+QML_DEFINE_TYPE(Qt,4,6,Package,QmlPackage)
+
+QT_END_NAMESPACE
+
+#include <qmlpackage.moc>
diff --git a/src/declarative/util/qmlpackage_p.h b/src/declarative/util/qmlpackage_p.h
new file mode 100644
index 0000000..ff42aad
--- /dev/null
+++ b/src/declarative/util/qmlpackage_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLPACKAGE_H
+#define QMLPACKAGE_H
+
+#include <qml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+/*****************************************************************************
+ *****************************************************************************
+ XXX Experimental
+ *****************************************************************************
+*****************************************************************************/
+
+class QmlPackagePrivate;
+class QmlPackageAttached;
+class QmlPackage : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPackage)
+
+ Q_CLASSINFO("DefaultProperty", "data")
+ Q_PROPERTY(QmlList<QObject *> *data READ data SCRIPTABLE false)
+
+public:
+ QmlPackage(QObject *parent=0);
+ virtual ~QmlPackage();
+
+ QmlList<QObject *> *data();
+
+ QObject *part(const QString & = QString());
+ bool hasPart(const QString &);
+
+ static QmlPackageAttached *qmlAttachedProperties(QObject *);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlPackage)
+QML_DECLARE_TYPEINFO(QmlPackage, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QMLPACKAGE_H
diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp
new file mode 100644
index 0000000..c03b5df
--- /dev/null
+++ b/src/declarative/util/qmlpixmapcache.cpp
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlpixmapcache_p.h"
+#include "qmlnetworkaccessmanagerfactory.h"
+
+#include "qfxperf_p_p.h"
+
+#include <qmlengine.h>
+#include <private/qmlglobal_p.h>
+
+#include <QCoreApplication>
+#include <QImageReader>
+#include <QHash>
+#include <QNetworkReply>
+#include <QPixmapCache>
+#include <QFile>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QtCore/qdebug.h>
+#include <private/qobject_p.h>
+#include <QSslError>
+
+#ifdef Q_OS_LINUX
+#include <pthread.h>
+#include <linux/sched.h>
+#endif
+
+// Maximum number of simultaneous image requests to send.
+static const int maxImageRequestCount = 8;
+
+QT_BEGIN_NAMESPACE
+
+#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0))
+inline uint qHash(const QUrl &uri)
+{
+ return qHash(uri.toEncoded(QUrl::FormattingOption(0x100)));
+}
+#endif
+
+class QmlImageReaderEvent : public QEvent
+{
+public:
+ enum ReadError { NoError, Loading, Decoding };
+
+ QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, const QString &errStr, QImage &img)
+ : QEvent(QEvent::User), error(err), errorString(errStr), image(img) {}
+
+ ReadError error;
+ QString errorString;
+ QImage image;
+};
+
+class QmlImageRequestHandler;
+class QmlImageReader : public QThread
+{
+ Q_OBJECT
+public:
+ QmlImageReader(QmlEngine *eng);
+ ~QmlImageReader();
+
+ QmlPixmapReply *getImage(const QUrl &url);
+ void cancel(QmlPixmapReply *rep);
+
+ static QmlImageReader *instance(QmlEngine *engine);
+
+protected:
+ void run();
+
+private:
+ QList<QmlPixmapReply*> jobs;
+ QList<QmlPixmapReply*> cancelled;
+ QmlEngine *engine;
+ QmlImageRequestHandler *handler;
+ QMutex mutex;
+
+ static QHash<QmlEngine *,QmlImageReader*> readers;
+ static QMutex readerMutex;
+ friend class QmlImageRequestHandler;
+};
+
+QHash<QmlEngine *,QmlImageReader*> QmlImageReader::readers;
+QMutex QmlImageReader::readerMutex;
+
+
+class QmlImageRequestHandler : public QObject
+{
+ Q_OBJECT
+public:
+ QmlImageRequestHandler(QmlImageReader *read, QmlEngine *eng)
+ : QObject(), accessManager(0), engine(eng), reader(read)
+ {
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ }
+
+ QmlPixmapReply *getImage(const QUrl &url);
+ void cancel(QmlPixmapReply *reply);
+
+protected:
+ bool event(QEvent *event);
+
+private slots:
+ void networkRequestDone();
+
+private:
+ QNetworkAccessManager *networkAccessManager() {
+ if (!accessManager) {
+ if (engine && engine->networkAccessManagerFactory()) {
+ accessManager = engine->networkAccessManagerFactory()->create(this);
+ } else {
+ accessManager = new QNetworkAccessManager(this);
+ }
+ }
+ return accessManager;
+ }
+
+ QHash<QNetworkReply*,QmlPixmapReply*> replies;
+ QNetworkAccessManager *accessManager;
+ QmlEngine *engine;
+ QmlImageReader *reader;
+};
+
+//===========================================================================
+
+bool QmlImageRequestHandler::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()");
+ downloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
+ thisNetworkRequestDone = QmlImageRequestHandler::staticMetaObject.indexOfSlot("networkRequestDone()");
+ }
+
+ while (1) {
+ reader->mutex.lock();
+
+ if (reader->cancelled.count()) {
+ for (int i = 0; i < reader->cancelled.count(); ++i) {
+ QmlPixmapReply *job = reader->cancelled.at(i);
+ QNetworkReply *reply = replies.key(job, 0);
+ if (reply && reply->isRunning()) {
+ replies.remove(reply);
+ reply->close();
+ job->release(true);
+ }
+ }
+ reader->cancelled.clear();
+ }
+
+ if (!reader->jobs.count() || replies.count() > maxImageRequestCount) {
+ reader->mutex.unlock();
+ break;
+ }
+
+ QmlPixmapReply *runningJob = reader->jobs.takeFirst();
+ runningJob->addRef();
+ runningJob->setLoading();
+ QUrl url = runningJob->url();
+ reader->mutex.unlock();
+
+ // fetch
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ QNetworkReply *reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone);
+
+ replies.insert(reply, runningJob);
+ }
+ return true;
+ }
+
+ return QObject::event(event);
+}
+
+void QmlImageRequestHandler::networkRequestDone()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ QmlPixmapReply *job = replies.take(reply);
+ if (job) {
+ QImage image;
+ QmlImageReaderEvent::ReadError error;
+ QString errorString;
+ if (reply->error()) {
+ error = QmlImageReaderEvent::Loading;
+ errorString = reply->errorString();
+ } else {
+ QImageReader imgio(reply);
+ if (imgio.read(&image)) {
+ error = QmlImageReaderEvent::NoError;
+ } else {
+ errorString = QLatin1String("Error decoding: ") + reply->url().toString()
+ + QLatin1String(" \"") + imgio.errorString() + QLatin1String("\"");
+ error = QmlImageReaderEvent::Decoding;
+ }
+ }
+ // send completion event to the QmlPixmapReply
+ QCoreApplication::postEvent(job, new QmlImageReaderEvent(error, errorString, image));
+ }
+ // kick off event loop again if we have dropped below max request count
+ if (replies.count() == maxImageRequestCount)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ reply->deleteLater();
+}
+
+//===========================================================================
+
+QmlImageReader::QmlImageReader(QmlEngine *eng)
+ : QThread(eng), engine(eng), handler(0)
+{
+ start(QThread::LowPriority);
+}
+
+QmlImageReader::~QmlImageReader()
+{
+ quit();
+ wait();
+ readerMutex.lock();
+ readers.remove(engine);
+ readerMutex.unlock();
+ delete handler;
+}
+
+QmlImageReader *QmlImageReader::instance(QmlEngine *engine)
+{
+ readerMutex.lock();
+ QmlImageReader *reader = readers.value(engine);
+ if (!reader) {
+ reader = new QmlImageReader(engine);
+ readers.insert(engine, reader);
+ }
+ readerMutex.unlock();
+
+ return reader;
+}
+
+QmlPixmapReply *QmlImageReader::getImage(const QUrl &url)
+{
+ mutex.lock();
+ QmlPixmapReply *reply = new QmlPixmapReply(this, url);
+ jobs.append(reply);
+ if (jobs.count() == 1 && handler)
+ QCoreApplication::postEvent(handler, new QEvent(QEvent::User));
+ mutex.unlock();
+ return reply;
+}
+
+void QmlImageReader::cancel(QmlPixmapReply *reply)
+{
+ mutex.lock();
+ if (reply->isLoading()) {
+ // Already requested. Add to cancel list to be cancelled in reader thread.
+ cancelled.append(reply);
+ if (cancelled.count() == 1 && handler)
+ QCoreApplication::postEvent(handler, new QEvent(QEvent::User));
+ } else {
+ // Not yet processed - just remove from waiting list
+ QList<QmlPixmapReply*>::iterator it = jobs.begin();
+ while (it != jobs.end()) {
+ QmlPixmapReply *job = *it;
+ if (job == reply) {
+ jobs.erase(it);
+ break;
+ }
+ ++it;
+ }
+ }
+ mutex.unlock();
+}
+
+void QmlImageReader::run()
+{
+#if defined(Q_OS_LINUX) && defined(SCHED_IDLE)
+ struct sched_param param;
+ int policy;
+
+ pthread_getschedparam(pthread_self(), &policy, &param);
+ pthread_setschedparam(pthread_self(), SCHED_IDLE, &param);
+#endif
+
+ handler = new QmlImageRequestHandler(this, engine);
+
+ exec();
+}
+
+//===========================================================================
+
+static bool readImage(QIODevice *dev, QPixmap *pixmap, QString &errorString)
+{
+ QImageReader imgio(dev);
+
+//#define QT_TEST_SCALED_SIZE
+#ifdef QT_TEST_SCALED_SIZE
+ /*
+ Some mechanism is needed for loading images at a limited size, especially
+ for remote images. Loading only thumbnails of remote progressive JPEG
+ images can be efficient. (Qt jpeg handler does not do so currently)
+ */
+
+ QSize limit(60,60);
+ QSize sz = imgio.size();
+ if (sz.width() > limit.width() || sz.height() > limit.height()) {
+ sz.scale(limit,Qt::KeepAspectRatio);
+ imgio.setScaledSize(sz);
+ }
+#endif
+
+ QImage img;
+ if (imgio.read(&img)) {
+#ifdef QT_TEST_SCALED_SIZE
+ if (!sz.isValid())
+ img = img.scaled(limit,Qt::KeepAspectRatio);
+#endif
+ *pixmap = QPixmap::fromImage(img);
+ return true;
+ } else {
+ errorString = imgio.errorString();
+ return false;
+ }
+}
+
+/*!
+ \internal
+ \class QmlPixmapCache
+ \brief Enacapsultes a pixmap for QmlGraphics items.
+
+ This class is NOT reentrant.
+ */
+
+static QString toLocalFileOrQrc(const QUrl& url)
+{
+ QString r = url.toLocalFile();
+ if (r.isEmpty() && url.scheme() == QLatin1String("qrc"))
+ r = QLatin1Char(':') + url.path();
+ return r;
+}
+
+typedef QHash<QUrl, QmlPixmapReply *> QmlPixmapReplyHash;
+Q_GLOBAL_STATIC(QmlPixmapReplyHash, qmlActivePixmapReplies);
+
+class QmlPixmapReplyPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPixmapReply)
+
+public:
+ QmlPixmapReplyPrivate(QmlImageReader *r, const QUrl &u)
+ : QObjectPrivate(), refCount(1), url(u), status(QmlPixmapReply::Loading), loading(false), reader(r) {
+ }
+
+ int refCount;
+ QUrl url;
+ QPixmap pixmap; // ensure reference to pixmap so QPixmapCache does not discard
+ QmlPixmapReply::Status status;
+ bool loading;
+ QmlImageReader *reader;
+};
+
+
+QmlPixmapReply::QmlPixmapReply(QmlImageReader *reader, const QUrl &url)
+ : QObject(*new QmlPixmapReplyPrivate(reader, url), 0)
+{
+}
+
+QmlPixmapReply::~QmlPixmapReply()
+{
+}
+
+const QUrl &QmlPixmapReply::url() const
+{
+ Q_D(const QmlPixmapReply);
+ return d->url;
+}
+
+bool QmlPixmapReply::event(QEvent *event)
+{
+ Q_D(QmlPixmapReply);
+ if (event->type() == QEvent::User) {
+ d->loading = false;
+ if (!release(true)) {
+ QmlImageReaderEvent *de = static_cast<QmlImageReaderEvent*>(event);
+ d->status = (de->error == QmlImageReaderEvent::NoError) ? Ready : Error;
+ if (d->status == Ready)
+ d->pixmap = QPixmap::fromImage(de->image);
+ else
+ qWarning() << de->errorString;
+ QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100));
+ QString strKey = QString::fromLatin1(key.constData(), key.count());
+ QPixmapCache::insert(strKey, d->pixmap); // note: may fail (returns false)
+ emit finished();
+ }
+ return true;
+ }
+
+ return QObject::event(event);
+}
+
+QmlPixmapReply::Status QmlPixmapReply::status() const
+{
+ Q_D(const QmlPixmapReply);
+ return d->status;
+}
+
+bool QmlPixmapReply::isLoading() const
+{
+ Q_D(const QmlPixmapReply);
+ return d->loading;
+}
+
+void QmlPixmapReply::setLoading()
+{
+ Q_D(QmlPixmapReply);
+ d->loading = true;
+}
+
+void QmlPixmapReply::addRef()
+{
+ Q_D(QmlPixmapReply);
+ ++d->refCount;
+}
+
+bool QmlPixmapReply::release(bool defer)
+{
+ Q_D(QmlPixmapReply);
+ Q_ASSERT(d->refCount > 0);
+ --d->refCount;
+ if (d->refCount == 0) {
+ qmlActivePixmapReplies()->remove(d->url);
+ if (d->status == Loading && !d->loading)
+ d->reader->cancel(this);
+ if (defer)
+ deleteLater();
+ else
+ delete this;
+ return true;
+ } else if (d->refCount == 1 && d->loading) {
+ // The only reference left is the reader thread.
+ qmlActivePixmapReplies()->remove(d->url);
+ d->reader->cancel(this);
+ }
+
+ return false;
+}
+
+/*!
+ Finds the cached pixmap corresponding to \a url.
+ If the image is a network resource and has not yet
+ been retrieved and cached, request() must be called.
+
+ Returns Ready, or Error if the image has been retrieved,
+ otherwise the current retrieval status.
+*/
+QmlPixmapReply::Status QmlPixmapCache::get(const QUrl& url, QPixmap *pixmap)
+{
+ QmlPixmapReply::Status status = QmlPixmapReply::Unrequested;
+
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ QString lf = toLocalFileOrQrc(url);
+ if (!lf.isEmpty()) {
+ status = QmlPixmapReply::Ready;
+ if (!QPixmapCache::find(lf,pixmap)) {
+ QFile f(lf);
+ if (f.open(QIODevice::ReadOnly)) {
+ QString errorString;
+ if (!readImage(&f, pixmap, errorString)) {
+ errorString = QLatin1String("Error decoding: ") + url.toString()
+ + QLatin1String(" \"") + errorString + QLatin1String("\"");
+ qWarning() << errorString;
+ *pixmap = QPixmap();
+ status = QmlPixmapReply::Error;
+ }
+ } else {
+ qWarning() << "Cannot open" << url;
+ *pixmap = QPixmap();
+ status = QmlPixmapReply::Error;
+ }
+ if (status == QmlPixmapReply::Ready)
+ QPixmapCache::insert(lf, *pixmap);
+ }
+ return status;
+ }
+#endif
+
+ QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100));
+ QString strKey = QString::fromLatin1(key.constData(), key.count());
+ QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
+ if (iter != qmlActivePixmapReplies()->end() && (*iter)->status() == QmlPixmapReply::Ready) {
+ // Must check this, since QPixmapCache::insert may have failed.
+ *pixmap = (*iter)->d_func()->pixmap;
+ status = (*iter)->status();
+ (*iter)->release();
+ } else if (QPixmapCache::find(strKey, pixmap)) {
+ if (iter != qmlActivePixmapReplies()->end()) {
+ status = (*iter)->status();
+ (*iter)->release();
+ } else {
+ status = pixmap->isNull() ? QmlPixmapReply::Error : QmlPixmapReply::Ready;
+ }
+ } else if (iter != qmlActivePixmapReplies()->end()) {
+ status = QmlPixmapReply::Loading;
+ }
+
+ return status;
+}
+
+/*!
+ Starts a network request to load \a url.
+
+ Returns a QmlPixmapReply. Caller should connect to QmlPixmapReply::finished()
+ and call get() when the image is available.
+
+ The returned QmlPixmapReply will be deleted when all request() calls are
+ matched by a corresponding get() call.
+*/
+QmlPixmapReply *QmlPixmapCache::request(QmlEngine *engine, const QUrl &url)
+{
+ QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
+ if (iter == qmlActivePixmapReplies()->end()) {
+ QmlImageReader *reader = QmlImageReader::instance(engine);
+ QmlPixmapReply *item = reader->getImage(url);
+ iter = qmlActivePixmapReplies()->insert(url, item);
+ } else {
+ (*iter)->addRef();
+ }
+
+ return (*iter);
+}
+
+/*!
+ Cancels a previous call to request().
+
+ May also cancel loading (eg. if no other pending request).
+
+ Any connections from the QmlPixmapReply returned by request() to \a obj will be
+ disconnected.
+*/
+void QmlPixmapCache::cancel(const QUrl& url, QObject *obj)
+{
+ QmlPixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url);
+ if (iter == qmlActivePixmapReplies()->end())
+ return;
+
+ QmlPixmapReply *reply = *iter;
+ if (obj)
+ QObject::disconnect(reply, 0, obj, 0);
+ reply->release();
+}
+
+/*!
+ This function is mainly for test verification. It returns the number of
+ requests that are still unfinished.
+*/
+int QmlPixmapCache::pendingRequests()
+{
+ return qmlActivePixmapReplies()->count();
+}
+
+#include <qmlpixmapcache.moc>
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlpixmapcache_p.h b/src/declarative/util/qmlpixmapcache_p.h
new file mode 100644
index 0000000..462faf6
--- /dev/null
+++ b/src/declarative/util/qmlpixmapcache_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLPIXMAPCACHE_H
+#define QMLPIXMAPCACHE_H
+
+#include <QtCore/QString>
+#include <QtGui/QPixmap>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QmlEngine;
+class QNetworkReply;
+class QmlImageReader;
+
+class QmlPixmapReplyPrivate;
+class Q_DECLARATIVE_EXPORT QmlPixmapReply : public QObject
+{
+ Q_OBJECT
+public:
+ ~QmlPixmapReply();
+
+ enum Status { Ready, Error, Unrequested, Loading };
+ Status status() const;
+
+ const QUrl &url() const;
+
+Q_SIGNALS:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+ void addRef();
+ bool release(bool defer=false);
+ bool isLoading() const;
+ void setLoading();
+
+private:
+ QmlPixmapReply(QmlImageReader *reader, const QUrl &url);
+ Q_DISABLE_COPY(QmlPixmapReply)
+ Q_DECLARE_PRIVATE(QmlPixmapReply)
+ friend class QmlImageRequestHandler;
+ friend class QmlImageReader;
+ friend class QmlPixmapCache;
+};
+
+class Q_DECLARATIVE_EXPORT QmlPixmapCache
+{
+public:
+ static QmlPixmapReply::Status get(const QUrl& url, QPixmap *pixmap);
+ static QmlPixmapReply *request(QmlEngine *, const QUrl& url);
+ static void cancel(const QUrl& url, QObject *obj);
+ static int pendingRequests();
+};
+
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLPIXMAPCACHE_H
diff --git a/src/declarative/util/qmlpropertychanges.cpp b/src/declarative/util/qmlpropertychanges.cpp
new file mode 100644
index 0000000..68fc5cc
--- /dev/null
+++ b/src/declarative/util/qmlpropertychanges.cpp
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlpropertychanges_p.h"
+
+#include "qmlopenmetaobject_p.h"
+
+#include <qmlinfo.h>
+#include <qmlcustomparser_p.h>
+#include <qmlparser_p.h>
+#include <qmlexpression.h>
+#include <qmlbinding.h>
+#include <qmlcontext.h>
+#include <qmlguard_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass PropertyChanges QmlPropertyChanges
+ \brief The PropertyChanges element describes new property values for a state.
+
+ PropertyChanges provides a state change that modifies the properties of an item.
+
+ Here is a property change that modifies the text and color of a Text element
+ when it is clicked:
+
+ \qml
+ Text {
+ id: myText
+ width: 100; height: 100
+ text: "Hello"
+ color: "blue"
+
+ states: State {
+ name: "myState"
+
+ PropertyChanges {
+ target: myText
+ text: "Goodbye"
+ color: "red"
+ }
+ }
+
+ MouseRegion { anchors.fill: parent; onClicked: myText.state = 'myState' }
+ }
+ \endqml
+
+ State-specific script for signal handlers can also be specified:
+
+ \qml
+ PropertyChanges {
+ target: myMouseRegion
+ onClicked: doSomethingDifferent()
+ }
+ \endqml
+
+ Changes to an Item's parent or anchors should be done using the associated change elements
+ (ParentChange and AnchorChanges, respectively) rather than PropertyChanges.
+
+ \sa {qmlstate}{States}
+*/
+
+/*!
+ \internal
+ \class QmlPropertyChanges
+ \brief The QmlPropertyChanges class describes new property values for a state.
+*/
+
+/*!
+ \qmlproperty Object PropertyChanges::target
+ This property holds the object which contains the properties to be changed.
+*/
+
+class QmlReplaceSignalHandler : public QmlActionEvent
+{
+public:
+ QmlReplaceSignalHandler() : expression(0), reverseExpression(0),
+ rewindExpression(0), ownedExpression(0) {}
+ ~QmlReplaceSignalHandler() {
+ delete ownedExpression;
+ }
+
+ virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
+
+ QmlMetaProperty property;
+ QmlExpression *expression;
+ QmlExpression *reverseExpression;
+ QmlExpression *rewindExpression;
+ QmlGuard<QmlExpression> ownedExpression;
+
+ virtual void execute() {
+ ownedExpression = property.setSignalExpression(expression);
+ }
+
+ virtual bool isReversable() { return true; }
+ virtual void reverse() {
+ ownedExpression = property.setSignalExpression(reverseExpression);
+ }
+
+ virtual void saveOriginals() {
+ saveCurrentValues();
+ reverseExpression = rewindExpression;
+ }
+
+ virtual void rewind() {
+ ownedExpression = property.setSignalExpression(rewindExpression);
+ }
+ virtual void saveCurrentValues() { rewindExpression = property.signalExpression(); }
+
+ virtual bool override(QmlActionEvent*other) {
+ if (other == this)
+ return true;
+ if (other->typeName() != typeName())
+ return false;
+ if (static_cast<QmlReplaceSignalHandler*>(other)->property == property)
+ return true;
+ return false;
+ }
+};
+
+
+class QmlPropertyChangesPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPropertyChanges)
+public:
+ QmlPropertyChangesPrivate() : object(0), decoded(true), restore(true),
+ isExplicit(false) {}
+
+ QObject *object;
+ QByteArray data;
+
+ bool decoded : 1;
+ bool restore : 1;
+ bool isExplicit : 1;
+
+ void decode();
+
+ QList<QPair<QByteArray, QVariant> > properties;
+ QList<QPair<QByteArray, QmlExpression *> > expressions;
+ QList<QmlReplaceSignalHandler*> signalReplacements;
+
+ QmlMetaProperty property(const QByteArray &);
+};
+
+class QmlPropertyChangesParser : public QmlCustomParser
+{
+public:
+ void compileList(QList<QPair<QByteArray, QVariant> > &list, const QByteArray &pre, const QmlCustomParserProperty &prop);
+
+ virtual QByteArray compile(const QList<QmlCustomParserProperty> &);
+ virtual void setCustomData(QObject *, const QByteArray &);
+};
+
+void
+QmlPropertyChangesParser::compileList(QList<QPair<QByteArray, QVariant> > &list,
+ const QByteArray &pre,
+ const QmlCustomParserProperty &prop)
+{
+ QByteArray propName = pre + prop.name();
+
+ QList<QVariant> values = prop.assignedValues();
+ for (int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if (value.userType() == qMetaTypeId<QmlCustomParserNode>()) {
+ continue;
+ } else if(value.userType() == qMetaTypeId<QmlCustomParserProperty>()) {
+
+ QmlCustomParserProperty prop =
+ qvariant_cast<QmlCustomParserProperty>(value);
+ QByteArray pre = propName + '.';
+ compileList(list, pre, prop);
+
+ } else {
+ list << qMakePair(propName, value);
+ }
+ }
+}
+
+QByteArray
+QmlPropertyChangesParser::compile(const QList<QmlCustomParserProperty> &props)
+{
+ QList<QPair<QByteArray, QVariant> > data;
+ for(int ii = 0; ii < props.count(); ++ii)
+ compileList(data, QByteArray(), props.at(ii));
+
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ ds << data.count();
+ for(int ii = 0; ii < data.count(); ++ii) {
+ QmlParser::Variant v = qvariant_cast<QmlParser::Variant>(data.at(ii).second);
+ QVariant var;
+ bool isScript = v.isScript();
+ switch(v.type()) {
+ case QmlParser::Variant::Boolean:
+ var = QVariant(v.asBoolean());
+ break;
+ case QmlParser::Variant::Number:
+ var = QVariant(v.asNumber());
+ break;
+ case QmlParser::Variant::String:
+ var = QVariant(v.asString());
+ break;
+ case QmlParser::Variant::Invalid:
+ case QmlParser::Variant::Script:
+ var = QVariant(v.asScript());
+ break;
+ }
+
+ ds << data.at(ii).first << isScript << var;
+ }
+
+ return rv;
+}
+
+void QmlPropertyChangesPrivate::decode()
+{
+ Q_Q(QmlPropertyChanges);
+ if (decoded)
+ return;
+
+ QDataStream ds(&data, QIODevice::ReadOnly);
+
+ int count;
+ ds >> count;
+ for (int ii = 0; ii < count; ++ii) {
+ QByteArray name;
+ bool isScript;
+ QVariant data;
+ ds >> name;
+ ds >> isScript;
+ ds >> data;
+
+ 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);
+ }
+ }
+
+ decoded = true;
+ data.clear();
+}
+
+void QmlPropertyChangesParser::setCustomData(QObject *object,
+ const QByteArray &data)
+{
+ QmlPropertyChangesPrivate *p =
+ static_cast<QmlPropertyChangesPrivate *>(QObjectPrivate::get(object));
+ p->data = data;
+ p->decoded = false;
+}
+
+QmlPropertyChanges::QmlPropertyChanges()
+: QmlStateOperation(*(new QmlPropertyChangesPrivate))
+{
+}
+
+QmlPropertyChanges::~QmlPropertyChanges()
+{
+ Q_D(QmlPropertyChanges);
+ for(int ii = 0; ii < d->expressions.count(); ++ii)
+ delete d->expressions.at(ii).second;
+ for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
+ delete d->signalReplacements.at(ii);
+}
+
+QObject *QmlPropertyChanges::object() const
+{
+ Q_D(const QmlPropertyChanges);
+ return d->object;
+}
+
+void QmlPropertyChanges::setObject(QObject *o)
+{
+ Q_D(QmlPropertyChanges);
+ d->object = o;
+}
+
+/*!
+ \qmlproperty bool PropertyChanges::restoreEntryValues
+
+ Whether or not the previous values should be restored when
+ leaving the state. By default, restoreEntryValues is true.
+
+ By setting restoreEntryValues to false, you can create a temporary state
+ that has permanent effects on property values.
+*/
+bool QmlPropertyChanges::restoreEntryValues() const
+{
+ Q_D(const QmlPropertyChanges);
+ return d->restore;
+}
+
+void QmlPropertyChanges::setRestoreEntryValues(bool v)
+{
+ Q_D(QmlPropertyChanges);
+ d->restore = v;
+}
+
+QmlMetaProperty
+QmlPropertyChangesPrivate::property(const QByteArray &property)
+{
+ Q_Q(QmlPropertyChanges);
+ QmlMetaProperty prop = QmlMetaProperty::createProperty(object, QString::fromUtf8(property));
+ if (!prop.isValid()) {
+ qmlInfo(q) << QmlPropertyChanges::tr("Cannot assign to non-existant property \"%1\"").arg(QString::fromUtf8(property));
+ return QmlMetaProperty();
+ } else if (!(prop.type() & QmlMetaProperty::SignalProperty) && !prop.isWritable()) {
+ qmlInfo(q) << QmlPropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(QString::fromUtf8(property));
+ return QmlMetaProperty();
+ }
+ return prop;
+}
+
+QmlPropertyChanges::ActionList QmlPropertyChanges::actions()
+{
+ Q_D(QmlPropertyChanges);
+
+ d->decode();
+
+ ActionList list;
+
+ for (int ii = 0; ii < d->properties.count(); ++ii) {
+
+ QByteArray property = d->properties.at(ii).first;
+
+ QmlAction a(d->object, QString::fromLatin1(property),
+ d->properties.at(ii).second);
+
+ if (a.property.isValid()) {
+ a.restore = restoreEntryValues();
+
+ if (a.property.propertyType() == QVariant::Url &&
+ (a.toValue.userType() == QVariant::String || a.toValue.userType() == QVariant::ByteArray) && !a.toValue.isNull())
+ a.toValue.setValue(qmlContext(this)->resolvedUrl(QUrl(a.toValue.toString())));
+
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
+
+ QmlReplaceSignalHandler *handler = d->signalReplacements.at(ii);
+
+ if (handler->property.isValid()) {
+ QmlAction a;
+ a.event = handler;
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->expressions.count(); ++ii) {
+
+ QByteArray property = d->expressions.at(ii).first;
+ QmlMetaProperty prop = d->property(property);
+
+ if (prop.isValid()) {
+ QmlAction a;
+ a.restore = restoreEntryValues();
+ a.property = prop;
+ a.fromValue = a.property.read();
+ a.specifiedObject = d->object;
+ a.specifiedProperty = QString::fromLatin1(property);
+
+ if (d->isExplicit) {
+ a.toValue = d->expressions.at(ii).second->value();
+ } else {
+ QmlBinding *newBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this));
+ newBinding->setTarget(prop);
+ a.toBinding = newBinding;
+ a.deletableToBinding = true;
+ }
+
+ list << a;
+ }
+ }
+
+ return list;
+}
+
+/*!
+ \qmlproperty bool PropertyChanges::explicit
+
+ If explicit is set to true, any potential bindings will be interpreted as
+ once-off assignments that occur when the state is entered.
+
+ In the following example, the addition of explicit prevents myItem.width from
+ being bound to parent.width. Instead, it is assigned the value of parent.width
+ at the time of the state change.
+ \qml
+ PropertyChanges {
+ target: myItem
+ explicit: true
+ width: parent.width
+ }
+ \endqml
+
+ By default, explicit is false.
+*/
+bool QmlPropertyChanges::isExplicit() const
+{
+ Q_D(const QmlPropertyChanges);
+ return d->isExplicit;
+}
+
+void QmlPropertyChanges::setIsExplicit(bool e)
+{
+ Q_D(QmlPropertyChanges);
+ d->isExplicit = e;
+}
+
+QML_DEFINE_CUSTOM_TYPE(Qt, 4,6, PropertyChanges, QmlPropertyChanges, QmlPropertyChangesParser)
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlpropertychanges_p.h b/src/declarative/util/qmlpropertychanges_p.h
new file mode 100644
index 0000000..461730d
--- /dev/null
+++ b/src/declarative/util/qmlpropertychanges_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLPROPERTYCHANGES_H
+#define QMLPROPERTYCHANGES_H
+
+#include "qmlstateoperations_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlPropertyChangesPrivate;
+class Q_DECLARATIVE_EXPORT QmlPropertyChanges : public QmlStateOperation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlPropertyChanges)
+
+ Q_PROPERTY(QObject *target READ object WRITE setObject)
+ Q_PROPERTY(bool restoreEntryValues READ restoreEntryValues WRITE setRestoreEntryValues)
+ Q_PROPERTY(bool explicit READ isExplicit WRITE setIsExplicit)
+public:
+ QmlPropertyChanges();
+ ~QmlPropertyChanges();
+
+ QObject *object() const;
+ void setObject(QObject *);
+
+ bool restoreEntryValues() const;
+ void setRestoreEntryValues(bool);
+
+ bool isExplicit() const;
+ void setIsExplicit(bool);
+
+ virtual ActionList actions();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlPropertyChanges)
+
+QT_END_HEADER
+
+#endif // QMLPROPERTYCHANGES_H
diff --git a/src/declarative/util/qmlpropertymap.cpp b/src/declarative/util/qmlpropertymap.cpp
new file mode 100644
index 0000000..226f82e
--- /dev/null
+++ b/src/declarative/util/qmlpropertymap.cpp
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlpropertymap.h"
+
+#include "qmlopenmetaobject_p.h"
+
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+//QmlPropertyMapMetaObject lets us listen for changes coming from QML
+//so we can emit the changed signal.
+class QmlPropertyMapMetaObject : public QmlOpenMetaObject
+{
+public:
+ QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv);
+
+protected:
+ virtual void propertyWrite(int index);
+
+private:
+ QmlPropertyMap *map;
+ QmlPropertyMapPrivate *priv;
+};
+
+class QmlPropertyMapPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlPropertyMap)
+public:
+ QmlPropertyMapMetaObject *mo;
+ QStringList keys;
+ void emitChanged(const QString &key);
+};
+
+void QmlPropertyMapPrivate::emitChanged(const QString &key)
+{
+ Q_Q(QmlPropertyMap);
+ emit q->valueChanged(key);
+}
+
+QmlPropertyMapMetaObject::QmlPropertyMapMetaObject(QmlPropertyMap *obj, QmlPropertyMapPrivate *objPriv) : QmlOpenMetaObject(obj)
+{
+ map = obj;
+ priv = objPriv;
+}
+
+void QmlPropertyMapMetaObject::propertyWrite(int index)
+{
+ priv->emitChanged(QString::fromUtf8(name(index)));
+}
+
+/*!
+ \class QmlPropertyMap
+ \brief The QmlPropertyMap class allows you to set key-value pairs that can be used in bindings.
+
+ QmlPropertyMap provides a convenient way to expose domain data to the UI layer.
+ The following example shows how you might declare data in C++ and then
+ access it in QML.
+
+ Setup in C++:
+ \code
+ //create our data
+ QmlPropertyMap ownerData;
+ ownerData.insert("name", QVariant(QString("John Smith")));
+ ownerData.insert("phone", QVariant(QString("555-5555")));
+
+ //expose it to the UI layer
+ QmlContext *ctxt = view->bindContext();
+ ctxt->setProperty("owner", &data);
+ \endcode
+
+ Then, in QML:
+ \code
+ Text { text: owner.name }
+ Text { text: owner.phone }
+ \endcode
+
+ The binding is dynamic - whenever a key's value is updated, anything bound to that
+ key will be updated as well.
+
+ To detect value changes made in the UI layer you can connect to the valueChanged() signal.
+ However, note that valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+
+ \note It is not possible to remove keys from the map; once a key has been added, you can only
+ modify or clear its associated value.
+*/
+
+/*!
+ Constructs a bindable map with parent object \a parent.
+*/
+QmlPropertyMap::QmlPropertyMap(QObject *parent)
+: QObject(*(new QmlPropertyMapPrivate), parent)
+{
+ Q_D(QmlPropertyMap);
+ d->mo = new QmlPropertyMapMetaObject(this, d);
+}
+
+/*!
+ Destroys the bindable map.
+*/
+QmlPropertyMap::~QmlPropertyMap()
+{
+}
+
+/*!
+ Clears the value (if any) associated with \a key.
+*/
+void QmlPropertyMap::clear(const QString &key)
+{
+ Q_D(QmlPropertyMap);
+ d->mo->setValue(key.toUtf8(), QVariant());
+}
+
+/*!
+ Returns the value associated with \a key.
+
+ If no value has been set for this key (or if the value has been cleared),
+ an invalid QVariant is returned.
+*/
+QVariant QmlPropertyMap::value(const QString &key) const
+{
+ Q_D(const QmlPropertyMap);
+ return d->mo->value(key.toUtf8());
+}
+
+/*!
+ Sets the value associated with \a key to \a value.
+
+ If the key doesn't exist, it is automatically created.
+*/
+void QmlPropertyMap::insert(const QString &key, const QVariant &value)
+{
+ Q_D(QmlPropertyMap);
+ if (!d->keys.contains(key))
+ d->keys.append(key);
+ d->mo->setValue(key.toUtf8(), value);
+}
+
+/*!
+ Returns the list of keys.
+
+ Keys that have been cleared will still appear in this list, even though their
+ associated values are invalid QVariants.
+*/
+QStringList QmlPropertyMap::keys() const
+{
+ Q_D(const QmlPropertyMap);
+ return d->keys;
+}
+
+/*!
+ \overload
+
+ Same as size().
+*/
+int QmlPropertyMap::count() const
+{
+ Q_D(const QmlPropertyMap);
+ return d->keys.count();
+}
+
+/*!
+ Returns the number of keys in the map.
+
+ \sa isEmpty(), count()
+*/
+int QmlPropertyMap::size() const
+{
+ Q_D(const QmlPropertyMap);
+ return d->keys.size();
+}
+
+/*!
+ Returns true if the map contains no keys; otherwise returns
+ false.
+
+ \sa size()
+*/
+bool QmlPropertyMap::isEmpty() const
+{
+ Q_D(const QmlPropertyMap);
+ return d->keys.isEmpty();
+}
+
+/*!
+ Returns true if the map contains \a key.
+
+ \sa size()
+*/
+bool QmlPropertyMap::contains(const QString &key) const
+{
+ Q_D(const QmlPropertyMap);
+ return d->keys.contains(key);
+}
+
+/*!
+ Returns the value associated with the key \a key as a modifiable
+ reference.
+
+ If the map contains no item with key \a key, the function inserts
+ an invalid QVariant into the map with key \a key, and
+ returns a reference to it.
+
+ \sa insert(), value()
+*/
+QVariant &QmlPropertyMap::operator[](const QString &key)
+{
+ //### optimize
+ Q_D(QmlPropertyMap);
+ QByteArray utf8key = key.toUtf8();
+ if (!d->keys.contains(key)) {
+ d->keys.append(key);
+ d->mo->setValue(utf8key, QVariant()); //force creation -- needed below
+ }
+
+ return (*(d->mo))[utf8key];
+}
+
+/*!
+ \overload
+
+ Same as value().
+*/
+const QVariant QmlPropertyMap::operator[](const QString &key) const
+{
+ return value(key);
+}
+
+/*!
+ \fn void QmlPropertyMap::valueChanged(const QString &key)
+ This signal is emitted whenever one of the values in the map is changed. \a key
+ is the key corresponding to the value that was changed.
+
+ \note valueChanged() is \bold NOT emitted when changes are made by calling insert()
+ or clear() - it is only emitted when a value is updated from QML.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlpropertymap.h b/src/declarative/util/qmlpropertymap.h
new file mode 100644
index 0000000..bb397fe
--- /dev/null
+++ b/src/declarative/util/qmlpropertymap.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLPROPERTYMAP_H
+#define QMLPROPERTYMAP_H
+
+#include <QtCore/QObject>
+#include <QtCore/QHash>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlPropertyMapPrivate;
+class Q_DECLARATIVE_EXPORT QmlPropertyMap : public QObject
+{
+ Q_OBJECT
+public:
+ QmlPropertyMap(QObject *parent = 0);
+ virtual ~QmlPropertyMap();
+
+ QVariant value(const QString &key) const;
+ void insert(const QString &key, const QVariant &value);
+ void clear(const QString &key);
+
+ Q_INVOKABLE QStringList keys() const;
+
+ int count() const;
+ int size() const;
+ bool isEmpty() const;
+ bool contains(const QString &key) const;
+
+ QVariant &operator[](const QString &key);
+ const QVariant operator[](const QString &key) const;
+
+Q_SIGNALS:
+ void valueChanged(const QString &key);
+
+private:
+ Q_DECLARE_PRIVATE(QmlPropertyMap)
+ Q_DISABLE_COPY(QmlPropertyMap)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmlspringfollow.cpp b/src/declarative/util/qmlspringfollow.cpp
new file mode 100644
index 0000000..764d7f9
--- /dev/null
+++ b/src/declarative/util/qmlspringfollow.cpp
@@ -0,0 +1,464 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlspringfollow_p.h"
+
+#include "qmlanimation_p_p.h"
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+#include <limits.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,SpringFollow,QmlSpringFollow)
+
+class QmlSpringFollowPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlSpringFollow)
+public:
+ QmlSpringFollowPrivate()
+ : currentValue(0), sourceValue(0), maxVelocity(0), lastTime(0)
+ , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.01)
+ , modulus(0.0), useMass(false), haveModulus(false), enabled(true), mode(Track), clock(this) {}
+
+ QmlMetaProperty property;
+ qreal currentValue;
+ qreal sourceValue;
+ qreal maxVelocity;
+ qreal velocityms;
+ int lastTime;
+ qreal mass;
+ qreal spring;
+ qreal damping;
+ qreal velocity;
+ qreal epsilon;
+ qreal modulus;
+
+ bool useMass : 1;
+ bool haveModulus : 1;
+ bool enabled : 1;
+
+ enum Mode {
+ Track,
+ Velocity,
+ Spring
+ };
+ Mode mode;
+
+ void tick(int);
+ void updateMode();
+ void start();
+ void stop();
+
+ QTickAnimationProxy<QmlSpringFollowPrivate, &QmlSpringFollowPrivate::tick> clock;
+};
+
+void QmlSpringFollowPrivate::tick(int time)
+{
+ Q_Q(QmlSpringFollow);
+
+ int elapsed = time - lastTime;
+ if (!elapsed)
+ return;
+ qreal srcVal = sourceValue;
+ if (haveModulus) {
+ currentValue = fmod(currentValue, modulus);
+ srcVal = fmod(srcVal, modulus);
+ }
+ if (mode == Spring) {
+ if (elapsed < 16) // capped at 62fps.
+ return;
+ // Real men solve the spring DEs using RK4.
+ // We'll do something much simpler which gives a result that looks fine.
+ int count = elapsed / 16;
+ for (int i = 0; i < count; ++i) {
+ qreal diff = srcVal - currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (useMass)
+ velocity = velocity + (spring * diff - damping * velocity) / mass;
+ else
+ velocity = velocity + spring * diff - damping * velocity;
+ if (maxVelocity > 0.) {
+ // limit velocity
+ if (velocity > maxVelocity)
+ velocity = maxVelocity;
+ else if (velocity < -maxVelocity)
+ velocity = -maxVelocity;
+ }
+ currentValue += velocity * 16.0 / 1000.0;
+ if (haveModulus) {
+ currentValue = fmod(currentValue, modulus);
+ if (currentValue < 0.0)
+ currentValue += modulus;
+ }
+ }
+ if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) {
+ velocity = 0.0;
+ currentValue = srcVal;
+ clock.stop();
+ }
+ lastTime = time - (elapsed - count * 16);
+ } else {
+ qreal moveBy = elapsed * velocityms;
+ qreal diff = srcVal - currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (diff > 0) {
+ currentValue += moveBy;
+ if (haveModulus)
+ currentValue = fmod(currentValue, modulus);
+ if (currentValue > sourceValue) {
+ currentValue = sourceValue;
+ clock.stop();
+ }
+ } else {
+ currentValue -= moveBy;
+ if (haveModulus && currentValue < 0.0)
+ currentValue = fmod(currentValue, modulus) + modulus;
+ if (currentValue < sourceValue) {
+ currentValue = sourceValue;
+ clock.stop();
+ }
+ }
+ lastTime = time;
+ }
+ property.write(currentValue);
+ emit q->valueChanged(currentValue);
+ if (clock.state() != QAbstractAnimation::Running)
+ emit q->syncChanged();
+}
+
+void QmlSpringFollowPrivate::updateMode()
+{
+ if (spring == 0. && maxVelocity == 0.)
+ mode = Track;
+ else if (spring > 0.)
+ mode = Spring;
+ else
+ mode = Velocity;
+}
+
+void QmlSpringFollowPrivate::start()
+{
+ if (!enabled)
+ return;
+
+ Q_Q(QmlSpringFollow);
+ if (mode == QmlSpringFollowPrivate::Track) {
+ currentValue = sourceValue;
+ property.write(currentValue);
+ } else if (sourceValue != currentValue && clock.state() != QAbstractAnimation::Running) {
+ lastTime = 0;
+ currentValue = property.read().toReal();
+ clock.start(); // infinity??
+ emit q->syncChanged();
+ }
+}
+
+void QmlSpringFollowPrivate::stop()
+{
+ clock.stop();
+}
+
+/*!
+ \qmlclass SpringFollow QmlSpringFollow
+ \brief The SpringFollow element allows a property to track a value.
+
+ In example below, \e rect2 will follow \e rect1 moving with a velocity of up to 200:
+ \code
+ Rectangle {
+ id: rect1
+ width: 20; height: 20
+ color: "#00ff00"
+ y: 200 //initial value
+ y: SequentialAnimation {
+ running: true
+ repeat: true
+ NumberAnimation {
+ to: 200
+ easing: "easeOutBounce(amplitude:100)"
+ duration: 2000
+ }
+ PauseAnimation { duration: 1000 }
+ }
+ }
+ Rectangle {
+ id: rect2
+ x: rect1.width
+ width: 20; height: 20
+ color: "#ff0000"
+ y: SpringFollow { source: rect1.y; velocity: 200 }
+ }
+ \endcode
+
+ \sa EaseFollow
+*/
+
+QmlSpringFollow::QmlSpringFollow(QObject *parent)
+: QObject(*(new QmlSpringFollowPrivate),parent)
+{
+}
+
+QmlSpringFollow::~QmlSpringFollow()
+{
+}
+
+void QmlSpringFollow::setTarget(const QmlMetaProperty &property)
+{
+ Q_D(QmlSpringFollow);
+ d->property = property;
+ d->currentValue = property.read().toReal();
+}
+
+qreal QmlSpringFollow::sourceValue() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->sourceValue;
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::source
+ This property holds the source value which will be tracked.
+
+ Bind to a property in order to track its changes.
+*/
+
+void QmlSpringFollow::setSourceValue(qreal value)
+{
+ Q_D(QmlSpringFollow);
+ if (d->clock.state() == QAbstractAnimation::Running && d->sourceValue == value)
+ return;
+
+ d->sourceValue = value;
+ d->start();
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::velocity
+ This property holds the maximum velocity allowed when tracking the source.
+*/
+
+qreal QmlSpringFollow::velocity() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->maxVelocity;
+}
+
+void QmlSpringFollow::setVelocity(qreal velocity)
+{
+ Q_D(QmlSpringFollow);
+ d->maxVelocity = velocity;
+ d->velocityms = velocity / 1000.0;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::spring
+ This property holds the spring constant
+
+ The spring constant describes how strongly the target is pulled towards the
+ source. Setting spring to 0 turns off spring tracking. Useful values 0 - 5.0
+
+ When a spring constant is set and the velocity property is greater than 0,
+ velocity limits the maximum speed.
+*/
+qreal QmlSpringFollow::spring() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->spring;
+}
+
+void QmlSpringFollow::setSpring(qreal spring)
+{
+ Q_D(QmlSpringFollow);
+ d->spring = spring;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::damping
+ This property holds the spring damping constant
+
+ The damping constant describes how quickly a sprung follower comes to rest.
+ Useful range is 0 - 1.0
+*/
+qreal QmlSpringFollow::damping() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->damping;
+}
+
+void QmlSpringFollow::setDamping(qreal damping)
+{
+ Q_D(QmlSpringFollow);
+ if (damping > 1.)
+ damping = 1.;
+
+ d->damping = damping;
+}
+
+
+/*!
+ \qmlproperty qreal SpringFollow::epsilon
+ This property holds the spring epsilon
+
+ The epsilon is the rate and amount of change in the value which is close enough
+ to 0 to be considered equal to zero. This will depend on the usage of the value.
+ For pixel positions, 0.25 would suffice. For scale, 0.005 will suffice.
+
+ The default is 0.01. Tuning this value can provide small performance improvements.
+*/
+qreal QmlSpringFollow::epsilon() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->epsilon;
+}
+
+void QmlSpringFollow::setEpsilon(qreal epsilon)
+{
+ Q_D(QmlSpringFollow);
+ d->epsilon = epsilon;
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::modulus
+ This property holds the modulus value.
+
+ Setting a \a modulus forces the target value to "wrap around" at the modulus.
+ For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10.
+*/
+qreal QmlSpringFollow::modulus() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->modulus;
+}
+
+void QmlSpringFollow::setModulus(qreal modulus)
+{
+ Q_D(QmlSpringFollow);
+ if (d->modulus != modulus) {
+ d->haveModulus = modulus != 0.0;
+ d->modulus = modulus;
+ emit modulusChanged();
+ }
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::mass
+ This property holds the "mass" of the property being moved.
+
+ mass is 1.0 by default. Setting a different mass changes the dynamics of
+ a \l spring follow.
+*/
+qreal QmlSpringFollow::mass() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->mass;
+}
+
+void QmlSpringFollow::setMass(qreal mass)
+{
+ Q_D(QmlSpringFollow);
+ if (d->mass != mass && mass > 0.0) {
+ d->useMass = mass != 1.0;
+ d->mass = mass;
+ emit massChanged();
+ }
+}
+
+/*!
+ \qmlproperty qreal SpringFollow::value
+ The current value.
+*/
+
+/*!
+ \qmlproperty bool SpringFollow::enabled
+ This property holds whether the target will track the source.
+*/
+bool QmlSpringFollow::enabled() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->enabled;
+}
+
+void QmlSpringFollow::setEnabled(bool enabled)
+{
+ Q_D(QmlSpringFollow);
+ d->enabled = enabled;
+ if (enabled)
+ d->start();
+ else
+ d->stop();
+}
+
+/*!
+ \qmlproperty bool SpringFollow::inSync
+ This property is true when target is equal to the source; otherwise
+ false. If inSync is true the target is not being animated.
+
+ If \l enabled is false then inSync will also be false.
+*/
+bool QmlSpringFollow::inSync() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->enabled && d->clock.state() != QAbstractAnimation::Running;
+}
+
+qreal QmlSpringFollow::value() const
+{
+ Q_D(const QmlSpringFollow);
+ return d->currentValue;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlspringfollow_p.h b/src/declarative/util/qmlspringfollow_p.h
new file mode 100644
index 0000000..7731b9e
--- /dev/null
+++ b/src/declarative/util/qmlspringfollow_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSMOOTHFOLLOW_H
+#define QMLSMOOTHFOLLOW_H
+
+#include <qmlpropertyvaluesource.h>
+#include <qml.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlSpringFollowPrivate;
+class Q_DECLARATIVE_EXPORT QmlSpringFollow : public QObject,
+ public QmlPropertyValueSource
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlSpringFollow)
+ Q_INTERFACES(QmlPropertyValueSource)
+
+ Q_PROPERTY(qreal source READ sourceValue WRITE setSourceValue)
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity)
+ Q_PROPERTY(qreal spring READ spring WRITE setSpring)
+ Q_PROPERTY(qreal damping READ damping WRITE setDamping)
+ Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled)
+ Q_PROPERTY(qreal value READ value NOTIFY valueChanged)
+ Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged)
+ Q_PROPERTY(qreal mass READ mass WRITE setMass NOTIFY massChanged)
+ Q_PROPERTY(bool inSync READ inSync NOTIFY syncChanged)
+
+public:
+ QmlSpringFollow(QObject *parent=0);
+ ~QmlSpringFollow();
+
+ virtual void setTarget(const QmlMetaProperty &);
+
+ qreal sourceValue() const;
+ void setSourceValue(qreal value);
+ qreal velocity() const;
+ void setVelocity(qreal velocity);
+ qreal spring() const;
+ void setSpring(qreal spring);
+ qreal damping() const;
+ void setDamping(qreal damping);
+ qreal epsilon() const;
+ void setEpsilon(qreal epsilon);
+ qreal mass() const;
+ void setMass(qreal modulus);
+ qreal modulus() const;
+ void setModulus(qreal modulus);
+ bool enabled() const;
+ void setEnabled(bool enabled);
+ bool inSync() const;
+
+ qreal value() const;
+
+Q_SIGNALS:
+ void valueChanged(qreal);
+ void modulusChanged();
+ void massChanged();
+ void syncChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlSpringFollow)
+
+QT_END_HEADER
+
+#endif // QMLSMOOTHFOLLOW_H
diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp
new file mode 100644
index 0000000..cae8054
--- /dev/null
+++ b/src/declarative/util/qmlstate.cpp
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlstate_p_p.h"
+#include "qmlstate_p.h"
+
+#include "qmltransition_p.h"
+#include "qmlstategroup_p.h"
+#include "qmlstateoperations_p.h"
+#include "qmlanimation_p.h"
+#include "qmlanimation_p_p.h"
+
+#include <qmlbinding.h>
+#include <qmlglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+QmlAction::QmlAction()
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), toBinding(0), event(0),
+ specifiedObject(0)
+{
+}
+
+QmlAction::QmlAction(QObject *target, const QString &propertyName,
+ const QVariant &value)
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), toValue(value), fromBinding(0),
+ toBinding(0), event(0), specifiedObject(target),
+ specifiedProperty(propertyName)
+{
+ property = QmlMetaProperty::createProperty(target, propertyName);
+ if (property.isValid())
+ fromValue = property.read();
+}
+
+QmlActionEvent::~QmlActionEvent()
+{
+}
+
+QString QmlActionEvent::typeName() const
+{
+ return QString();
+}
+
+void QmlActionEvent::execute()
+{
+}
+
+bool QmlActionEvent::isReversable()
+{
+ return false;
+}
+
+void QmlActionEvent::reverse()
+{
+}
+
+QList<QmlAction> QmlActionEvent::extraActions()
+{
+ return QList<QmlAction>();
+}
+
+bool QmlActionEvent::changesBindings()
+{
+ return false;
+}
+
+void QmlActionEvent::clearForwardBindings()
+{
+}
+
+void QmlActionEvent::clearReverseBindings()
+{
+}
+
+bool QmlActionEvent::override(QmlActionEvent *other)
+{
+ Q_UNUSED(other);
+ return false;
+}
+
+/*!
+ \internal
+*/
+QmlStateOperation::QmlStateOperation(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlclass State QmlState
+ \brief The State element defines configurations of objects and properties.
+
+ A state is specified as a set of batched changes from the default configuration.
+
+ Note that setting the state of an object from within another state of the same object is
+ inadvisible. Not only would this have the same effect as going directly to the second state
+ it may cause the program to crash.
+
+ \sa {qmlstates}{States}, {state-transitions}{Transitions}
+*/
+
+/*!
+ \internal
+ \class QmlState
+ \brief The QmlState class allows you to define configurations of objects and properties.
+
+ \ingroup group_states
+
+ QmlState allows you to specify a state as a set of batched changes from the default
+ configuration.
+
+ \sa {states-transitions}{States and Transitions}
+*/
+
+QML_DEFINE_TYPE(Qt,4,6,State,QmlState)
+QmlState::QmlState(QObject *parent)
+: QObject(*(new QmlStatePrivate), parent)
+{
+ Q_D(QmlState);
+ d->transitionManager.setState(this);
+}
+
+QmlState::~QmlState()
+{
+ Q_D(QmlState);
+ if (d->group)
+ d->group->removeState(this);
+}
+
+/*!
+ \qmlproperty string State::name
+ This property holds the name of the state
+
+ Each state should have a unique name.
+*/
+QString QmlState::name() const
+{
+ Q_D(const QmlState);
+ return d->name;
+}
+
+void QmlState::setName(const QString &n)
+{
+ Q_D(QmlState);
+ d->name = n;
+}
+
+bool QmlState::isWhenKnown() const
+{
+ Q_D(const QmlState);
+ return d->when != 0;
+}
+
+/*!
+ \qmlproperty bool State::when
+ This property holds when the state should be applied
+
+ This should be set to an expression that evaluates to true when you want the state to
+ be applied.
+*/
+QmlBinding *QmlState::when() const
+{
+ Q_D(const QmlState);
+ return d->when;
+}
+
+void QmlState::setWhen(QmlBinding *when)
+{
+ Q_D(QmlState);
+ d->when = when;
+ if (d->group)
+ d->group->updateAutoState();
+}
+
+/*!
+ \qmlproperty string State::extend
+ This property holds the state that this state extends
+
+ The state being extended is treated as the base state in regards to
+ the changes specified by the extending state.
+*/
+QString QmlState::extends() const
+{
+ Q_D(const QmlState);
+ return d->extends;
+}
+
+void QmlState::setExtends(const QString &extends)
+{
+ Q_D(QmlState);
+ d->extends = extends;
+}
+
+/*!
+ \qmlproperty list<Change> State::changes
+ This property holds the changes to apply for this state
+ \default
+
+ By default these changes are applied against the default state. If the state
+ extends another state, then the changes are applied against the state being
+ extended.
+*/
+QmlList<QmlStateOperation *> *QmlState::changes()
+{
+ Q_D(QmlState);
+ return &d->operations;
+}
+
+QmlState &QmlState::operator<<(QmlStateOperation *op)
+{
+ Q_D(QmlState);
+ d->operations.append(op);
+ return *this;
+}
+
+void QmlStatePrivate::complete()
+{
+ Q_Q(QmlState);
+
+ for (int ii = 0; ii < reverting.count(); ++ii) {
+ for (int jj = 0; jj < revertList.count(); ++jj) {
+ if (revertList.at(jj).property == reverting.at(ii)) {
+ revertList.removeAt(jj);
+ break;
+ }
+ }
+ }
+ reverting.clear();
+
+ emit q->completed();
+}
+
+// Generate a list of actions for this state. This includes coelescing state
+// actions that this state "extends"
+QmlStateOperation::ActionList
+QmlStatePrivate::generateActionList(QmlStateGroup *group) const
+{
+ QmlStateOperation::ActionList applyList;
+ if (inState)
+ return applyList;
+
+ // Prevent "extends" recursion
+ inState = true;
+
+ if (!extends.isEmpty()) {
+ QList<QmlState *> states = group->states();
+ for (int ii = 0; ii < states.count(); ++ii)
+ if (states.at(ii)->name() == extends)
+ applyList = static_cast<QmlStatePrivate*>(states.at(ii)->d_func())->generateActionList(group);
+ }
+
+ foreach(QmlStateOperation *op, operations)
+ applyList << op->actions();
+
+ inState = false;
+ return applyList;
+}
+
+QmlStateGroup *QmlState::stateGroup() const
+{
+ Q_D(const QmlState);
+ return d->group;
+}
+
+void QmlState::setStateGroup(QmlStateGroup *group)
+{
+ Q_D(QmlState);
+ d->group = group;
+}
+
+void QmlState::cancel()
+{
+ Q_D(QmlState);
+ d->transitionManager.cancel();
+}
+
+void QmlAction::deleteFromBinding()
+{
+ if (fromBinding) {
+ property.setBinding(0);
+ fromBinding->destroy();
+ fromBinding = 0;
+ }
+}
+
+void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *revert)
+{
+ Q_D(QmlState);
+
+ qmlExecuteDeferred(this);
+
+ cancel();
+ if (revert)
+ revert->cancel();
+ d->revertList.clear();
+ d->reverting.clear();
+
+ if (revert) {
+ QmlStatePrivate *revertPrivate =
+ static_cast<QmlStatePrivate*>(revert->d_func());
+ d->revertList = revertPrivate->revertList;
+ revertPrivate->revertList.clear();
+ }
+
+ // List of actions caused by this state
+ QmlStateOperation::ActionList applyList = d->generateActionList(group);
+
+ // List of actions that need to be reverted to roll back (just) this state
+ QmlStatePrivate::SimpleActionList additionalReverts;
+ // First add the reverse of all the applyList actions
+ for (int ii = 0; ii < applyList.count(); ++ii) {
+ QmlAction &action = applyList[ii];
+
+ bool found = false;
+
+ int jj;
+ if (action.event) {
+ if (!action.event->isReversable())
+ continue;
+ for (jj = 0; jj < d->revertList.count(); ++jj) {
+ QmlActionEvent *event = d->revertList.at(jj).event;
+ if (event && event->typeName() == action.event->typeName()) {
+ if (action.event->override(event)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found || action.event != d->revertList.at(jj).event)
+ action.event->saveOriginals();
+ else if (action.event->isRewindable())
+ action.event->saveCurrentValues();
+ } else {
+ action.fromBinding = action.property.binding();
+
+ for (jj = 0; jj < d->revertList.count(); ++jj) {
+ if (d->revertList.at(jj).property == action.property) {
+ found = true;
+ 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
+ QmlSimpleAction r(action);
+ additionalReverts << r;
+ }
+ } else if (d->revertList.at(jj).binding != action.fromBinding) {
+ action.deleteFromBinding();
+ }
+ }
+
+ // Any reverts from a previous state that aren't carried forth
+ // into this state need to be translated into apply actions
+ for (int ii = 0; ii < d->revertList.count(); ++ii) {
+ bool found = false;
+ if (d->revertList.at(ii).event) {
+ QmlActionEvent *event = d->revertList.at(ii).event;
+ if (!event->isReversable())
+ continue;
+ for (int jj = 0; !found && jj < applyList.count(); ++jj) {
+ const QmlAction &action = applyList.at(jj);
+ if (action.event && action.event->typeName() == event->typeName()) {
+ if (action.event->override(event))
+ found = true;
+ }
+ }
+ } else {
+ for (int jj = 0; !found && jj < applyList.count(); ++jj) {
+ const QmlAction &action = applyList.at(jj);
+ if (action.property == d->revertList.at(ii).property)
+ found = true;
+ }
+ }
+ if (!found) {
+ QVariant cur = d->revertList.at(ii).property.read();
+ QmlAbstractBinding *delBinding = d->revertList.at(ii).property.setBinding(0);
+ if (delBinding)
+ delBinding->destroy();
+
+ QmlAction a;
+ a.property = d->revertList.at(ii).property;
+ a.fromValue = cur;
+ a.toValue = d->revertList.at(ii).value;
+ a.toBinding = d->revertList.at(ii).binding;
+ a.specifiedObject = d->revertList.at(ii).specifiedObject;
+ a.specifiedProperty = d->revertList.at(ii).specifiedProperty;
+ a.event = d->revertList.at(ii).event;
+ a.reverseEvent = d->revertList.at(ii).reverseEvent;
+ if (a.event && a.event->isRewindable())
+ a.event->saveCurrentValues();
+ applyList << a;
+ // Store these special reverts in the reverting list
+ d->reverting << d->revertList.at(ii).property;
+ }
+ }
+ // All the local reverts now become part of the ongoing revertList
+ d->revertList << additionalReverts;
+
+ // Output for debugging
+ if (stateChangeDebug()) {
+ foreach(const QmlAction &action, applyList) {
+ if (action.event)
+ qWarning() << " QmlAction event:" << action.event->typeName();
+ else
+ qWarning() << " QmlAction:" << action.property.object()
+ << action.property.name() << "From:" << action.fromValue
+ << "To:" << action.toValue;
+ }
+ }
+
+ d->transitionManager.transition(applyList, trans);
+}
+
+QML_DEFINE_NOCREATE_TYPE(QmlStateOperation)
+QmlStateOperation::ActionList QmlStateOperation::actions()
+{
+ return ActionList();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h
new file mode 100644
index 0000000..5862c02
--- /dev/null
+++ b/src/declarative/util/qmlstate_p.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSTATE_H
+#define QMLSTATE_H
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlActionEvent;
+class QmlBinding;
+class Q_DECLARATIVE_EXPORT QmlAction
+{
+public:
+ QmlAction();
+ QmlAction(QObject *, const QString &, const QVariant &);
+
+ bool restore:1;
+ bool actionDone:1;
+ bool reverseEvent:1;
+ bool deletableToBinding:1;
+
+ QmlMetaProperty property;
+ QVariant fromValue;
+ QVariant toValue;
+
+ QmlAbstractBinding *fromBinding;
+ QmlAbstractBinding *toBinding;
+ QmlActionEvent *event;
+
+ //strictly for matching
+ QObject *specifiedObject;
+ QString specifiedProperty;
+
+ void deleteFromBinding();
+};
+
+class QmlActionEvent
+{
+public:
+ virtual ~QmlActionEvent();
+ virtual QString typeName() const;
+
+ virtual void execute();
+ virtual bool isReversable();
+ virtual void reverse();
+ virtual void saveOriginals() {}
+
+ virtual bool isRewindable() { return isReversable(); }
+ virtual void rewind() {}
+ virtual void saveCurrentValues() {}
+
+ //virtual bool hasExtraActions();
+ virtual QList<QmlAction> extraActions();
+
+ virtual bool changesBindings();
+ virtual void clearForwardBindings();
+ virtual void clearReverseBindings();
+ virtual bool override(QmlActionEvent*other);
+};
+
+//### rename to QmlStateChange?
+class QmlStateGroup;
+class Q_DECLARATIVE_EXPORT QmlStateOperation : public QObject
+{
+ Q_OBJECT
+public:
+ QmlStateOperation(QObject *parent = 0)
+ : QObject(parent) {}
+ typedef QList<QmlAction> ActionList;
+
+ virtual ActionList actions();
+
+protected:
+ QmlStateOperation(QObjectPrivate &dd, QObject *parent = 0);
+};
+
+typedef QmlStateOperation::ActionList QmlStateActions;
+
+class QmlTransition;
+class QmlStatePrivate;
+class Q_DECLARATIVE_EXPORT QmlState : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QmlBinding *when READ when WRITE setWhen)
+ Q_PROPERTY(QString extend READ extends WRITE setExtends)
+ Q_PROPERTY(QmlList<QmlStateOperation *>* changes READ changes)
+ Q_CLASSINFO("DefaultProperty", "changes")
+ Q_CLASSINFO("DeferredPropertyNames", "changes")
+
+public:
+ QmlState(QObject *parent=0);
+ virtual ~QmlState();
+
+ QString name() const;
+ void setName(const QString &);
+
+ /*'when' is a QmlBinding to limit state changes oscillation
+ due to the unpredictable order of evaluation of bound expressions*/
+ bool isWhenKnown() const;
+ QmlBinding *when() const;
+ void setWhen(QmlBinding *);
+
+ QString extends() const;
+ void setExtends(const QString &);
+
+ QmlList<QmlStateOperation *> *changes();
+ QmlState &operator<<(QmlStateOperation *);
+
+ void apply(QmlStateGroup *, QmlTransition *, QmlState *revert);
+ void cancel();
+
+ QmlStateGroup *stateGroup() const;
+ void setStateGroup(QmlStateGroup *);
+
+Q_SIGNALS:
+ void completed();
+
+private:
+ Q_DECLARE_PRIVATE(QmlState)
+ Q_DISABLE_COPY(QmlState)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlStateOperation)
+QML_DECLARE_TYPE(QmlState)
+
+QT_END_HEADER
+
+#endif // QMLSTATE_H
diff --git a/src/declarative/util/qmlstate_p_p.h b/src/declarative/util/qmlstate_p_p.h
new file mode 100644
index 0000000..235fe62
--- /dev/null
+++ b/src/declarative/util/qmlstate_p_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSTATE_P_H
+#define QMLSTATE_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 "qmlstate_p.h"
+
+#include "qmlanimation_p_p.h"
+#include "qmltransitionmanager_p_p.h"
+
+#include <qmlguard_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlSimpleAction
+{
+public:
+ enum State { StartState, EndState };
+ QmlSimpleAction(const QmlAction &a, State state = StartState)
+ {
+ property = a.property;
+ specifiedObject = a.specifiedObject;
+ specifiedProperty = a.specifiedProperty;
+ event = a.event;
+ if (state == StartState) {
+ value = a.fromValue;
+ binding = property.binding();
+ reverseEvent = true;
+ } else {
+ value = a.toValue;
+ binding = a.toBinding;
+ reverseEvent = false;
+ }
+ }
+
+ QmlMetaProperty property;
+ QVariant value;
+ QmlAbstractBinding *binding;
+ QObject *specifiedObject;
+ QString specifiedProperty;
+ QmlActionEvent *event;
+ bool reverseEvent;
+};
+
+class QmlStatePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlState)
+
+public:
+ QmlStatePrivate()
+ : when(0), inState(false), group(0) {}
+
+ typedef QList<QmlSimpleAction> SimpleActionList;
+
+ QString name;
+ QmlBinding *when;
+
+ class OperationList;
+ struct OperationGuard : public QmlGuard<QmlStateOperation>
+ {
+ OperationGuard(QObject *obj, OperationList *l) : list(l) { (QmlGuard<QObject>&)*this = obj; }
+ OperationList *list;
+ void objectDestroyed(QmlStateOperation *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+
+ class OperationList : public QList<OperationGuard>, public QmlList<QmlStateOperation*>
+ {
+ public:
+ virtual void append(QmlStateOperation* v) { QList<OperationGuard>::append(OperationGuard(v, this)); }
+ virtual void insert(int i, QmlStateOperation* v) { QList<OperationGuard>::insert(i, OperationGuard(v, this)); }
+ virtual void clear() { QList<OperationGuard>::clear(); }
+ virtual QmlStateOperation* at(int i) const { return QList<OperationGuard>::at(i); }
+ virtual void removeAt(int i) { QList<OperationGuard>::removeAt(i); }
+ virtual int count() const { return QList<OperationGuard>::count(); }
+ };
+ OperationList operations;
+
+ QmlTransitionManager transitionManager;
+
+ SimpleActionList revertList;
+ QList<QmlMetaProperty> reverting;
+ QString extends;
+ mutable bool inState;
+ QmlStateGroup *group;
+
+ QmlStateOperation::ActionList generateActionList(QmlStateGroup *) const;
+ void complete();
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLSTATE_P_H
diff --git a/src/declarative/util/qmlstategroup.cpp b/src/declarative/util/qmlstategroup.cpp
new file mode 100644
index 0000000..d4db2b9
--- /dev/null
+++ b/src/declarative/util/qmlstategroup.cpp
@@ -0,0 +1,423 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlstategroup_p.h"
+
+#include "qmltransition_p.h"
+#include "qmlstate_p_p.h"
+
+#include <qmlbinding.h>
+#include <qmlglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+QML_DEFINE_TYPE(Qt,4,6,StateGroup,QmlStateGroup)
+
+class QmlStateGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlStateGroup)
+public:
+ QmlStateGroupPrivate(QmlStateGroup *p)
+ : nullState(0), states(p), componentComplete(true),
+ ignoreTrans(false), applyingState(false) {}
+
+ QString currentState;
+ QmlState *nullState;
+
+ struct StateList : public QmlConcreteList<QmlState *>
+ {
+ StateList(QmlStateGroup *g)
+ :group(g) {}
+ void append(QmlState *s) {
+ QmlConcreteList<QmlState *>::append(s);
+ if (s) s->setStateGroup(group);
+ }
+ private:
+ QmlStateGroup *group;
+ };
+ StateList states;
+
+ QmlConcreteList<QmlTransition *> transitions;
+ bool componentComplete;
+ bool ignoreTrans;
+ bool applyingState;
+
+ QmlTransition *findTransition(const QString &from, const QString &to);
+ void setCurrentStateInternal(const QString &state, bool = false);
+ bool updateAutoState();
+};
+
+/*!
+ \qmlclass StateGroup QmlStateGroup
+ \brief The StateGroup element provides state support for non-Item elements.
+
+ Item (and all dervied elements) provides built in support for states and transitions
+ via its state, states and transitions properties. StateGroup provides an easy way to
+ use this support in other (non-Item-derived) elements.
+
+ \qml
+ MyCustomObject {
+ StateGroup {
+ id: myStateGroup
+ states: State {
+ name: "state1"
+ ...
+ }
+ transitions: Transition {
+ ...
+ }
+ }
+
+ onSomethingHappened: myStateGroup.state = "state1";
+ }
+ \endqml
+
+ \sa {qmlstate}{States} {state-transitions}{Transitions}
+*/
+
+QmlStateGroup::QmlStateGroup(QObject *parent)
+ : QObject(*(new QmlStateGroupPrivate(this)), parent)
+{
+}
+
+QmlStateGroup::~QmlStateGroup()
+{
+ Q_D(const QmlStateGroup);
+ for (int i = 0; i < d->states.count(); ++i)
+ d->states.at(i)->setStateGroup(0);
+}
+
+QList<QmlState *> QmlStateGroup::states() const
+{
+ Q_D(const QmlStateGroup);
+ return d->states;
+}
+
+/*!
+ \qmlproperty list<State> StateGroup::states
+ This property holds a list of states defined by the state group.
+
+ \qml
+ StateGroup {
+ states: [
+ State { ... },
+ State { ... }
+ ...
+ ]
+ }
+ \endqml
+
+ \sa {qmlstate}{States}
+*/
+QmlList<QmlState *>* QmlStateGroup::statesProperty()
+{
+ Q_D(QmlStateGroup);
+ return &(d->states);
+}
+
+/*!
+ \qmlproperty list<Transition> StateGroup::transitions
+ This property holds a list of transitions defined by the state group.
+
+ \qml
+ StateGroup {
+ transitions: [
+ Transition { ... },
+ Transition { ... }
+ ...
+ ]
+ }
+ \endqml
+
+ \sa {state-transitions}{Transitions}
+*/
+QmlList<QmlTransition *>* QmlStateGroup::transitionsProperty()
+{
+ Q_D(QmlStateGroup);
+ return &(d->transitions);
+}
+
+/*!
+ \qmlproperty string StateGroup::state
+
+ This property holds the name of the current state of the state group.
+
+ This property is often used in scripts to change between states. For
+ example:
+
+ \qml
+ Script {
+ function toggle() {
+ if (button.state == 'On')
+ button.state = 'Off';
+ else
+ button.state = 'On';
+ }
+ }
+ \endqml
+
+ If the state group is in its base state (i.e. no explicit state has been
+ set), \c state will be a blank string. Likewise, you can return a
+ state group to its base state by setting its current state to \c ''.
+
+ \sa {qmlstates}{States}
+*/
+QString QmlStateGroup::state() const
+{
+ Q_D(const QmlStateGroup);
+ return d->currentState;
+}
+
+void QmlStateGroup::setState(const QString &state)
+{
+ Q_D(QmlStateGroup);
+ if (d->currentState == state)
+ return;
+
+ d->setCurrentStateInternal(state);
+}
+
+void QmlStateGroup::classBegin()
+{
+ Q_D(QmlStateGroup);
+ d->componentComplete = false;
+}
+
+void QmlStateGroup::componentComplete()
+{
+ Q_D(QmlStateGroup);
+ d->componentComplete = true;
+
+ if (d->updateAutoState()) {
+ return;
+ } else if (!d->currentState.isEmpty()) {
+ QString cs = d->currentState;
+ d->currentState = QString();
+ d->setCurrentStateInternal(cs, true);
+ }
+}
+
+/*!
+ Returns true if the state was changed, otherwise false.
+*/
+bool QmlStateGroup::updateAutoState()
+{
+ Q_D(QmlStateGroup);
+ return d->updateAutoState();
+}
+
+bool QmlStateGroupPrivate::updateAutoState()
+{
+ Q_Q(QmlStateGroup);
+ if (!componentComplete)
+ return false;
+
+ bool revert = false;
+ for (int ii = 0; ii < states.count(); ++ii) {
+ QmlState *state = states.at(ii);
+ if (state->isWhenKnown()) {
+ if (!state->name().isEmpty()) {
+ if (state->when() && state->when()->value().toBool()) {
+ if (stateChangeDebug())
+ qWarning() << "Setting auto state due to:"
+ << state->when()->expression();
+ if (currentState != state->name()) {
+ q->setState(state->name());
+ return true;
+ } else {
+ return false;
+ }
+ } else if (state->name() == currentState) {
+ revert = true;
+ }
+ }
+ }
+ }
+ if (revert) {
+ bool rv = currentState != QString();
+ q->setState(QString());
+ return rv;
+ } else {
+ return false;
+ }
+}
+
+QmlTransition *QmlStateGroupPrivate::findTransition(const QString &from, const QString &to)
+{
+ QmlTransition *highest = 0;
+ int score = 0;
+ bool reversed = false;
+ bool done = false;
+
+ for (int ii = 0; !done && ii < transitions.count(); ++ii) {
+ QmlTransition *t = transitions.at(ii);
+ for (int ii = 0; ii < 2; ++ii)
+ {
+ if (ii && (!t->reversible() ||
+ (t->fromState() == QLatin1String("*") &&
+ t->toState() == QLatin1String("*"))))
+ break;
+ QStringList fromState;
+ QStringList toState;
+
+ fromState = t->fromState().split(QLatin1Char(','));
+ toState = t->toState().split(QLatin1Char(','));
+ if (ii == 1)
+ qSwap(fromState, toState);
+ int tScore = 0;
+ if (fromState.contains(from))
+ tScore += 2;
+ else if (fromState.contains(QLatin1String("*")))
+ tScore += 1;
+ else
+ continue;
+
+ if (toState.contains(to))
+ tScore += 2;
+ else if (toState.contains(QLatin1String("*")))
+ tScore += 1;
+ else
+ continue;
+
+ if (ii == 1)
+ reversed = true;
+ else
+ reversed = false;
+
+ if (tScore == 4) {
+ highest = t;
+ done = true;
+ break;
+ } else if (tScore > score) {
+ score = tScore;
+ highest = t;
+ }
+ }
+ }
+
+ if (highest)
+ highest->setReversed(reversed);
+
+ return highest;
+}
+
+void QmlStateGroupPrivate::setCurrentStateInternal(const QString &state,
+ bool ignoreTrans)
+{
+ Q_Q(QmlStateGroup);
+ if (!componentComplete) {
+ currentState = state;
+ return;
+ }
+
+ if (applyingState) {
+ qWarning() << "Can't apply a state change as part of a state definition.";
+ return;
+ }
+
+ applyingState = true;
+
+ QmlTransition *transition = (ignoreTrans || ignoreTrans) ? 0 : findTransition(currentState, state);
+ if (stateChangeDebug()) {
+ qWarning() << this << "Changing state. From" << currentState << ". To" << state;
+ if (transition)
+ qWarning() << " using transition" << transition->fromState()
+ << transition->toState();
+ }
+
+ QmlState *oldState = 0;
+ if (!currentState.isEmpty()) {
+ for (int ii = 0; ii < states.count(); ++ii) {
+ if (states.at(ii)->name() == currentState) {
+ oldState = states.at(ii);
+ break;
+ }
+ }
+ }
+
+ currentState = state;
+ emit q->stateChanged(currentState);
+
+ QmlState *newState = 0;
+ for (int ii = 0; ii < states.count(); ++ii) {
+ if (states.at(ii)->name() == currentState) {
+ newState = states.at(ii);
+ break;
+ }
+ }
+
+ if (oldState == 0 || newState == 0) {
+ if (!nullState) { nullState = new QmlState; QmlGraphics_setParent_noEvent(nullState, q); }
+ if (!oldState) oldState = nullState;
+ if (!newState) newState = nullState;
+ }
+
+ newState->apply(q, transition, oldState);
+ applyingState = false;
+ if (!transition)
+ static_cast<QmlStatePrivate*>(QObjectPrivate::get(newState))->complete();
+}
+
+QmlState *QmlStateGroup::findState(const QString &name) const
+{
+ Q_D(const QmlStateGroup);
+ for (int i = 0; i < d->states.count(); ++i) {
+ QmlState *state = d->states.at(i);
+ if (state->name() == name)
+ return state;
+ }
+
+ return 0;
+}
+
+void QmlStateGroup::removeState(QmlState *state)
+{
+ Q_D(QmlStateGroup);
+ d->states.removeOne(state);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlstategroup_p.h b/src/declarative/util/qmlstategroup_p.h
new file mode 100644
index 0000000..112c9eb
--- /dev/null
+++ b/src/declarative/util/qmlstategroup_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSTATEGROUP_H
+#define QMLSTATEGROUP_H
+
+#include "qmlstate_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlStateGroupPrivate;
+class Q_DECLARATIVE_EXPORT QmlStateGroup : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QmlParserStatus)
+ Q_DECLARE_PRIVATE(QmlStateGroup)
+
+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QmlList<QmlState *>* states READ statesProperty DESIGNABLE false)
+ Q_PROPERTY(QmlList<QmlTransition *>* transitions READ transitionsProperty DESIGNABLE false)
+
+public:
+ QmlStateGroup(QObject * = 0);
+ virtual ~QmlStateGroup();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QmlList<QmlState *>* statesProperty();
+ QList<QmlState *> states() const;
+
+ QmlList<QmlTransition *>* transitionsProperty();
+
+ QmlState *findState(const QString &name) const;
+
+ virtual void classBegin();
+ virtual void componentComplete();
+Q_SIGNALS:
+ void stateChanged(const QString &);
+
+private:
+ friend class QmlState;
+ bool updateAutoState();
+ void removeState(QmlState *state);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlStateGroup)
+
+QT_END_HEADER
+
+#endif // QMLSTATEGROUP_H
diff --git a/src/declarative/util/qmlstateoperations.cpp b/src/declarative/util/qmlstateoperations.cpp
new file mode 100644
index 0000000..35c8f7d
--- /dev/null
+++ b/src/declarative/util/qmlstateoperations.cpp
@@ -0,0 +1,834 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlstateoperations_p.h"
+
+#include <qml.h>
+#include <qmlcontext.h>
+#include <qmlexpression.h>
+#include <qmlinfo.h>
+#include <qmlgraphicsanchors_p_p.h>
+#include <qmlgraphicsitem_p.h>
+#include <qmlguard_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtCore/qmath.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlParentChangePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlParentChange)
+public:
+ QmlParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
+ rewindParent(0), rewindStackBefore(0) {}
+
+ QmlGraphicsItem *target;
+ QmlGraphicsItem *parent;
+ QmlGuard<QmlGraphicsItem> origParent;
+ QmlGuard<QmlGraphicsItem> origStackBefore;
+ QmlGraphicsItem *rewindParent;
+ QmlGraphicsItem *rewindStackBefore;
+
+ void doChange(QmlGraphicsItem *targetParent, QmlGraphicsItem *stackBefore = 0);
+};
+
+void QmlParentChangePrivate::doChange(QmlGraphicsItem *targetParent, QmlGraphicsItem *stackBefore)
+{
+ if (targetParent && target && target->parentItem()) {
+ //### for backwards direction, can we just restore original x, y, scale, rotation
+ Q_Q(QmlParentChange);
+ bool ok;
+ const QTransform &transform = target->itemTransform(targetParent, &ok);
+ if (transform.type() >= QTransform::TxShear || !ok) {
+ qmlInfo(q) << QObject::tr("Unable to preserve appearance under complex transform");
+ ok = false;
+ }
+
+ qreal scale = 1;
+ qreal rotation = 0;
+ if (ok && transform.type() != QTransform::TxRotate) {
+ if (transform.m11() == transform.m22())
+ scale = transform.m11();
+ else {
+ qmlInfo(q) << QObject::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+ } else if (ok && transform.type() == QTransform::TxRotate) {
+ if (transform.m11() == transform.m22())
+ scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+ else {
+ qmlInfo(q) << QObject::tr("Unable to preserve appearance under non-uniform scale");
+ ok = false;
+ }
+
+ if (scale != 0)
+ rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+ else {
+ qmlInfo(q) << QObject::tr("Unable to preserve appearance under scale of 0");
+ ok = false;
+ }
+ }
+
+ qreal xt = transform.dx();
+ qreal yt = transform.dy();
+ if (ok && target->transformOrigin() != QmlGraphicsItem::TopLeft) {
+ qreal tempxt = target->transformOriginPoint().x();
+ qreal tempyt = target->transformOriginPoint().y();
+ QTransform t;
+ t.translate(-tempxt, -tempyt);
+ t.rotate(rotation);
+ t.scale(scale, scale);
+ t.translate(tempxt, tempyt);
+ QPointF offset = t.map(QPointF(0,0));
+ xt += offset.x();
+ yt += offset.y();
+ }
+
+ target->setParentItem(targetParent);
+ if (ok) {
+ //qDebug() << xt << yt << rotation << scale;
+ target->setX(xt);
+ target->setY(yt);
+ target->setRotation(rotation);
+ target->setScale(scale);
+ }
+ } else if (target) {
+ target->setParentItem(targetParent);
+ }
+
+ //restore the original stack position.
+ //### if stackBefore has also been reparented this won't work
+ if (stackBefore)
+ target->stackBefore(stackBefore);
+}
+
+/*!
+ \preliminary
+ \qmlclass ParentChange QmlParentChange
+ \brief The ParentChange element allows you to reparent an Item in a state change.
+
+ ParentChange reparents an Item while preserving its visual appearance (position, rotation,
+ and scale) on screen. You can then specify a transition to move/rotate/scale the Item to
+ its final intended appearance.
+
+ ParentChange can only preserve visual appearance if no complex transforms are involved.
+ More specifically, it will not work if the transform property has been set for any
+ Items involved in the reparenting (defined as any Items in the common ancestor tree
+ for the original and new parent).
+
+ You can specify at which point in a transition you want a ParentChange to occur by
+ using a ParentAction.
+*/
+
+QML_DEFINE_TYPE(Qt,4,6,ParentChange,QmlParentChange)
+QmlParentChange::QmlParentChange(QObject *parent)
+ : QmlStateOperation(*(new QmlParentChangePrivate), parent)
+{
+}
+
+QmlParentChange::~QmlParentChange()
+{
+}
+
+/*!
+ \qmlproperty Item ParentChange::target
+ This property holds the item to be reparented
+*/
+
+QmlGraphicsItem *QmlParentChange::object() const
+{
+ Q_D(const QmlParentChange);
+ return d->target;
+}
+
+void QmlParentChange::setObject(QmlGraphicsItem *target)
+{
+ Q_D(QmlParentChange);
+ d->target = target;
+}
+
+/*!
+ \qmlproperty Item ParentChange::parent
+ This property holds the parent for the item in this state
+*/
+
+QmlGraphicsItem *QmlParentChange::parent() const
+{
+ Q_D(const QmlParentChange);
+ return d->parent;
+}
+
+void QmlParentChange::setParent(QmlGraphicsItem *parent)
+{
+ Q_D(QmlParentChange);
+ d->parent = parent;
+}
+
+QmlStateOperation::ActionList QmlParentChange::actions()
+{
+ Q_D(QmlParentChange);
+ if (!d->target || !d->parent)
+ return ActionList();
+
+ QmlAction a;
+ a.event = this;
+
+ return ActionList() << a;
+}
+
+class AccessibleFxItem : public QmlGraphicsItem
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QmlGraphicsItem)
+public:
+ int siblingIndex() {
+ Q_D(QmlGraphicsItem);
+ return d->siblingIndex;
+ }
+};
+
+void QmlParentChange::saveOriginals()
+{
+ Q_D(QmlParentChange);
+ saveCurrentValues();
+ d->origParent = d->rewindParent;
+ d->origStackBefore = d->rewindStackBefore;
+}
+
+void QmlParentChange::execute()
+{
+ Q_D(QmlParentChange);
+ d->doChange(d->parent);
+}
+
+bool QmlParentChange::isReversable()
+{
+ return true;
+}
+
+void QmlParentChange::reverse()
+{
+ Q_D(QmlParentChange);
+ d->doChange(d->origParent, d->origStackBefore);
+}
+
+QString QmlParentChange::typeName() const
+{
+ return QLatin1String("ParentChange");
+}
+
+bool QmlParentChange::override(QmlActionEvent*other)
+{
+ Q_D(QmlParentChange);
+ if (other->typeName() != QLatin1String("ParentChange"))
+ return false;
+ if (QmlParentChange *otherPC = static_cast<QmlParentChange*>(other))
+ return (d->target == otherPC->object());
+ return false;
+}
+
+void QmlParentChange::saveCurrentValues()
+{
+ Q_D(QmlParentChange);
+ if (!d->target) {
+ d->rewindParent = 0;
+ d->rewindStackBefore = 0;
+ return;
+ }
+
+ d->rewindParent = d->target->parentItem();
+
+ if (!d->rewindParent) {
+ d->rewindStackBefore = 0;
+ return;
+ }
+
+ //try to determine the item's original stack position so we can restore it
+ int siblingIndex = ((AccessibleFxItem*)d->target)->siblingIndex() + 1;
+ QList<QGraphicsItem*> children = d->rewindParent->childItems();
+ for (int i = 0; i < children.count(); ++i) {
+ QmlGraphicsItem *child = qobject_cast<QmlGraphicsItem*>(children.at(i));
+ if (!child)
+ continue;
+ if (((AccessibleFxItem*)child)->siblingIndex() == siblingIndex) {
+ d->rewindStackBefore = child;
+ break;
+ }
+ }
+}
+
+void QmlParentChange::rewind()
+{
+ Q_D(QmlParentChange);
+ d->doChange(d->rewindParent, d->rewindStackBefore);
+}
+
+class QmlStateChangeScriptPrivate : public QObjectPrivate
+{
+public:
+ QmlStateChangeScriptPrivate() {}
+
+ QmlScriptString script;
+ QString name;
+};
+
+/*!
+ \qmlclass StateChangeScript QmlStateChangeScript
+ \brief The StateChangeScript element allows you to run a script in a state.
+
+ The script specified will be run immediately when the state is made current.
+ Alternatively you can use a ScriptAction to specify at which point in the transition
+ you want the StateChangeScript to be run.
+*/
+QML_DEFINE_TYPE(Qt,4,6,StateChangeScript,QmlStateChangeScript)
+QmlStateChangeScript::QmlStateChangeScript(QObject *parent)
+: QmlStateOperation(*(new QmlStateChangeScriptPrivate), parent)
+{
+}
+
+QmlStateChangeScript::~QmlStateChangeScript()
+{
+}
+
+/*!
+ \qmlproperty script StateChangeScript::script
+ This property holds the script to run when the state is current.
+*/
+QmlScriptString QmlStateChangeScript::script() const
+{
+ Q_D(const QmlStateChangeScript);
+ return d->script;
+}
+
+void QmlStateChangeScript::setScript(const QmlScriptString &s)
+{
+ Q_D(QmlStateChangeScript);
+ d->script = s;
+}
+
+/*!
+ \qmlproperty script StateChangeScript::script
+ This property holds the name of the script. This name can be used by a
+ ScriptAction to target a specific script.
+
+ \sa ScriptAction::stateChangeScriptName
+*/
+QString QmlStateChangeScript::name() const
+{
+ Q_D(const QmlStateChangeScript);
+ return d->name;
+}
+
+void QmlStateChangeScript::setName(const QString &n)
+{
+ Q_D(QmlStateChangeScript);
+ d->name = n;
+}
+
+void QmlStateChangeScript::execute()
+{
+ Q_D(QmlStateChangeScript);
+ const QString &script = d->script.script();
+ if (!script.isEmpty()) {
+ QmlExpression expr(d->script.context(), script, d->script.scopeObject());
+ expr.setTrackChange(false);
+ expr.value();
+ }
+}
+
+QmlStateChangeScript::ActionList QmlStateChangeScript::actions()
+{
+ ActionList rv;
+ QmlAction a;
+ a.event = this;
+ rv << a;
+ return rv;
+}
+
+QString QmlStateChangeScript::typeName() const
+{
+ return QLatin1String("StateChangeScript");
+}
+
+/*!
+ \qmlclass AnchorChanges QmlAnchorChanges
+ \brief The AnchorChanges element allows you to change the anchors of an item in a state.
+
+ In the following example we change the top and bottom anchors of an item:
+ \snippet examples/declarative/anchors/anchor-changes.qml 0
+
+ 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:
+ \qml
+ //animate our anchor changes
+ NumberAnimation { matchTargets: content; matchProperties: "x,y,width,height" }
+ \endqml
+
+ For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+QML_DEFINE_TYPE(Qt,4,6,AnchorChanges,QmlAnchorChanges)
+
+class QmlAnchorChangesPrivate : public QObjectPrivate
+{
+public:
+ QmlAnchorChangesPrivate() : target(0) {}
+
+ QString name;
+ QmlGraphicsItem *target;
+ QString resetString;
+ QStringList resetList;
+ QmlGraphicsAnchorLine left;
+ QmlGraphicsAnchorLine right;
+ QmlGraphicsAnchorLine horizontalCenter;
+ QmlGraphicsAnchorLine top;
+ QmlGraphicsAnchorLine bottom;
+ QmlGraphicsAnchorLine verticalCenter;
+ QmlGraphicsAnchorLine baseline;
+
+ QmlGraphicsAnchorLine origLeft;
+ QmlGraphicsAnchorLine origRight;
+ QmlGraphicsAnchorLine origHCenter;
+ QmlGraphicsAnchorLine origTop;
+ QmlGraphicsAnchorLine origBottom;
+ QmlGraphicsAnchorLine origVCenter;
+ QmlGraphicsAnchorLine origBaseline;
+
+ QmlGraphicsAnchorLine rewindLeft;
+ QmlGraphicsAnchorLine rewindRight;
+ QmlGraphicsAnchorLine rewindHCenter;
+ QmlGraphicsAnchorLine rewindTop;
+ QmlGraphicsAnchorLine rewindBottom;
+ QmlGraphicsAnchorLine rewindVCenter;
+ QmlGraphicsAnchorLine rewindBaseline;
+
+ qreal fromX;
+ qreal fromY;
+ qreal fromWidth;
+ qreal fromHeight;
+};
+
+/*!
+ \qmlproperty Item AnchorChanges::target
+ This property holds the Item whose anchors will change
+*/
+
+QmlAnchorChanges::QmlAnchorChanges(QObject *parent)
+ : QmlStateOperation(*(new QmlAnchorChangesPrivate), parent)
+{
+}
+
+QmlAnchorChanges::~QmlAnchorChanges()
+{
+}
+
+QmlAnchorChanges::ActionList QmlAnchorChanges::actions()
+{
+ QmlAction a;
+ a.event = this;
+ return ActionList() << a;
+}
+
+QmlGraphicsItem *QmlAnchorChanges::object() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->target;
+}
+
+void QmlAnchorChanges::setObject(QmlGraphicsItem *target)
+{
+ Q_D(QmlAnchorChanges);
+ d->target = target;
+}
+
+QString QmlAnchorChanges::reset() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->resetString;
+}
+
+void QmlAnchorChanges::setReset(const QString &reset)
+{
+ Q_D(QmlAnchorChanges);
+ d->resetString = reset;
+ d->resetList = d->resetString.split(QLatin1Char(','));
+ for (int i = 0; i < d->resetList.count(); ++i)
+ d->resetList[i] = d->resetList.at(i).trimmed();
+}
+
+/*!
+ \qmlproperty AnchorLine AnchorChanges::left
+ \qmlproperty AnchorLine AnchorChanges::right
+ \qmlproperty AnchorLine AnchorChanges::horizontalCenter
+ \qmlproperty AnchorLine AnchorChanges::top
+ \qmlproperty AnchorLine AnchorChanges::bottom
+ \qmlproperty AnchorLine AnchorChanges::verticalCenter
+ \qmlproperty AnchorLine AnchorChanges::baseline
+
+ These properties change the respective anchors of the item.
+*/
+
+QmlGraphicsAnchorLine QmlAnchorChanges::left() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->left;
+}
+
+void QmlAnchorChanges::setLeft(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->left = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::right() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->right;
+}
+
+void QmlAnchorChanges::setRight(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->right = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::horizontalCenter() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->horizontalCenter;
+}
+
+void QmlAnchorChanges::setHorizontalCenter(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->horizontalCenter = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::top() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->top;
+}
+
+void QmlAnchorChanges::setTop(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->top = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::bottom() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->bottom;
+}
+
+void QmlAnchorChanges::setBottom(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->bottom = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::verticalCenter() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->verticalCenter;
+}
+
+void QmlAnchorChanges::setVerticalCenter(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->verticalCenter = edge;
+}
+
+QmlGraphicsAnchorLine QmlAnchorChanges::baseline() const
+{
+ Q_D(const QmlAnchorChanges);
+ return d->baseline;
+}
+
+void QmlAnchorChanges::setBaseline(const QmlGraphicsAnchorLine &edge)
+{
+ Q_D(QmlAnchorChanges);
+ d->baseline = edge;
+}
+
+void QmlAnchorChanges::execute()
+{
+ Q_D(QmlAnchorChanges);
+ if (!d->target)
+ return;
+
+ //set any anchors that have been specified
+ if (d->left.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setLeft(d->left);
+ if (d->right.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setRight(d->right);
+ if (d->horizontalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setHorizontalCenter(d->horizontalCenter);
+ if (d->top.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setTop(d->top);
+ if (d->bottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBottom(d->bottom);
+ if (d->verticalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setVerticalCenter(d->verticalCenter);
+ if (d->baseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBaseline(d->baseline);
+}
+
+bool QmlAnchorChanges::isReversable()
+{
+ return true;
+}
+
+void QmlAnchorChanges::reverse()
+{
+ Q_D(QmlAnchorChanges);
+ if (!d->target)
+ return;
+
+ //restore previous anchors
+ if (d->origLeft.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setLeft(d->origLeft);
+ if (d->origRight.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setRight(d->origRight);
+ if (d->origHCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setHorizontalCenter(d->origHCenter);
+ if (d->origTop.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setTop(d->origTop);
+ if (d->origBottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBottom(d->origBottom);
+ if (d->origVCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setVerticalCenter(d->origVCenter);
+ if (d->origBaseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBaseline(d->origBaseline);
+}
+
+QString QmlAnchorChanges::typeName() const
+{
+ return QLatin1String("AnchorChanges");
+}
+
+QList<QmlAction> QmlAnchorChanges::extraActions()
+{
+ Q_D(QmlAnchorChanges);
+ QList<QmlAction> 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) {
+ QmlAction a;
+ a.fromValue = d->fromX;
+ a.property = QmlMetaProperty(d->target, QLatin1String("x"));
+ extra << a;
+
+ a.fromValue = d->fromY;
+ a.property = QmlMetaProperty(d->target, QLatin1String("y"));
+ extra << a;
+
+ a.fromValue = d->fromWidth;
+ a.property = QmlMetaProperty(d->target, QLatin1String("width"));
+ extra << a;
+
+ a.fromValue = d->fromHeight;
+ a.property = QmlMetaProperty(d->target, QLatin1String("height"));
+ extra << a;
+ }
+
+ return extra;
+}
+
+bool QmlAnchorChanges::changesBindings()
+{
+ return true;
+}
+
+void QmlAnchorChanges::saveOriginals()
+{
+ Q_D(QmlAnchorChanges);
+ d->origLeft = d->target->anchors()->left();
+ d->origRight = d->target->anchors()->right();
+ d->origHCenter = d->target->anchors()->horizontalCenter();
+ d->origTop = d->target->anchors()->top();
+ d->origBottom = d->target->anchors()->bottom();
+ d->origVCenter = d->target->anchors()->verticalCenter();
+ d->origBaseline = d->target->anchors()->baseline();
+
+ saveCurrentValues();
+}
+
+void QmlAnchorChanges::clearForwardBindings()
+{
+ Q_D(QmlAnchorChanges);
+ d->fromX = d->target->x();
+ d->fromY = d->target->y();
+ d->fromWidth = d->target->width();
+ d->fromHeight = d->target->height();
+
+ //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();
+
+ //reset any anchors that we'll be setting in the state
+ if (d->left.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetLeft();
+ if (d->right.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetRight();
+ if (d->horizontalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->top.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetTop();
+ if (d->bottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBottom();
+ if (d->verticalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetVerticalCenter();
+ if (d->baseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBaseline();
+}
+
+void QmlAnchorChanges::clearReverseBindings()
+{
+ Q_D(QmlAnchorChanges);
+ 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 != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetLeft();
+ if (d->right.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetRight();
+ if (d->horizontalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->top.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetTop();
+ if (d->bottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBottom();
+ if (d->verticalCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetVerticalCenter();
+ if (d->baseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBaseline();
+
+ //reset any anchors that were set in the original state
+ if (d->origLeft.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetLeft();
+ if (d->origRight.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetRight();
+ if (d->origHCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetHorizontalCenter();
+ if (d->origTop.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetTop();
+ if (d->origBottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBottom();
+ if (d->origVCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetVerticalCenter();
+ if (d->origBaseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->resetBaseline();
+}
+
+bool QmlAnchorChanges::override(QmlActionEvent*other)
+{
+ if (other->typeName() != QLatin1String("AnchorChanges"))
+ return false;
+ if (static_cast<QmlActionEvent*>(this) == other)
+ return true;
+ if (static_cast<QmlAnchorChanges*>(other)->object() == object())
+ return true;
+ return false;
+}
+
+void QmlAnchorChanges::rewind()
+{
+ Q_D(QmlAnchorChanges);
+ if (!d->target)
+ return;
+
+ //restore previous anchors
+ if (d->rewindLeft.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setLeft(d->rewindLeft);
+ if (d->rewindRight.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setRight(d->rewindRight);
+ if (d->rewindHCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setHorizontalCenter(d->rewindHCenter);
+ if (d->rewindTop.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setTop(d->rewindTop);
+ if (d->rewindBottom.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBottom(d->rewindBottom);
+ if (d->rewindVCenter.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setVerticalCenter(d->rewindVCenter);
+ if (d->rewindBaseline.anchorLine != QmlGraphicsAnchorLine::Invalid)
+ d->target->anchors()->setBaseline(d->rewindBaseline);
+}
+
+void QmlAnchorChanges::saveCurrentValues()
+{
+ Q_D(QmlAnchorChanges);
+ d->rewindLeft = d->target->anchors()->left();
+ d->rewindRight = d->target->anchors()->right();
+ d->rewindHCenter = d->target->anchors()->horizontalCenter();
+ d->rewindTop = d->target->anchors()->top();
+ d->rewindBottom = d->target->anchors()->bottom();
+ d->rewindVCenter = d->target->anchors()->verticalCenter();
+ d->rewindBaseline = d->target->anchors()->baseline();
+}
+
+#include <qmlstateoperations.moc>
+#include <moc_qmlstateoperations_p.cpp>
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/util/qmlstateoperations_p.h b/src/declarative/util/qmlstateoperations_p.h
new file mode 100644
index 0000000..1a9f76f
--- /dev/null
+++ b/src/declarative/util/qmlstateoperations_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSTATEOPERATIONS_H
+#define QMLSTATEOPERATIONS_H
+
+#include "qmlstate_p.h"
+
+#include <qmlgraphicsitem.h>
+#include "private/qmlgraphicsanchors_p.h"
+#include <qmlscriptstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlParentChangePrivate;
+class Q_DECLARATIVE_EXPORT QmlParentChange : public QmlStateOperation, public QmlActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlParentChange)
+
+ Q_PROPERTY(QmlGraphicsItem *target READ object WRITE setObject)
+ Q_PROPERTY(QmlGraphicsItem *parent READ parent WRITE setParent)
+public:
+ QmlParentChange(QObject *parent=0);
+ ~QmlParentChange();
+
+ QmlGraphicsItem *object() const;
+ void setObject(QmlGraphicsItem *);
+
+ QmlGraphicsItem *parent() const;
+ void setParent(QmlGraphicsItem *);
+
+ virtual ActionList actions();
+
+ virtual void saveOriginals();
+ virtual void execute();
+ virtual bool isReversable();
+ virtual void reverse();
+ virtual QString typeName() const;
+ virtual bool override(QmlActionEvent*other);
+ virtual void rewind();
+ virtual void saveCurrentValues();
+};
+
+class QmlStateChangeScriptPrivate;
+class Q_DECLARATIVE_EXPORT QmlStateChangeScript : public QmlStateOperation, public QmlActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlStateChangeScript)
+
+ Q_PROPERTY(QmlScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString name READ name WRITE setName)
+
+public:
+ QmlStateChangeScript(QObject *parent=0);
+ ~QmlStateChangeScript();
+
+ virtual ActionList actions();
+
+ virtual QString typeName() const;
+
+ QmlScriptString script() const;
+ void setScript(const QmlScriptString &);
+
+ QString name() const;
+ void setName(const QString &);
+
+ virtual void execute();
+};
+
+class QmlAnchorChangesPrivate;
+class Q_DECLARATIVE_EXPORT QmlAnchorChanges : public QmlStateOperation, public QmlActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlAnchorChanges)
+
+ Q_PROPERTY(QmlGraphicsItem *target READ object WRITE setObject)
+ Q_PROPERTY(QString reset READ reset WRITE setReset)
+ Q_PROPERTY(QmlGraphicsAnchorLine left READ left WRITE setLeft)
+ Q_PROPERTY(QmlGraphicsAnchorLine right READ right WRITE setRight)
+ Q_PROPERTY(QmlGraphicsAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter)
+ Q_PROPERTY(QmlGraphicsAnchorLine top READ top WRITE setTop)
+ Q_PROPERTY(QmlGraphicsAnchorLine bottom READ bottom WRITE setBottom)
+ Q_PROPERTY(QmlGraphicsAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter)
+ Q_PROPERTY(QmlGraphicsAnchorLine baseline READ baseline WRITE setBaseline)
+
+public:
+ QmlAnchorChanges(QObject *parent=0);
+ ~QmlAnchorChanges();
+
+ virtual ActionList actions();
+
+ QmlGraphicsItem *object() const;
+ void setObject(QmlGraphicsItem *);
+
+ QString reset() const;
+ void setReset(const QString &);
+
+ QmlGraphicsAnchorLine left() const;
+ void setLeft(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine right() const;
+ void setRight(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine top() const;
+ void setTop(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine bottom() const;
+ void setBottom(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QmlGraphicsAnchorLine &edge);
+
+ QmlGraphicsAnchorLine baseline() const;
+ void setBaseline(const QmlGraphicsAnchorLine &edge);
+
+ virtual void execute();
+ virtual bool isReversable();
+ virtual void reverse();
+ virtual QString typeName() const;
+ virtual bool override(QmlActionEvent*other);
+ virtual QList<QmlAction> extraActions();
+ virtual bool changesBindings();
+ virtual void saveOriginals();
+ virtual void clearForwardBindings();
+ virtual void clearReverseBindings();
+ virtual void rewind();
+ virtual void saveCurrentValues();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlParentChange)
+QML_DECLARE_TYPE(QmlStateChangeScript)
+QML_DECLARE_TYPE(QmlAnchorChanges)
+
+QT_END_HEADER
+
+#endif // QMLSTATEOPERATIONS_H
diff --git a/src/declarative/util/qmlstyledtext.cpp b/src/declarative/util/qmlstyledtext.cpp
new file mode 100644
index 0000000..36b5e49
--- /dev/null
+++ b/src/declarative/util/qmlstyledtext.cpp
@@ -0,0 +1,343 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 <QStack>
+#include <QVector>
+#include <QPainter>
+#include <QTextLayout>
+#include <QDebug>
+#include <qmath.h>
+#include "qmlstyledtext_p.h"
+
+/*
+ QmlStyledText supports few tags:
+
+ <b></b> - bold
+ <i></i> - italic
+ <br> - new line
+ <font color="color_name" size="1-7"></font>
+
+ The opening and closing tags must be correctly nested.
+*/
+
+class QmlStyledTextPrivate
+{
+public:
+ QmlStyledTextPrivate(const QString &t, QTextLayout &l) : text(t), layout(l), baseFont(layout.font()) {}
+
+ void parse();
+ bool parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format);
+ bool parseCloseTag(const QChar *&ch, const QString &textIn);
+ void parseEntity(const QChar *&ch, const QString &textIn, QString &textOut);
+ bool parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format);
+ QPair<QStringRef,QStringRef> parseAttribute(const QChar *&ch, const QString &textIn);
+ QStringRef parseValue(const QChar *&ch, const QString &textIn);
+
+ inline void skipSpace(const QChar *&ch) {
+ while (ch->isSpace() && !ch->isNull())
+ ++ch;
+ }
+
+ QString text;
+ QTextLayout &layout;
+ QFont baseFont;
+
+ static const QChar lessThan;
+ static const QChar greaterThan;
+ static const QChar equals;
+ static const QChar singleQuote;
+ static const QChar doubleQuote;
+ static const QChar slash;
+ static const QChar ampersand;
+};
+
+const QChar QmlStyledTextPrivate::lessThan(QLatin1Char('<'));
+const QChar QmlStyledTextPrivate::greaterThan(QLatin1Char('>'));
+const QChar QmlStyledTextPrivate::equals(QLatin1Char('='));
+const QChar QmlStyledTextPrivate::singleQuote(QLatin1Char('\''));
+const QChar QmlStyledTextPrivate::doubleQuote(QLatin1Char('\"'));
+const QChar QmlStyledTextPrivate::slash(QLatin1Char('/'));
+const QChar QmlStyledTextPrivate::ampersand(QLatin1Char('&'));
+
+QmlStyledText::QmlStyledText(const QString &string, QTextLayout &layout)
+: d(new QmlStyledTextPrivate(string, layout))
+{
+}
+
+QmlStyledText::~QmlStyledText()
+{
+ delete d;
+}
+
+void QmlStyledText::parse(const QString &string, QTextLayout &layout)
+{
+ QmlStyledText styledText(string, layout);
+ styledText.d->parse();
+}
+
+void QmlStyledTextPrivate::parse()
+{
+ QList<QTextLayout::FormatRange> ranges;
+ QStack<QTextCharFormat> formatStack;
+
+ QString drawText;
+ drawText.reserve(text.count());
+
+ int textStart = 0;
+ int textLength = 0;
+ int rangeStart = 0;
+ const QChar *ch = text.constData();
+ while (!ch->isNull()) {
+ if (*ch == lessThan) {
+ if (textLength)
+ drawText.append(QStringRef(&text, textStart, textLength));
+ if (rangeStart != drawText.length() && formatStack.count()) {
+ QTextLayout::FormatRange formatRange;
+ formatRange.format = formatStack.top();
+ formatRange.start = rangeStart;
+ formatRange.length = drawText.length() - rangeStart;
+ ranges.append(formatRange);
+ }
+ rangeStart = drawText.length();
+ ++ch;
+ if (*ch == slash) {
+ ++ch;
+ if (parseCloseTag(ch, text))
+ formatStack.pop();
+ } else {
+ QTextCharFormat format;
+ if (formatStack.count())
+ format = formatStack.top();
+ else
+ format.setFont(baseFont);
+ if (parseTag(ch, text, drawText, format))
+ formatStack.push(format);
+ }
+ textStart = ch - text.constData() + 1;
+ textLength = 0;
+ } else if (*ch == ampersand) {
+ ++ch;
+ drawText.append(QStringRef(&text, textStart, textLength));
+ parseEntity(ch, text, drawText);
+ textStart = ch - text.constData() + 1;
+ textLength = 0;
+ } else {
+ ++textLength;
+ }
+ ++ch;
+ }
+ if (textLength)
+ drawText.append(QStringRef(&text, textStart, textLength));
+ if (rangeStart != drawText.length() && formatStack.count()) {
+ QTextLayout::FormatRange formatRange;
+ formatRange.format = formatStack.top();
+ formatRange.start = rangeStart;
+ formatRange.length = drawText.length() - rangeStart;
+ ranges.append(formatRange);
+ }
+
+ layout.setText(drawText);
+ layout.setAdditionalFormats(ranges);
+}
+
+bool QmlStyledTextPrivate::parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format)
+{
+ skipSpace(ch);
+
+ int tagStart = ch - textIn.constData();
+ int tagLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ if (char0 == QLatin1Char('b')) {
+ if (tagLength == 1) {
+ format.setFontWeight(QFont::Bold);
+ return true;
+ } else if (tagLength == 2 && tag.at(1) == QLatin1Char('r')) {
+ textOut.append(QChar(QChar::LineSeparator));
+ return true;
+ }
+ } else if (char0 == QLatin1Char('i')) {
+ if (tagLength == 1) {
+ format.setFontItalic(true);
+ return true;
+ }
+ }
+ return false;
+ } else if (ch->isSpace()) {
+ // may have params.
+ QStringRef tag(&textIn, tagStart, tagLength);
+ if (tag == QLatin1String("font"))
+ return parseFontAttributes(ch, textIn, format);
+ if (*ch == greaterThan || ch->isNull())
+ continue;
+ } else if (*ch != slash){
+ tagLength++;
+ }
+ ++ch;
+ }
+
+ return false;
+}
+
+bool QmlStyledTextPrivate::parseCloseTag(const QChar *&ch, const QString &textIn)
+{
+ skipSpace(ch);
+
+ int tagStart = ch - textIn.constData();
+ int tagLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ if (char0 == QLatin1Char('b')) {
+ if (tagLength == 1)
+ return true;
+ else if (tag.at(1) == QLatin1Char('r') && tagLength == 2)
+ return true;
+ } else if (char0 == QLatin1Char('i')) {
+ if (tagLength == 1)
+ return true;
+ } else if (tag == QLatin1String("font")) {
+ return true;
+ }
+ return false;
+ } else if (!ch->isSpace()){
+ tagLength++;
+ }
+ ++ch;
+ }
+
+ return false;
+}
+
+void QmlStyledTextPrivate::parseEntity(const QChar *&ch, const QString &textIn, QString &textOut)
+{
+ int entityStart = ch - textIn.constData();
+ int entityLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == QLatin1Char(';')) {
+ QStringRef entity(&textIn, entityStart, entityLength);
+ if (entity == QLatin1String("gt"))
+ textOut += QChar(62);
+ else if (entity == QLatin1String("lt"))
+ textOut += QChar(60);
+ else if (entity == QLatin1String("amp"))
+ textOut += QChar(38);
+ return;
+ }
+ ++entityLength;
+ ++ch;
+ }
+}
+
+bool QmlStyledTextPrivate::parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
+{
+ bool valid = false;
+ QPair<QStringRef,QStringRef> attr;
+ do {
+ attr = parseAttribute(ch, textIn);
+ if (attr.first == QLatin1String("color")) {
+ valid = true;
+ format.setForeground(QColor(attr.second.toString()));
+ } else if (attr.first == QLatin1String("size")) {
+ valid = true;
+ int size = attr.second.toString().toInt();
+ if (attr.second.at(0) == QLatin1Char('-') || attr.second.at(0) == QLatin1Char('+'))
+ size += 3;
+ if (size >= 1 && size <= 7) {
+ static const qreal scaling[] = { 0.7, 0.8, 1.0, 1.2, 1.5, 2.0, 2.4 };
+ format.setFontPointSize(baseFont.pointSize() * scaling[size-1]);
+ }
+ }
+ } while (!ch->isNull() && !attr.first.isEmpty());
+
+ return valid;
+}
+
+QPair<QStringRef,QStringRef> QmlStyledTextPrivate::parseAttribute(const QChar *&ch, const QString &textIn)
+{
+ skipSpace(ch);
+
+ int attrStart = ch - textIn.constData();
+ int attrLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ break;
+ } else if (*ch == equals) {
+ ++ch;
+ if (*ch != singleQuote && *ch != doubleQuote) {
+ while (*ch != greaterThan && !ch->isNull())
+ ++ch;
+ break;
+ }
+ ++ch;
+ if (!attrLength)
+ break;
+ QStringRef attr(&textIn, attrStart, attrLength);
+ QStringRef val = parseValue(ch, textIn);
+ if (!val.isEmpty())
+ return QPair<QStringRef,QStringRef>(attr,val);
+ break;
+ } else {
+ ++attrLength;
+ }
+ ++ch;
+ }
+
+ return QPair<QStringRef,QStringRef>();
+}
+
+QStringRef QmlStyledTextPrivate::parseValue(const QChar *&ch, const QString &textIn)
+{
+ int valStart = ch - textIn.constData();
+ int valLength = 0;
+ while (*ch != singleQuote && *ch != doubleQuote && !ch->isNull()) {
+ ++valLength;
+ ++ch;
+ }
+ if (ch->isNull())
+ return QStringRef();
+ ++ch; // skip quote
+
+ return QStringRef(&textIn, valStart, valLength);
+}
diff --git a/src/declarative/util/qmlstyledtext_p.h b/src/declarative/util/qmlstyledtext_p.h
new file mode 100644
index 0000000..0cfb43e
--- /dev/null
+++ b/src/declarative/util/qmlstyledtext_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSTYLEDTEXT_H
+#define QMLSTYLEDTEXT_H
+
+#include <QSizeF>
+
+class QPainter;
+class QPointF;
+class QString;
+class QmlStyledTextPrivate;
+class Q_DECLARATIVE_EXPORT QmlStyledText
+{
+public:
+ static void parse(const QString &string, QTextLayout &layout);
+
+private:
+ QmlStyledText(const QString &string, QTextLayout &layout);
+ ~QmlStyledText();
+
+ QmlStyledTextPrivate *d;
+};
+
+#endif
diff --git a/src/declarative/util/qmlsystempalette.cpp b/src/declarative/util/qmlsystempalette.cpp
new file mode 100644
index 0000000..39d8f3e
--- /dev/null
+++ b/src/declarative/util/qmlsystempalette.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlsystempalette_p.h"
+
+#include <QApplication>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlSystemPalettePrivate : public QObjectPrivate
+{
+public:
+ QPalette palette;
+ QPalette::ColorGroup group;
+};
+
+QML_DEFINE_TYPE(Qt,4,6,SystemPalette,QmlSystemPalette)
+
+/*!
+ \qmlclass SystemPalette QmlSystemPalette
+ \ingroup group_utility
+ \brief The SystemPalette item gives access to the Qt palettes.
+ \sa QPalette
+
+ Example:
+ \qml
+ SystemPalette { id: myPalette; colorGroup: Qt.Active }
+
+ Rectangle {
+ width: 640; height: 480
+ color: myPalette.window
+ Text {
+ anchors.fill: parent
+ text: "Hello!"; color: myPalette.windowText
+ }
+ }
+ \endqml
+*/
+QmlSystemPalette::QmlSystemPalette(QObject *parent)
+ : QObject(*(new QmlSystemPalettePrivate), parent)
+{
+ Q_D(QmlSystemPalette);
+ d->palette = QApplication::palette();
+ d->group = QPalette::Active;
+ qApp->installEventFilter(this);
+}
+
+QmlSystemPalette::~QmlSystemPalette()
+{
+}
+
+/*!
+ \qmlproperty color SystemPalette::window
+ The window (general background) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::window() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Window);
+}
+
+/*!
+ \qmlproperty color SystemPalette::windowText
+ The window text (general foreground) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::windowText() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::WindowText);
+}
+
+/*!
+ \qmlproperty color SystemPalette::base
+ The base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::base() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Base);
+}
+
+/*!
+ \qmlproperty color SystemPalette::text
+ The text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::text() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Text);
+}
+
+/*!
+ \qmlproperty color SystemPalette::alternateBase
+ The alternate base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::alternateBase() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::AlternateBase);
+}
+
+/*!
+ \qmlproperty color SystemPalette::button
+ The button color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::button() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Button);
+}
+
+/*!
+ \qmlproperty color SystemPalette::buttonText
+ The button text foreground color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::buttonText() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::ButtonText);
+}
+
+/*!
+ \qmlproperty color SystemPalette::light
+ The light color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::light() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Light);
+}
+
+/*!
+ \qmlproperty color SystemPalette::midlight
+ The midlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::midlight() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Midlight);
+}
+
+/*!
+ \qmlproperty color SystemPalette::dark
+ The dark color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::dark() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Dark);
+}
+
+/*!
+ \qmlproperty color SystemPalette::mid
+ The mid color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::mid() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Mid);
+}
+
+/*!
+ \qmlproperty color SystemPalette::shadow
+ The shadow color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::shadow() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Shadow);
+}
+
+/*!
+ \qmlproperty color SystemPalette::highlight
+ The highlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::highlight() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::Highlight);
+}
+
+/*!
+ \qmlproperty color SystemPalette::highlightedText
+ The highlighted text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QmlSystemPalette::highlightedText() const
+{
+ Q_D(const QmlSystemPalette);
+ return d->palette.color(d->group, QPalette::HighlightedText);
+}
+
+/*!
+ \qmlproperty QmlSystemPalette::ColorGroup SystemPalette::colorGroup
+
+ The color group of the palette. It can be Active, Inactive or Disabled.
+ Active is the default.
+
+ \sa QPalette::ColorGroup
+*/
+QmlSystemPalette::ColorGroup QmlSystemPalette::colorGroup() const
+{
+ Q_D(const QmlSystemPalette);
+ return (QmlSystemPalette::ColorGroup)d->group;
+}
+
+void QmlSystemPalette::setColorGroup(QmlSystemPalette::ColorGroup colorGroup)
+{
+ Q_D(QmlSystemPalette);
+ d->group = (QPalette::ColorGroup)colorGroup;
+ emit paletteChanged();
+}
+
+bool QmlSystemPalette::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched == qApp) {
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
+ return false;
+ }
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+bool QmlSystemPalette::event(QEvent *event)
+{
+ Q_D(QmlSystemPalette);
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ d->palette = QApplication::palette();
+ emit paletteChanged();
+ return true;
+ }
+ return QObject::event(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlsystempalette_p.h b/src/declarative/util/qmlsystempalette_p.h
new file mode 100644
index 0000000..7c39d4a
--- /dev/null
+++ b/src/declarative/util/qmlsystempalette_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLSYSTEMPALETTE_H
+#define QMLSYSTEMPALETTE_H
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+#include <QPalette>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlSystemPalettePrivate;
+class Q_DECLARATIVE_EXPORT QmlSystemPalette : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ColorGroup)
+ Q_DECLARE_PRIVATE(QmlSystemPalette)
+
+ Q_PROPERTY(QmlSystemPalette::ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY paletteChanged)
+ Q_PROPERTY(QColor window READ window NOTIFY paletteChanged)
+ Q_PROPERTY(QColor windowText READ windowText NOTIFY paletteChanged)
+ Q_PROPERTY(QColor base READ base NOTIFY paletteChanged)
+ Q_PROPERTY(QColor text READ text NOTIFY paletteChanged)
+ Q_PROPERTY(QColor alternateBase READ alternateBase NOTIFY paletteChanged)
+ Q_PROPERTY(QColor button READ button NOTIFY paletteChanged)
+ Q_PROPERTY(QColor buttonText READ buttonText NOTIFY paletteChanged)
+ Q_PROPERTY(QColor light READ light NOTIFY paletteChanged)
+ Q_PROPERTY(QColor midlight READ midlight NOTIFY paletteChanged)
+ Q_PROPERTY(QColor dark READ dark NOTIFY paletteChanged)
+ Q_PROPERTY(QColor mid READ mid NOTIFY paletteChanged)
+ Q_PROPERTY(QColor shadow READ shadow NOTIFY paletteChanged)
+ Q_PROPERTY(QColor highlight READ highlight NOTIFY paletteChanged)
+ Q_PROPERTY(QColor highlightedText READ highlightedText NOTIFY paletteChanged)
+
+public:
+ QmlSystemPalette(QObject *parent=0);
+ ~QmlSystemPalette();
+
+ enum ColorGroup { Active = QPalette::Active, Inactive = QPalette::Inactive, Disabled = QPalette::Disabled };
+
+ QColor window() const;
+ QColor windowText() const;
+
+ QColor base() const;
+ QColor text() const;
+ QColor alternateBase() const;
+
+ QColor button() const;
+ QColor buttonText() const;
+
+ QColor light() const;
+ QColor midlight() const;
+ QColor dark() const;
+ QColor mid() const;
+ QColor shadow() const;
+
+ QColor highlight() const;
+ QColor highlightedText() const;
+
+ QmlSystemPalette::ColorGroup colorGroup() const;
+ void setColorGroup(QmlSystemPalette::ColorGroup);
+
+Q_SIGNALS:
+ void paletteChanged();
+
+private:
+ bool eventFilter(QObject *watched, QEvent *event);
+ bool event(QEvent *event);
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlSystemPalette)
+
+QT_END_HEADER
+
+#endif // QMLSYSTEMPALETTE_H
diff --git a/src/declarative/util/qmltimeline.cpp b/src/declarative/util/qmltimeline.cpp
new file mode 100644
index 0000000..130e02d
--- /dev/null
+++ b/src/declarative/util/qmltimeline.cpp
@@ -0,0 +1,941 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmltimeline_p_p.h"
+
+#include <QDebug>
+#include <QMutex>
+#include <QThread>
+#include <QWaitCondition>
+#include <QEvent>
+#include <QCoreApplication>
+#include <QEasingCurve>
+#include <QTime>
+
+QT_BEGIN_NAMESPACE
+
+struct Update {
+ Update(QmlTimeLineValue *_g, qreal _v)
+ : g(_g), v(_v) {}
+ Update(const QmlTimeLineEvent &_e)
+ : g(0), v(0), e(_e) {}
+
+ QmlTimeLineValue *g;
+ qreal v;
+ QmlTimeLineEvent e;
+};
+
+struct QmlTimeLinePrivate
+{
+ QmlTimeLinePrivate(QmlTimeLine *);
+
+ struct Op {
+ enum Type {
+ Pause,
+ Set,
+ Move,
+ MoveBy,
+ Accel,
+ AccelDistance,
+ Execute
+ };
+ Op() {}
+ Op(Type t, int l, qreal v, qreal v2, int o,
+ const QmlTimeLineEvent &ev = QmlTimeLineEvent(), const QEasingCurve &es = QEasingCurve())
+ : type(t), length(l), value(v), value2(v2), order(o), event(ev),
+ easing(es) {}
+ Op(const Op &o)
+ : type(o.type), length(o.length), value(o.value), value2(o.value2),
+ order(o.order), event(o.event), easing(o.easing) {}
+ Op &operator=(const Op &o) {
+ type = o.type; length = o.length; value = o.value;
+ value2 = o.value2; order = o.order; event = o.event;
+ easing = o.easing;
+ return *this;
+ }
+
+ Type type;
+ int length;
+ qreal value;
+ qreal value2;
+
+ int order;
+ QmlTimeLineEvent event;
+ QEasingCurve easing;
+ };
+ struct TimeLine
+ {
+ TimeLine() : length(0), consumedOpLength(0), base(0.) {}
+ QList<Op> ops;
+ int length;
+ int consumedOpLength;
+ qreal base;
+ };
+
+ int length;
+ int syncPoint;
+ typedef QHash<QmlTimeLineObject *, TimeLine> Ops;
+ Ops ops;
+ QmlTimeLine *q;
+
+ void add(QmlTimeLineObject &, const Op &);
+ qreal value(const Op &op, int time, qreal base, bool *) const;
+
+ int advance(int);
+
+ bool clockRunning;
+ int prevTime;
+
+ int order;
+
+ QmlTimeLine::SyncMode syncMode;
+ int syncAdj;
+ QList<QPair<int, Update> > *updateQueue;
+};
+
+QmlTimeLinePrivate::QmlTimeLinePrivate(QmlTimeLine *parent)
+: length(0), syncPoint(0), q(parent), clockRunning(false), prevTime(0), order(0), syncMode(QmlTimeLine::LocalSync), syncAdj(0), updateQueue(0)
+{
+}
+
+void QmlTimeLinePrivate::add(QmlTimeLineObject &g, const Op &o)
+{
+ if (g._t && g._t != q) {
+ qWarning() << "QmlTimeLine: Cannot modify a QmlTimeLineValue owned by"
+ << "another timeline.";
+ return;
+ }
+ g._t = q;
+
+ Ops::Iterator iter = ops.find(&g);
+ if (iter == ops.end()) {
+ iter = ops.insert(&g, TimeLine());
+ if (syncPoint > 0)
+ q->pause(g, syncPoint);
+ }
+ if (!iter->ops.isEmpty() &&
+ o.type == Op::Pause &&
+ iter->ops.last().type == Op::Pause) {
+ iter->ops.last().length += o.length;
+ iter->length += o.length;
+ } else {
+ iter->ops.append(o);
+ iter->length += o.length;
+ }
+
+ if (iter->length > length)
+ length = iter->length;
+
+ if (!clockRunning) {
+ q->stop();
+ prevTime = 0;
+ clockRunning = true;
+
+ if (syncMode == QmlTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ q->start();
+/* q->tick(0);
+ if (syncMode == QmlTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ */
+ }
+}
+
+qreal QmlTimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const
+{
+ Q_ASSERT(time >= 0);
+ Q_ASSERT(time <= op.length);
+ *changed = true;
+
+ switch(op.type) {
+ case Op::Pause:
+ *changed = false;
+ return base;
+ case Op::Set:
+ return op.value;
+ case Op::Move:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return op.value;
+ } else {
+ qreal delta = op.value - base;
+ qreal pTime = (qreal)(time) / (qreal)op.length;
+ if (op.easing.type() == QEasingCurve::Linear)
+ return base + delta * pTime;
+ else
+ return base + delta * op.easing.valueForProgress(pTime);
+ }
+ case Op::MoveBy:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return base + op.value;
+ } else {
+ qreal delta = op.value;
+ qreal pTime = (qreal)(time) / (qreal)op.length;
+ if (op.easing.type() == QEasingCurve::Linear)
+ return base + delta * pTime;
+ else
+ return base + delta * op.easing.valueForProgress(pTime);
+ }
+ case Op::Accel:
+ if (time == 0) {
+ return base;
+ } else {
+ qreal t = (qreal)(time) / 1000.0f;
+ qreal delta = op.value * t + 0.5f * op.value2 * t * t;
+ return base + delta;
+ }
+ case Op::AccelDistance:
+ if (time == 0) {
+ return base;
+ } else if (time == (op.length)) {
+ return base + op.value2;
+ } else {
+ qreal t = (qreal)(time) / 1000.0f;
+ qreal accel = -1.0f * 1000.0f * op.value / (qreal)op.length;
+ qreal delta = op.value * t + 0.5f * accel * t * t;
+ return base + delta;
+
+ }
+ case Op::Execute:
+ op.event.execute();
+ *changed = false;
+ return -1;
+ }
+
+ return base;
+}
+
+/*!
+ \internal
+ \class QmlTimeLine
+ \ingroup group_animation
+ \brief The QmlTimeLine class provides a timeline for controlling animations.
+
+ QmlTimeLine is similar to QTimeLine except:
+ \list
+ \i It updates QmlTimeLineValue instances directly, rather than maintaining a single
+ current value.
+
+ For example, the following animates a simple value over 200 milliseconds:
+ \code
+ QmlTimeLineValue v(<starting value>);
+ QmlTimeLine tl;
+ tl.move(v, 100., 200);
+ tl.start()
+ \endcode
+
+ If your program needs to know when values are changed, it can either
+ connect to the QmlTimeLine's updated() signal, or inherit from QmlTimeLineValue
+ and reimplement the QmlTimeLineValue::setValue() method.
+
+ \i Supports multiple QmlTimeLineValue, arbitrary start and end values and allows
+ animations to be strung together for more complex effects.
+
+ For example, the following animation moves the x and y coordinates of
+ an object from wherever they are to the position (100, 100) in 50
+ milliseconds and then further animates them to (100, 200) in 50
+ milliseconds:
+
+ \code
+ QmlTimeLineValue x(<starting value>);
+ QmlTimeLineValue y(<starting value>);
+
+ QmlTimeLine tl;
+ tl.start();
+
+ tl.move(x, 100., 50);
+ tl.move(y, 100., 50);
+ tl.move(y, 200., 50);
+ \endcode
+
+ \i All QmlTimeLine instances share a single, synchronized clock.
+
+ Actions scheduled within the same event loop tick are scheduled
+ synchronously against each other, regardless of the wall time between the
+ scheduling. Synchronized scheduling applies both to within the same
+ QmlTimeLine and across separate QmlTimeLine's within the same process.
+
+ \endlist
+
+ Currently easing functions are not supported.
+*/
+
+
+/*!
+ Construct a new QmlTimeLine with the specified \a parent.
+*/
+QmlTimeLine::QmlTimeLine(QObject *parent)
+: QAbstractAnimation(parent)
+{
+ d = new QmlTimeLinePrivate(this);
+}
+
+/*!
+ Destroys the time line. Any inprogress animations are canceled, but not
+ completed.
+*/
+QmlTimeLine::~QmlTimeLine()
+{
+ for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter)
+ iter.key()->_t = 0;
+
+ delete d; d = 0;
+}
+
+/*!
+ \enum QmlTimeLine::SyncMode
+ */
+
+/*!
+ Return the timeline's synchronization mode.
+ */
+QmlTimeLine::SyncMode QmlTimeLine::syncMode() const
+{
+ return d->syncMode;
+}
+
+/*!
+ Set the timeline's synchronization mode to \a syncMode.
+ */
+void QmlTimeLine::setSyncMode(SyncMode syncMode)
+{
+ d->syncMode = syncMode;
+}
+
+/*!
+ Pause \a obj for \a time milliseconds.
+*/
+void QmlTimeLine::pause(QmlTimeLineObject &obj, int time)
+{
+ if (time <= 0) return;
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
+ d->add(obj, op);
+}
+
+/*!
+ Execute the \a event.
+ */
+void QmlTimeLine::execute(const QmlTimeLineEvent &event)
+{
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, event);
+ d->add(*event.eventObject(), op);
+}
+
+/*!
+ Set the \a value of \a timeLineValue.
+*/
+void QmlTimeLine::set(QmlTimeLineValue &timeLineValue, qreal value)
+{
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Set, 0, value, 0., d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Decelerate \a timeLineValue from the starting \a velocity to zero at the
+ given \a acceleration rate. Although the \a acceleration is technically
+ a deceleration, it should always be positive. The QmlTimeLine will ensure
+ that the deceleration is in the opposite direction to the initial velocity.
+*/
+int QmlTimeLine::accel(QmlTimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
+{
+ if ((velocity > 0.0f) == (acceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+
+ int time = static_cast<int>(-1000 * velocity / acceleration);
+
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ \overload
+
+ Decelerate \a timeLineValue from the starting \a velocity to zero at the
+ given \a acceleration rate over a maximum distance of maxDistance.
+
+ If necessary, QmlTimeLine will reduce the acceleration to ensure that the
+ entire operation does not require a move of more than \a maxDistance.
+ \a maxDistance should always be positive.
+*/
+int QmlTimeLine::accel(QmlTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
+{
+ Q_ASSERT(acceleration >= 0.0f && maxDistance >= 0.0f);
+
+ qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance);
+ if (maxAccel > acceleration)
+ acceleration = maxAccel;
+
+ if ((velocity > 0.0f) == (acceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+
+ int time = static_cast<int>(-1000 * velocity / acceleration);
+
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ Decelerate \a timeLineValue from the starting \a velocity to zero over the given
+ \a distance. This is like accel(), but the QmlTimeLine calculates the exact
+ deceleration to use.
+
+ \a distance should be positive.
+*/
+int QmlTimeLine::accelDistance(QmlTimeLineValue &timeLineValue, qreal velocity, qreal distance)
+{
+ if (distance == 0.0f || velocity == 0.0f)
+ return -1;
+ Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f));
+
+ int time = static_cast<int>(1000 * (2.0f * distance) / velocity);
+
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++);
+ d->add(timeLineValue, op);
+
+ return time;
+}
+
+/*!
+ Linearly change the \a timeLineValue from its current value to the given
+ \a destination value over \a time milliseconds.
+*/
+void QmlTimeLine::move(QmlTimeLineValue &timeLineValue, qreal destination, int time)
+{
+ if (time <= 0) return;
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Change the \a timeLineValue from its current value to the given \a destination
+ value over \a time milliseconds using the \a easing curve.
+ */
+void QmlTimeLine::move(QmlTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QmlTimeLineEvent(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Linearly change the \a timeLineValue from its current value by the \a change amount
+ over \a time milliseconds.
+*/
+void QmlTimeLine::moveBy(QmlTimeLineValue &timeLineValue, qreal change, int time)
+{
+ if (time <= 0) return;
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Change the \a timeLineValue from its current value by the \a change amount over
+ \a time milliseconds using the \a easing curve.
+ */
+void QmlTimeLine::moveBy(QmlTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QmlTimeLineEvent(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Cancel (but don't complete) all scheduled actions for \a timeLineValue.
+*/
+void QmlTimeLine::reset(QmlTimeLineValue &timeLineValue)
+{
+ if (!timeLineValue._t)
+ return;
+ if (timeLineValue._t != this) {
+ qWarning() << "QmlTimeLine: Cannot reset a QmlTimeLineValue owned by another timeline.";
+ return;
+ }
+ remove(&timeLineValue);
+ timeLineValue._t = 0;
+}
+
+int QmlTimeLine::duration() const
+{
+ return -1;
+}
+
+/*!
+ Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo
+ within this timeline.
+
+ Following operations on \a timeLineValue in this timeline will be scheduled after
+ all the currently scheduled actions on \a syncTo are complete. In
+ psuedo-code this is equivalent to:
+ \code
+ QmlTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
+ \endcode
+*/
+void QmlTimeLine::sync(QmlTimeLineValue &timeLineValue, QmlTimeLineValue &syncTo)
+{
+ QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo);
+ if (iter == d->ops.end())
+ return;
+ int length = iter->length;
+
+ iter = d->ops.find(&timeLineValue);
+ if (iter == d->ops.end()) {
+ pause(timeLineValue, length);
+ } else {
+ int glength = iter->length;
+ pause(timeLineValue, length - glength);
+ }
+}
+
+/*!
+ Synchronize the end point of \a timeLineValue to the endpoint of the longest
+ action cursrently scheduled in the timeline.
+
+ In psuedo-code, this is equivalent to:
+ \code
+ QmlTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
+ \endcode
+*/
+void QmlTimeLine::sync(QmlTimeLineValue &timeLineValue)
+{
+ QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue);
+ if (iter == d->ops.end()) {
+ pause(timeLineValue, d->length);
+ } else {
+ pause(timeLineValue, d->length - iter->length);
+ }
+}
+
+/*
+ Synchronize all currently and future scheduled values in this timeline to
+ the longest action currently scheduled.
+
+ For example:
+ \code
+ value1->setValue(0.);
+ value2->setValue(0.);
+ value3->setValue(0.);
+ QmlTimeLine tl;
+ ...
+ tl.move(value1, 10, 200);
+ tl.move(value2, 10, 100);
+ tl.sync();
+ tl.move(value2, 20, 100);
+ tl.move(value3, 20, 100);
+ \endcode
+
+ will result in:
+
+ \table
+ \header \o \o 0ms \o 50ms \o 100ms \o 150ms \o 200ms \o 250ms \o 300ms
+ \row \o value1 \o 0 \o 2.5 \o 5.0 \o 7.5 \o 10 \o 10 \o 10
+ \row \o value2 \o 0 \o 5.0 \o 10.0 \o 10.0 \o 10.0 \o 15.0 \o 20.0
+ \row \o value2 \o 0 \o 0 \o 0 \o 0 \o 0 \o 10.0 \o 20.0
+ \endtable
+*/
+
+/*void QmlTimeLine::sync()
+{
+ for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter)
+ pause(*iter.key(), d->length - iter->length);
+ d->syncPoint = d->length;
+}*/
+
+/*!
+ \internal
+
+ Temporary hack.
+ */
+void QmlTimeLine::setSyncPoint(int sp)
+{
+ d->syncPoint = sp;
+}
+
+/*!
+ \internal
+
+ Temporary hack.
+ */
+int QmlTimeLine::syncPoint() const
+{
+ return d->syncPoint;
+}
+
+/*!
+ Returns true if the timeline is active. An active timeline is one where
+ QmlTimeLineValue actions are still pending.
+*/
+bool QmlTimeLine::isActive() const
+{
+ return !d->ops.isEmpty();
+}
+
+/*!
+ Completes the timeline. All queued actions are played to completion, and then discarded. For example,
+ \code
+ QmlTimeLineValue v(0.);
+ QmlTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.complete();
+ // v.value() == 100.
+ \endcode
+*/
+void QmlTimeLine::complete()
+{
+ d->advance(d->length);
+}
+
+/*!
+ Resets the timeline. All queued actions are discarded and QmlTimeLineValue's retain their current value. For example,
+ \code
+ QmlTimeLineValue v(0.);
+ QmlTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.clear();
+ // v.value() == 50.
+ \endcode
+*/
+void QmlTimeLine::clear()
+{
+ for (QmlTimeLinePrivate::Ops::ConstIterator iter = d->ops.begin(); iter != d->ops.end(); ++iter)
+ iter.key()->_t = 0;
+ d->ops.clear();
+ d->length = 0;
+ d->syncPoint = 0;
+ //XXX need stop here?
+}
+
+int QmlTimeLine::time() const
+{
+ return d->prevTime;
+}
+
+/*!
+ \fn void QmlTimeLine::updated()
+
+ Emitted each time the timeline modifies QmlTimeLineValues. Even if multiple
+ QmlTimeLineValues are changed, this signal is only emitted once for each clock tick.
+*/
+
+void QmlTimeLine::updateCurrentTime(int v)
+{
+ if (d->syncAdj == -1)
+ d->syncAdj = v;
+ v -= d->syncAdj;
+
+ int timeChanged = v - d->prevTime;
+#if 0
+ if (!timeChanged)
+ return;
+#endif
+ d->prevTime = v;
+ d->advance(timeChanged);
+ emit updated();
+
+ // Do we need to stop the clock?
+ if (d->ops.isEmpty()) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = false;
+ emit completed();
+ } /*else if (pauseTime > 0) {
+ GfxClock::cancelClock();
+ d->prevTime = 0;
+ GfxClock::pauseFor(pauseTime);
+ d->syncAdj = 0;
+ d->clockRunning = false;
+ }*/ else if (/*!GfxClock::isActive()*/ state() != Running) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = true;
+ d->syncAdj = 0;
+ start();
+ }
+}
+
+bool operator<(const QPair<int, Update> &lhs,
+ const QPair<int, Update> &rhs)
+{
+ return lhs.first < rhs.first;
+}
+
+int QmlTimeLinePrivate::advance(int t)
+{
+ int pauseTime = -1;
+
+ // XXX - surely there is a more efficient way?
+ do {
+ pauseTime = -1;
+ // Minimal advance time
+ int advanceTime = t;
+ for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ++iter) {
+ TimeLine &tl = *iter;
+ Op &op = tl.ops.first();
+ int length = op.length - tl.consumedOpLength;
+
+ if (length < advanceTime) {
+ advanceTime = length;
+ if (advanceTime == 0)
+ break;
+ }
+ }
+ t -= advanceTime;
+
+ // Process until then. A zero length advance time will only process
+ // sets.
+ QList<QPair<int, Update> > updates;
+
+ for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ) {
+ QmlTimeLineValue *v = static_cast<QmlTimeLineValue *>(iter.key());
+ TimeLine &tl = *iter;
+ Q_ASSERT(!tl.ops.isEmpty());
+
+ do {
+ Op &op = tl.ops.first();
+ if (advanceTime == 0 && op.length != 0)
+ continue;
+
+ if (tl.consumedOpLength == 0 &&
+ op.type != Op::Pause &&
+ op.type != Op::Execute)
+ tl.base = v->value();
+
+ if ((tl.consumedOpLength + advanceTime) == op.length) {
+ if (op.type == Op::Execute) {
+ updates << qMakePair(op.order, Update(op.event));
+ } else {
+ bool changed = false;
+ qreal val = value(op, op.length, tl.base, &changed);
+ if (changed)
+ updates << qMakePair(op.order, Update(v, val));
+ }
+ tl.length -= qMin(advanceTime, tl.length);
+ tl.consumedOpLength = 0;
+ tl.ops.removeFirst();
+ } else {
+ tl.consumedOpLength += advanceTime;
+ bool changed = false;
+ qreal val = value(op, tl.consumedOpLength, tl.base, &changed);
+ if (changed)
+ updates << qMakePair(op.order, Update(v, val));
+ tl.length -= qMin(advanceTime, tl.length);
+ break;
+ }
+
+ } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0);
+
+
+ if (tl.ops.isEmpty()) {
+ iter = ops.erase(iter);
+ v->_t = 0;
+ } else {
+ if (tl.ops.first().type == Op::Pause && pauseTime != 0) {
+ int opPauseTime = tl.ops.first().length - tl.consumedOpLength;
+ if (pauseTime == -1 || opPauseTime < pauseTime)
+ pauseTime = opPauseTime;
+ } else {
+ pauseTime = 0;
+ }
+ ++iter;
+ }
+ }
+
+ length -= qMin(length, advanceTime);
+ syncPoint -= advanceTime;
+
+ qSort(updates.begin(), updates.end());
+ updateQueue = &updates;
+ for (int ii = 0; ii < updates.count(); ++ii) {
+ const Update &v = updates.at(ii).second;
+ if (v.g)
+ v.g->setValue(v.v);
+ else
+ v.e.execute();
+ }
+ updateQueue = 0;
+ } while(t);
+
+ return pauseTime;
+}
+
+void QmlTimeLine::remove(QmlTimeLineObject *v)
+{
+ QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(v);
+ Q_ASSERT(iter != d->ops.end());
+
+ int len = iter->length;
+ d->ops.erase(iter);
+ if (len == d->length) {
+ // We need to recalculate the length
+ d->length = 0;
+ for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter) {
+
+ if (iter->length > d->length)
+ d->length = iter->length;
+
+ }
+ }
+ if (d->ops.isEmpty()) {
+ stop();
+ d->clockRunning = false;
+ } else if (/*!GfxClock::isActive()*/ state() != Running) {
+ stop();
+ d->prevTime = 0;
+ d->clockRunning = true;
+
+ if (d->syncMode == QmlTimeLine::LocalSync) {
+ d->syncAdj = -1;
+ } else {
+ d->syncAdj = 0;
+ }
+ start();
+ }
+
+ if (d->updateQueue) {
+ for (int ii = 0; ii < d->updateQueue->count(); ++ii) {
+ if (d->updateQueue->at(ii).second.g == v ||
+ d->updateQueue->at(ii).second.e.eventObject() == v) {
+ d->updateQueue->removeAt(ii);
+ --ii;
+ }
+ }
+ }
+
+
+}
+
+/*!
+ \internal
+ \class QmlTimeLineValue
+ \ingroup group_animation
+ \brief The QmlTimeLineValue class provides a value that can be modified by QmlTimeLine.
+*/
+
+/*!
+ \fn QmlTimeLineValue::QmlTimeLineValue(qreal value = 0)
+
+ Construct a new QmlTimeLineValue with an initial \a value.
+*/
+
+/*!
+ \fn qreal QmlTimeLineValue::value() const
+
+ Return the current value.
+*/
+
+/*!
+ \fn void QmlTimeLineValue::setValue(qreal value)
+
+ Set the current \a value.
+*/
+
+/*!
+ \fn QmlTimeLine *QmlTimeLineValue::timeLine() const
+
+ If a QmlTimeLine is operating on this value, return a pointer to it,
+ otherwise return null.
+*/
+
+
+QmlTimeLineObject::QmlTimeLineObject()
+: _t(0)
+{
+}
+
+QmlTimeLineObject::~QmlTimeLineObject()
+{
+ if (_t) {
+ _t->remove(this);
+ _t = 0;
+ }
+}
+
+QmlTimeLineEvent::QmlTimeLineEvent()
+: d0(0), d1(0), d2(0)
+{
+}
+
+QmlTimeLineEvent::QmlTimeLineEvent(const QmlTimeLineEvent &o)
+: d0(o.d0), d1(o.d1), d2(o.d2)
+{
+}
+
+QmlTimeLineEvent &QmlTimeLineEvent::operator=(const QmlTimeLineEvent &o)
+{
+ d0 = o.d0;
+ d1 = o.d1;
+ d2 = o.d2;
+ return *this;
+}
+
+void QmlTimeLineEvent::execute() const
+{
+ d0(d1);
+}
+
+QmlTimeLineObject *QmlTimeLineEvent::eventObject() const
+{
+ return d2;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmltimeline_p_p.h b/src/declarative/util/qmltimeline_p_p.h
new file mode 100644
index 0000000..09d46ba
--- /dev/null
+++ b/src/declarative/util/qmltimeline_p_p.h
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLTIMELINE_H
+#define QMLTIMELINE_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 <QtCore/QObject>
+#include <QtCore/QAbstractAnimation>
+
+QT_BEGIN_NAMESPACE
+
+class QEasingCurve;
+class QmlTimeLineValue;
+class QmlTimeLineEvent;
+struct QmlTimeLinePrivate;
+class QmlTimeLineObject;
+class Q_DECLARATIVE_EXPORT QmlTimeLine : public QAbstractAnimation
+{
+Q_OBJECT
+public:
+ QmlTimeLine(QObject *parent = 0);
+ ~QmlTimeLine();
+
+ enum SyncMode { LocalSync, GlobalSync };
+ SyncMode syncMode() const;
+ void setSyncMode(SyncMode);
+
+ void pause(QmlTimeLineObject &, int);
+ void execute(const QmlTimeLineEvent &);
+ void set(QmlTimeLineValue &, qreal);
+
+ int accel(QmlTimeLineValue &, qreal velocity, qreal accel);
+ int accel(QmlTimeLineValue &, qreal velocity, qreal accel, qreal maxDistance);
+ int accelDistance(QmlTimeLineValue &, qreal velocity, qreal distance);
+
+ void move(QmlTimeLineValue &, qreal destination, int time = 500);
+ void move(QmlTimeLineValue &, qreal destination, const QEasingCurve &, int time = 500);
+ void moveBy(QmlTimeLineValue &, qreal change, int time = 500);
+ void moveBy(QmlTimeLineValue &, qreal change, const QEasingCurve &, int time = 500);
+
+ void sync();
+ void setSyncPoint(int);
+ int syncPoint() const;
+
+ void sync(QmlTimeLineValue &);
+ void sync(QmlTimeLineValue &, QmlTimeLineValue &);
+
+ void reset(QmlTimeLineValue &);
+
+ void complete();
+ void clear();
+ bool isActive() const;
+
+ int time() const;
+
+ virtual int duration() const;
+Q_SIGNALS:
+ void updated();
+ void completed();
+
+protected:
+ virtual void updateCurrentTime(int);
+
+private:
+ void remove(QmlTimeLineObject *);
+ friend class QmlTimeLineObject;
+ friend struct QmlTimeLinePrivate;
+ QmlTimeLinePrivate *d;
+};
+
+class Q_DECLARATIVE_EXPORT QmlTimeLineObject
+{
+public:
+ QmlTimeLineObject();
+ virtual ~QmlTimeLineObject();
+
+protected:
+ friend class QmlTimeLine;
+ friend struct QmlTimeLinePrivate;
+ QmlTimeLine *_t;
+};
+
+class Q_DECLARATIVE_EXPORT QmlTimeLineValue : public QmlTimeLineObject
+{
+public:
+ QmlTimeLineValue(qreal v = 0.) : _v(v) {}
+
+ virtual qreal value() const { return _v; }
+ virtual void setValue(qreal v) { _v = v; }
+
+ QmlTimeLine *timeLine() const { return _t; }
+
+ operator qreal() const { return _v; }
+ QmlTimeLineValue &operator=(qreal v) { setValue(v); return *this; }
+private:
+ friend class QmlTimeLine;
+ friend struct QmlTimeLinePrivate;
+ qreal _v;
+};
+
+class Q_DECLARATIVE_EXPORT QmlTimeLineEvent
+{
+public:
+ QmlTimeLineEvent();
+ QmlTimeLineEvent(const QmlTimeLineEvent &o);
+
+ template<class T, void (T::*method)()>
+ QmlTimeLineEvent(QmlTimeLineObject *b, T *c)
+ {
+ d0 = &callFunc<T, method>;
+ d1 = (void *)c;
+ d2 = b;
+ }
+
+ template<class T, void (T::*method)()>
+ static QmlTimeLineEvent timeLineEvent(QmlTimeLineObject *b, T *c)
+ {
+ QmlTimeLineEvent rv;
+ rv.d0 = &callFunc<T, method>;
+ rv.d1 = (void *)c;
+ rv.d2 = b;
+ return rv;
+ }
+
+ QmlTimeLineEvent &operator=(const QmlTimeLineEvent &o);
+ void execute() const;
+ QmlTimeLineObject *eventObject() const;
+
+private:
+ typedef void (*CallFunc)(void *c);
+
+ template <class T, void (T::*method)()>
+ static void callFunc(void *c)
+ {
+ T *cls = (T *)c;
+ (cls->*method)();
+ }
+ CallFunc d0;
+ void *d1;
+ QmlTimeLineObject *d2;
+};
+
+template<class T>
+class QmlTimeLineValueProxy : public QmlTimeLineValue
+{
+public:
+ QmlTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.)
+ : QmlTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0)
+ {
+ Q_ASSERT(_class);
+ }
+
+ QmlTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.)
+ : QmlTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func)
+ {
+ Q_ASSERT(_class);
+ }
+
+ virtual void setValue(qreal v)
+ {
+ QmlTimeLineValue::setValue(v);
+ if (_setFunctionReal) (_class->*_setFunctionReal)(v);
+ else if (_setFunctionInt) (_class->*_setFunctionInt)((int)v);
+ }
+
+private:
+ T *_class;
+ void (T::*_setFunctionReal)(qreal);
+ void (T::*_setFunctionInt)(int);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/util/qmltimer.cpp b/src/declarative/util/qmltimer.cpp
new file mode 100644
index 0000000..046dfe9
--- /dev/null
+++ b/src/declarative/util/qmltimer.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmltimer_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpauseanimation.h>
+#include <qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,Timer,QmlTimer)
+
+class QmlTimerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlTimer)
+public:
+ QmlTimerPrivate()
+ : interval(1000), running(false), repeating(false), triggeredOnStart(false)
+ , classBegun(false), componentComplete(false), firstTick(true) {}
+ int interval;
+ QPauseAnimation pause;
+ bool running : 1;
+ bool repeating : 1;
+ bool triggeredOnStart : 1;
+ bool classBegun : 1;
+ bool componentComplete : 1;
+ bool firstTick : 1;
+};
+
+/*!
+ \qmlclass Timer QmlTimer
+ \brief The Timer item triggers a handler at a specified interval.
+
+ A timer can be used to trigger an action either once, or repeatedly
+ at a given interval.
+
+ Here is a timer that shows the current date and time, and updates
+ the text every 500 milliseconds:
+
+ \qml
+ Timer {
+ interval: 500; running: true; repeat: true
+ onTriggered: time.text = Date().toString()
+ }
+ Text {
+ id: time
+ }
+ \endqml
+
+ QmlTimer is synchronized with the animation timer. Since the animation
+ timer is usually set to 60fps, the resolution of QmlTimer will be
+ at best 16ms.
+
+ If the Timer is running and one of its properties is changed, the
+ elapsed time will be reset. For example, if a Timer with interval of
+ 1000ms has its \e repeat property changed 500ms after starting, the
+ elapsed time will be reset to 0, and the Timer will be triggered
+ 1000ms later.
+*/
+
+QmlTimer::QmlTimer(QObject *parent)
+ : QObject(*(new QmlTimerPrivate), parent)
+{
+ Q_D(QmlTimer);
+ connect(&d->pause, SIGNAL(currentLoopChanged(int)), this, SLOT(ticked()));
+ connect(&d->pause, SIGNAL(finished()), this, SLOT(finished()));
+ d->pause.setLoopCount(1);
+ d->pause.setDuration(d->interval);
+}
+
+/*!
+ \qmlproperty int Timer::interval
+
+ Sets the \a interval between triggers, in milliseconds.
+
+ The default interval is 1000 milliseconds.
+*/
+void QmlTimer::setInterval(int interval)
+{
+ Q_D(QmlTimer);
+ if (interval != d->interval) {
+ d->interval = interval;
+ update();
+ }
+}
+
+int QmlTimer::interval() const
+{
+ Q_D(const QmlTimer);
+ return d->interval;
+}
+
+/*!
+ \qmlproperty bool Timer::running
+
+ If set to true, starts the timer; otherwise stops the timer.
+ For a non-repeating timer, \a running is set to false after the
+ timer has been triggered.
+
+ \a running defaults to false.
+
+ \sa repeat
+*/
+bool QmlTimer::isRunning() const
+{
+ Q_D(const QmlTimer);
+ return d->running;
+}
+
+void QmlTimer::setRunning(bool running)
+{
+ Q_D(QmlTimer);
+ if (d->running != running) {
+ d->running = running;
+ d->firstTick = true;
+ emit runningChanged();
+ update();
+ }
+}
+
+/*!
+ \qmlproperty bool Timer::repeat
+
+ If \a repeat is true the timer is triggered repeatedly at the
+ specified interval; otherwise, the timer will trigger once at the
+ specified interval and then stop (i.e. running will be set to false).
+
+ \a repeat defaults to false.
+
+ \sa running
+*/
+bool QmlTimer::isRepeating() const
+{
+ Q_D(const QmlTimer);
+ return d->repeating;
+}
+
+void QmlTimer::setRepeating(bool repeating)
+{
+ Q_D(QmlTimer);
+ if (repeating != d->repeating) {
+ d->repeating = repeating;
+ update();
+ }
+}
+
+/*!
+ \qmlproperty bool Timer::triggeredOnStart
+
+ When a timer is started, the first trigger is usually after the specified
+ interval has elapsed. It is sometimes desirable to trigger immediately
+ when the timer is started; for example, to establish an initial
+ state.
+
+ If \a triggeredOnStart is true, the timer is triggered immediately
+ when started, and subsequently at the specified interval. Note that if
+ \e repeat is set to false, the timer is triggered twice; once on start,
+ and again at the interval.
+
+ \a triggeredOnStart defaults to false.
+
+ \sa running
+*/
+bool QmlTimer::triggeredOnStart() const
+{
+ Q_D(const QmlTimer);
+ return d->triggeredOnStart;
+}
+
+void QmlTimer::setTriggeredOnStart(bool triggeredOnStart)
+{
+ Q_D(QmlTimer);
+ if (d->triggeredOnStart != triggeredOnStart) {
+ d->triggeredOnStart = triggeredOnStart;
+ update();
+ }
+}
+
+/*!
+ \qmlmethod Timer::start()
+ \brief Starts the timer.
+
+ If the timer is already running, calling this method has no effect. The
+ \c running property will be true following a call to \c start().
+*/
+void QmlTimer::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod Timer::stop()
+ \brief Stops the timer.
+
+ If the timer is not running, calling this method has no effect. The
+ \c running property will be false following a call to \c stop().
+*/
+void QmlTimer::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod Timer::restart()
+ \brief Restarts the timer.
+
+ If the Timer is not running it will be started, otherwise it will be
+ stopped, reset to initial state and started. The \c running property
+ will be true following a call to \c restart().
+*/
+void QmlTimer::restart()
+{
+ setRunning(false);
+ setRunning(true);
+}
+
+void QmlTimer::update()
+{
+ Q_D(QmlTimer);
+ if (d->classBegun && !d->componentComplete)
+ return;
+ d->pause.stop();
+ if (d->running) {
+ d->pause.setCurrentTime(0);
+ d->pause.setLoopCount(d->repeating ? -1 : 1);
+ d->pause.setDuration(d->interval);
+ d->pause.start();
+ if (d->triggeredOnStart && d->firstTick) {
+ QCoreApplication::removePostedEvents(this, QEvent::MetaCall);
+ QMetaObject::invokeMethod(this, "ticked", Qt::QueuedConnection);
+ }
+ }
+}
+
+void QmlTimer::classBegin()
+{
+ Q_D(QmlTimer);
+ d->classBegun = true;
+}
+
+void QmlTimer::componentComplete()
+{
+ Q_D(QmlTimer);
+ d->componentComplete = true;
+ update();
+}
+
+/*!
+ \qmlsignal Timer::onTriggered()
+
+ This handler is called when the Timer is triggered.
+*/
+void QmlTimer::ticked()
+{
+ Q_D(QmlTimer);
+ if (d->running && (d->pause.currentTime() > 0 || (d->triggeredOnStart && d->firstTick)))
+ emit triggered();
+ d->firstTick = false;
+}
+
+void QmlTimer::finished()
+{
+ Q_D(QmlTimer);
+ if (d->repeating || !d->running)
+ return;
+ emit triggered();
+ d->running = false;
+ d->firstTick = false;
+ emit runningChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmltimer_p.h b/src/declarative/util/qmltimer_p.h
new file mode 100644
index 0000000..fcd6c84
--- /dev/null
+++ b/src/declarative/util/qmltimer_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLTIMER_H
+#define QMLTIMER_H
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractanimation.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlTimerPrivate;
+class Q_DECLARATIVE_EXPORT QmlTimer : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlTimer)
+ Q_INTERFACES(QmlParserStatus)
+ Q_PROPERTY(int interval READ interval WRITE setInterval)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating)
+ Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart)
+
+public:
+ QmlTimer(QObject *parent=0);
+
+ void setInterval(int interval);
+ int interval() const;
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+ bool isRepeating() const;
+ void setRepeating(bool repeating);
+
+ bool triggeredOnStart() const;
+ void setTriggeredOnStart(bool triggeredOnStart);
+
+protected:
+ void classBegin();
+ void componentComplete();
+
+public Q_SLOTS:
+ void start();
+ void stop();
+ void restart();
+
+Q_SIGNALS:
+ void triggered();
+ void runningChanged();
+
+private:
+ void update();
+
+private Q_SLOTS:
+ void ticked();
+ void finished();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlTimer)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qmltransition.cpp b/src/declarative/util/qmltransition.cpp
new file mode 100644
index 0000000..215fc91
--- /dev/null
+++ b/src/declarative/util/qmltransition.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlstate_p.h"
+#include "qmlstategroup_p.h"
+#include "qmlstate_p_p.h"
+#include "qmlstateoperations_p.h"
+#include "qmlanimation_p.h"
+#include "qmlanimation_p_p.h"
+#include "qmltransitionmanager_p_p.h"
+
+#include <QParallelAnimationGroup>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Transition QmlTransition
+ \brief The Transition element defines animated transitions that occur on state changes.
+
+ \sa {qmlstates}{States}, {state-transitions}{Transitions}
+*/
+
+/*!
+ \internal
+ \class QmlTransition
+ \brief The QmlTransition class allows you to define animated transitions that occur on state changes.
+
+ \ingroup group_states
+*/
+
+//ParallelAnimationWrapperallows us to do a "callback" when the animation finishes, rather than connecting
+//and disconnecting signals and slots frequently
+class ParallelAnimationWrapper : public QParallelAnimationGroup
+{
+ Q_OBJECT
+public:
+ ParallelAnimationWrapper(QObject *parent = 0) : QParallelAnimationGroup(parent) {}
+ QmlTransitionPrivate *trans;
+protected:
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState);
+};
+
+class QmlTransitionPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlTransition)
+public:
+ QmlTransitionPrivate() : fromState(QLatin1String("*")), toState(QLatin1String("*"))
+ , reversed(false), reversible(false), endState(0)
+ {
+ animations.parent = this;
+ }
+
+ QString fromState;
+ QString toState;
+ bool reversed;
+ bool reversible;
+ ParallelAnimationWrapper group;
+ QmlTransitionManager *endState;
+
+ void init()
+ {
+ group.trans = this;
+ }
+
+ void complete()
+ {
+ endState->complete();
+ }
+
+ class AnimationList : public QmlConcreteList<QmlAbstractAnimation *>
+ {
+ public:
+ AnimationList() : parent(0) {}
+ virtual void append(QmlAbstractAnimation *a);
+ virtual void clear() { QmlConcreteList<QmlAbstractAnimation *>::clear(); } //###
+
+ QmlTransitionPrivate *parent;
+ };
+ AnimationList animations;
+};
+
+void QmlTransitionPrivate::AnimationList::append(QmlAbstractAnimation *a)
+{
+ QmlConcreteList<QmlAbstractAnimation *>::append(a);
+ parent->group.addAnimation(a->qtAnimation());
+}
+
+void ParallelAnimationWrapper::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+{
+ QParallelAnimationGroup::updateState(newState, oldState);
+ if (newState == Stopped &&
+ ((direction() == QAbstractAnimation::Forward && currentLoopTime() == duration()) ||
+ (direction() == QAbstractAnimation::Backward && currentLoopTime() == 0)))
+ {
+ trans->complete();
+ }
+}
+
+
+QML_DEFINE_TYPE(Qt,4,6,Transition,QmlTransition)
+QmlTransition::QmlTransition(QObject *parent)
+ : QObject(*(new QmlTransitionPrivate), parent)
+{
+ Q_D(QmlTransition);
+ d->init();
+}
+
+QmlTransition::~QmlTransition()
+{
+}
+
+void QmlTransition::stop()
+{
+ Q_D(QmlTransition);
+ d->group.stop();
+}
+
+void QmlTransition::setReversed(bool r)
+{
+ Q_D(QmlTransition);
+ d->reversed = r;
+}
+
+void QmlTransition::prepare(QmlStateOperation::ActionList &actions,
+ QList<QmlMetaProperty> &after,
+ QmlTransitionManager *endState)
+{
+ Q_D(QmlTransition);
+
+ qmlExecuteDeferred(this);
+
+ if (d->reversed) {
+ for (int ii = d->animations.count() - 1; ii >= 0; --ii) {
+ d->animations.at(ii)->transition(actions, after, QmlAbstractAnimation::Backward);
+ }
+ } else {
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ d->animations.at(ii)->transition(actions, after, QmlAbstractAnimation::Forward);
+ }
+ }
+
+ d->endState = endState;
+ d->group.setDirection(d->reversed ? QAbstractAnimation::Backward : QAbstractAnimation::Forward);
+ d->group.start();
+}
+
+/*!
+ \qmlproperty string Transition::from
+ \qmlproperty string Transition::to
+ These properties are selectors indicating which state changes should trigger the transition.
+
+ from is used in conjunction with to to determine when a transition should
+ be applied. By default from and to are both "*" (any state). In the following example,
+ the transition is applied when changing from state1 to state2.
+ \code
+ Transition {
+ from: "state1"
+ to: "state2"
+ ...
+ }
+ \endcode
+*/
+QString QmlTransition::fromState() const
+{
+ Q_D(const QmlTransition);
+ return d->fromState;
+}
+
+void QmlTransition::setFromState(const QString &f)
+{
+ Q_D(QmlTransition);
+ d->fromState = f;
+}
+
+/*!
+ \qmlproperty bool Transition::reversible
+ This property holds whether the transition should be automatically reversed when the conditions that triggered this transition are reversed.
+
+ The default value is false.
+*/
+bool QmlTransition::reversible() const
+{
+ Q_D(const QmlTransition);
+ return d->reversible;
+}
+
+void QmlTransition::setReversible(bool r)
+{
+ Q_D(QmlTransition);
+ d->reversible = r;
+}
+
+QString QmlTransition::toState() const
+{
+ Q_D(const QmlTransition);
+ return d->toState;
+}
+
+void QmlTransition::setToState(const QString &t)
+{
+ Q_D(QmlTransition);
+ d->toState = t;
+}
+
+/*!
+ \qmlproperty list<Animation> Transition::animations
+ \default
+ This property holds a list of the animations to be run for this transition.
+
+ The top-level animations are run in parallel. To run them sequentially,
+ you can create a single SequentialAnimation which contains all the animations,
+ and assign that to animations the animations property.
+ \default
+*/
+QmlList<QmlAbstractAnimation *>* QmlTransition::animations()
+{
+ Q_D(QmlTransition);
+ return &d->animations;
+}
+
+QT_END_NAMESPACE
+
+#include <qmltransition.moc>
diff --git a/src/declarative/util/qmltransition_p.h b/src/declarative/util/qmltransition_p.h
new file mode 100644
index 0000000..c1a6f66
--- /dev/null
+++ b/src/declarative/util/qmltransition_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLTRANSITION_H
+#define QMLTRANSITION_H
+
+#include "qmlstate_p.h"
+
+#include <qml.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlAbstractAnimation;
+class QmlTransitionPrivate;
+class QmlTransitionManager;
+class Q_DECLARATIVE_EXPORT QmlTransition : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QmlTransition)
+
+ Q_PROPERTY(QString from READ fromState WRITE setFromState)
+ Q_PROPERTY(QString to READ toState WRITE setToState)
+ Q_PROPERTY(bool reversible READ reversible WRITE setReversible)
+ Q_PROPERTY(QmlList<QmlAbstractAnimation *>* animations READ animations)
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_CLASSINFO("DeferredPropertyNames", "animations")
+
+public:
+ QmlTransition(QObject *parent=0);
+ ~QmlTransition();
+
+ QString fromState() const;
+ void setFromState(const QString &);
+
+ QString toState() const;
+ void setToState(const QString &);
+
+ bool reversible() const;
+ void setReversible(bool);
+
+ QmlList<QmlAbstractAnimation *>* animations();
+
+ void prepare(QmlStateOperation::ActionList &actions,
+ QList<QmlMetaProperty> &after,
+ QmlTransitionManager *end);
+
+ void setReversed(bool r);
+ void stop();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlTransition)
+
+QT_END_HEADER
+
+#endif // QMLTRANSITION_H
diff --git a/src/declarative/util/qmltransitionmanager.cpp b/src/declarative/util/qmltransitionmanager.cpp
new file mode 100644
index 0000000..a3a16ca
--- /dev/null
+++ b/src/declarative/util/qmltransitionmanager.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmltransitionmanager_p_p.h"
+
+#include "qmlstate_p_p.h"
+
+#include <qmlbinding.h>
+#include <qmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+class QmlTransitionManagerPrivate
+{
+public:
+ QmlTransitionManagerPrivate()
+ : state(0), transition(0) {}
+
+ void applyBindings();
+ typedef QList<QmlSimpleAction> SimpleActionList;
+ QmlState *state;
+ QmlTransition *transition;
+ QmlStateOperation::ActionList bindingsList;
+ SimpleActionList completeList;
+};
+
+QmlTransitionManager::QmlTransitionManager()
+: d(new QmlTransitionManagerPrivate)
+{
+}
+
+void QmlTransitionManager::setState(QmlState *s)
+{
+ d->state = s;
+}
+
+QmlTransitionManager::~QmlTransitionManager()
+{
+ delete d; d = 0;
+}
+
+void QmlTransitionManager::complete()
+{
+ d->applyBindings();
+
+ for (int ii = 0; ii < d->completeList.count(); ++ii) {
+ const QmlMetaProperty &prop = d->completeList.at(ii).property;
+ prop.write(d->completeList.at(ii).value);
+ }
+
+ d->completeList.clear();
+
+ if (d->state)
+ static_cast<QmlStatePrivate*>(QObjectPrivate::get(d->state))->complete();
+}
+
+void QmlTransitionManagerPrivate::applyBindings()
+{
+ foreach(const QmlAction &action, bindingsList) {
+ if (action.toBinding) {
+ action.property.setBinding(action.toBinding);
+ } else if (action.event) {
+ if (action.reverseEvent)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+
+ }
+
+ bindingsList.clear();
+}
+
+void QmlTransitionManager::transition(const QList<QmlAction> &list,
+ QmlTransition *transition)
+{
+ cancel();
+
+ QmlStateOperation::ActionList applyList = list;
+ // Determine which actions are binding changes.
+ foreach(const QmlAction &action, applyList) {
+ if (action.toBinding)
+ d->bindingsList << action;
+ if (action.fromBinding)
+ action.property.setBinding(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();
+ }
+ }
+
+ // Animated transitions need both the start and the end value for
+ // each property change. In the presence of bindings, the end values
+ // are non-trivial to calculate. As a "best effort" attempt, we first
+ // apply all the property and binding changes, then read all the actual
+ // final values, then roll back the changes and proceed as normal.
+ //
+ // This doesn't catch everything, and it might be a little fragile in
+ // some cases - but whatcha going to do?
+
+ if (!d->bindingsList.isEmpty()) {
+
+ //### do extra actions here?
+
+ // Apply all the property and binding changes
+ for (int ii = 0; ii < applyList.size(); ++ii) {
+ const QmlAction &action = applyList.at(ii);
+ if (action.toBinding) {
+ action.property.setBinding(action.toBinding, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ } else if (!action.event) {
+ action.property.write(action.toValue, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ } else if (action.event->isReversable()) {
+ if (action.reverseEvent)
+ 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) {
+ QmlAction *action = &applyList[ii];
+ if (action->event)
+ continue;
+ const QmlMetaProperty &prop = action->property;
+ if (action->toBinding || !action->toValue.isValid()) { //### is this always right (used for exta actions)
+ action->toValue = prop.read();
+ }
+ }
+
+ // Revert back to the original values
+ foreach(const QmlAction &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();
+ }
+ }
+ continue;
+ }
+
+ if (action.toBinding)
+ action.property.setBinding(0); // Make sure this is disabled during the transition
+
+ action.property.write(action.fromValue, QmlMetaProperty::BypassInterceptor | QmlMetaProperty::DontRemoveBinding);
+ }
+ }
+
+ if (transition) {
+ QList<QmlMetaProperty> touched;
+ d->transition = transition;
+ d->transition->prepare(applyList, touched, this);
+
+ // Modify the action list to remove actions handled in the transition
+ for (int ii = 0; ii < applyList.count(); ++ii) {
+ const QmlAction &action = applyList.at(ii);
+
+ if (action.event) {
+
+ if (action.actionDone) {
+ applyList.removeAt(ii);
+ --ii;
+ }
+
+ } else {
+
+ if (touched.contains(action.property)) {
+ if (action.toValue != action.fromValue)
+ d->completeList <<
+ QmlSimpleAction(action, QmlSimpleAction::EndState);
+
+ applyList.removeAt(ii);
+ --ii;
+ }
+
+ }
+ }
+ }
+
+ // Any actions remaining have not been handled by the transition and should
+ // be applied immediately. We skip applying bindings, as they are all
+ // applied at the end in applyBindings() to avoid any nastiness mid
+ // transition
+ foreach(const QmlAction &action, applyList) {
+ if (action.event && !action.event->changesBindings()) {
+ if (action.event->isReversable() && action.reverseEvent)
+ action.event->reverse();
+ else
+ action.event->execute();
+ } else if (!action.event && !action.toBinding) {
+ action.property.write(action.toValue);
+ }
+ }
+ if (stateChangeDebug()) {
+ foreach(const QmlAction &action, applyList) {
+ if (action.event)
+ qWarning() << " No transition for event:" << action.event->typeName();
+ else
+ qWarning() << " No transition for:" << action.property.object()
+ << action.property.name() << "From:" << action.fromValue
+ << "To:" << action.toValue;
+ }
+ }
+ if (!transition)
+ d->applyBindings();
+}
+
+void QmlTransitionManager::cancel()
+{
+ if (d->transition) {
+ // ### this could potentially trigger a complete in rare circumstances
+ d->transition->stop();
+ d->transition = 0;
+ }
+
+ for(int i = 0; i < d->bindingsList.count(); ++i) {
+ QmlAction action = d->bindingsList[i];
+ if (action.toBinding && action.deletableToBinding) {
+ action.property.setBinding(0);
+ action.toBinding->destroy();
+ action.toBinding = 0;
+ action.deletableToBinding = false;
+ } else if (action.event) {
+ //### what do we do here?
+ }
+
+ }
+ d->bindingsList.clear();
+ d->completeList.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmltransitionmanager_p_p.h b/src/declarative/util/qmltransitionmanager_p_p.h
new file mode 100644
index 0000000..cb4111c
--- /dev/null
+++ b/src/declarative/util/qmltransitionmanager_p_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLTRANSITIONMANAGER_P_H
+#define QMLTRANSITIONMANAGER_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 "qmlstateoperations_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlStatePrivate;
+class QmlTransitionManagerPrivate;
+class QmlTransitionManager
+{
+public:
+ QmlTransitionManager();
+ ~QmlTransitionManager();
+
+ void transition(const QList<QmlAction> &, QmlTransition *transition);
+
+ void cancel();
+
+private:
+ Q_DISABLE_COPY(QmlTransitionManager);
+ QmlTransitionManagerPrivate *d;
+
+ void complete();
+ void setState(QmlState *);
+
+ friend class QmlState;
+ friend class QmlTransitionPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLTRANSITIONMANAGER_P_H
diff --git a/src/declarative/util/qmlview.cpp b/src/declarative/util/qmlview.cpp
new file mode 100644
index 0000000..690924f
--- /dev/null
+++ b/src/declarative/util/qmlview.cpp
@@ -0,0 +1,586 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlview.h"
+
+#include "qperformancelog_p_p.h"
+#include "qfxperf_p_p.h"
+
+#include <qml.h>
+#include <qmlgraphicsitem.h>
+#include <qmlengine.h>
+#include <qmlcontext.h>
+#include <qmldebug_p.h>
+#include <qmldebugservice_p.h>
+#include <qmlglobal_p.h>
+
+#include <qscriptvalueiterator.h>
+#include <qdebug.h>
+#include <qtimer.h>
+#include <qevent.h>
+#include <qdir.h>
+#include <qcoreapplication.h>
+#include <qfontdatabase.h>
+#include <qicon.h>
+#include <qurl.h>
+#include <qboxlayout.h>
+#include <qbasictimer.h>
+#include <QtCore/qabstractanimation.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)
+
+class QmlViewDebugServer;
+class FrameBreakAnimation : public QAbstractAnimation
+{
+public:
+ FrameBreakAnimation(QmlViewDebugServer *s)
+ : QAbstractAnimation((QObject*)s), server(s)
+ {
+ start();
+ }
+
+ virtual int duration() const { return -1; }
+ virtual void updateCurrentTime(int msecs);
+
+private:
+ QmlViewDebugServer *server;
+};
+
+class QmlViewDebugServer : public QmlDebugService
+{
+public:
+ QmlViewDebugServer(QObject *parent = 0) : QmlDebugService(QLatin1String("CanvasFrameRate"), parent), breaks(0)
+ {
+ timer.start();
+ new FrameBreakAnimation(this);
+ }
+
+ void addTiming(int pe, int tbf)
+ {
+ if (!isEnabled())
+ return;
+
+ bool isFrameBreak = breaks > 1;
+ breaks = 0;
+ int e = timer.elapsed();
+ QByteArray data;
+ QDataStream ds(&data, QIODevice::WriteOnly);
+ ds << (int)pe << (int)tbf << (int)e
+ << (bool)isFrameBreak;
+ sendMessage(data);
+ }
+
+ void frameBreak() { ++breaks; }
+
+private:
+ QTime timer;
+ int breaks;
+};
+
+Q_GLOBAL_STATIC(QmlViewDebugServer, qfxViewDebugServer);
+
+void FrameBreakAnimation::updateCurrentTime(int msecs)
+{
+ Q_UNUSED(msecs);
+ server->frameBreak();
+}
+
+class QmlViewPrivate
+{
+public:
+ QmlViewPrivate(QmlView *w)
+ : q(w), root(0), component(0), resizable(false) {}
+
+ QmlView *q;
+ QmlGraphicsItem *root;
+
+ QUrl source;
+ QString qml;
+
+ QmlEngine engine;
+ QmlComponent *component;
+ QBasicTimer resizetimer;
+
+ QSize initialSize;
+ bool resizable;
+ QTime frameTimer;
+
+ void init();
+
+ QGraphicsScene scene;
+};
+
+/*!
+ \class QmlView
+ \brief The QmlView class provides a widget for displaying a Qt Declarative user interface.
+
+ QmlView currently provides a minimal interface for displaying QML
+ files, and connecting between QML and C++ Qt objects.
+
+ Typical usage:
+ \code
+ ...
+ QmlView *view = new QmlView(this);
+ vbox->addWidget(view);
+
+ QUrl url(fileName);
+ view->setUrl(url);
+ ...
+ view->execute();
+ ...
+ view->show();
+ \endcode
+
+ To receive errors related to loading and executing QML with QmlView,
+ you can connect to the errors() signal.
+*/
+
+/*!
+ \fn QmlView::QmlView(QWidget *parent)
+
+ Constructs a QmlView with the given \a parent.
+*/
+QmlView::QmlView(QWidget *parent)
+: QGraphicsView(parent), d(new QmlViewPrivate(this))
+{
+ setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
+ d->init();
+}
+
+void QmlViewPrivate::init()
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ {
+ QmlPerfTimer<QmlPerf::FontDatabase> perf;
+ QFontDatabase database;
+ }
+#endif
+
+ q->setScene(&scene);
+
+ q->setOptimizationFlags(QGraphicsView::DontSavePainterState);
+ q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ q->setFrameStyle(0);
+
+ // These seem to give the best performance
+ q->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+ scene.setItemIndexMethod(QGraphicsScene::NoIndex);
+ q->viewport()->setFocusPolicy(Qt::NoFocus);
+
+ scene.setStickyFocus(true); //### needed for correct focus handling
+}
+
+/*!
+ The destructor clears the view's \l {QmlGraphicsItem} {items} and
+ deletes the internal representation.
+
+ \sa clearItems()
+ */
+QmlView::~QmlView()
+{
+ clearItems();
+ delete d; d = 0;
+}
+
+/*!
+ Sets the source to the \a url. The QML string is set to
+ empty.
+ */
+void QmlView::setUrl(const QUrl& url)
+{
+ d->source = url;
+ d->qml = QString();
+}
+
+/*!
+ Returns the source URL, if set.
+
+ \sa setUrl()
+ */
+QUrl QmlView::url() const
+{
+ return d->source;
+}
+
+/*!
+ Sets the source to the URL from the \a filename, and sets
+ the QML string to \a qml.
+ */
+void QmlView::setQml(const QString &qml, const QString &filename)
+{
+ d->source = QUrl::fromLocalFile(filename);
+ d->qml = qml;
+}
+
+/*!
+ Returns the QML string.
+ */
+QString QmlView::qml() const
+{
+ return d->qml;
+}
+
+/*!
+ Returns a pointer to the QmlEngine used for instantiating
+ QML Components.
+ */
+QmlEngine* QmlView::engine()
+{
+ return &d->engine;
+}
+
+/*!
+ This function returns the root of the context hierarchy. Each QML
+ component is instantiated in a QmlContext. QmlContext's are
+ essential for passing data to QML components. In QML, contexts are
+ arranged hierarchically and this hierarchy is managed by the
+ QmlEngine.
+ */
+QmlContext* QmlView::rootContext()
+{
+ return d->engine.rootContext();
+}
+
+/*!
+ Displays the Qt Declarative user interface.
+*/
+void QmlView::execute()
+{
+ if (d->qml.isEmpty()) {
+ d->component = new QmlComponent(&d->engine, d->source, this);
+ } else {
+ d->component = new QmlComponent(&d->engine, this);
+ d->component->setData(d->qml.toUtf8(), d->source);
+ }
+ connect (&d->engine, SIGNAL (quit ()), this, SIGNAL (quit ()));
+
+ if (!d->component->isLoading()) {
+ continueExecute();
+ } else {
+ connect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));
+ }
+}
+
+
+/*!
+ \internal
+ */
+void QmlView::continueExecute()
+{
+ disconnect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));
+
+ if (!d->component) {
+ qWarning() << "Error in loading" << d->source;
+ return;
+ }
+
+ if(d->component->isError()) {
+ QList<QmlError> errorList = d->component->errors();
+ foreach (const QmlError &error, errorList) {
+ qWarning() << error;
+ }
+ emit errors(errorList);
+
+ return;
+ }
+
+ QObject *obj = d->component->create();
+
+ if(d->component->isError()) {
+ QList<QmlError> errorList = d->component->errors();
+ foreach (const QmlError &error, errorList) {
+ qWarning() << error;
+ }
+ emit errors(errorList);
+
+ return;
+ }
+
+ if (obj) {
+ if (QmlGraphicsItem *item = qobject_cast<QmlGraphicsItem *>(obj)) {
+
+ d->scene.addItem(item);
+
+ QPerformanceLog::displayData();
+ QPerformanceLog::clear();
+ d->root = item;
+ connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged()));
+ connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged()));
+ if (d->initialSize.height() <= 0 && d->root->width() > 0)
+ d->initialSize.setWidth(d->root->width());
+ if (d->initialSize.height() <= 0 && d->root->height() > 0)
+ d->initialSize.setHeight(d->root->height());
+ resize(d->initialSize);
+
+ if (d->resizable) {
+ d->root->setWidth(width());
+ d->root->setHeight(height());
+ } else {
+ QSize sz(d->root->width(),d->root->height());
+ emit sceneResized(sz);
+ resize(sz);
+ }
+ updateGeometry();
+ emit initialSize(d->initialSize);
+ } else if (QWidget *wid = qobject_cast<QWidget *>(obj)) {
+ window()->setAttribute(Qt::WA_OpaquePaintEvent, false);
+ window()->setAttribute(Qt::WA_NoSystemBackground, false);
+ if (!layout()) {
+ setLayout(new QVBoxLayout);
+ layout()->setContentsMargins(0, 0, 0, 0);
+ } else if (layout()->count()) {
+ // Hide the QGraphicsView in GV mode.
+ QLayoutItem *item = layout()->itemAt(0);
+ if (item->widget())
+ item->widget()->hide();
+ }
+ layout()->addWidget(wid);
+ emit sceneResized(wid->size());
+ emit initialSize(wid->size());
+ }
+ }
+}
+
+/*! \fn void QmlView::sceneResized(QSize size)
+ This signal is emitted when the view is resized to \a size.
+ */
+
+/*! \fn void QmlView::initialSize(QSize size)
+ This signal is emitted when the initial \a size of the root item is known.
+ */
+
+/*! \fn void QmlView::errors(const QList<QmlError> &errors)
+ This signal is emitted when the qml loaded contains \a errors.
+ */
+
+/*!
+ \internal
+ */
+void QmlView::sizeChanged()
+{
+ // delay, so we catch both width and height changing.
+ d->resizetimer.start(0,this);
+}
+
+/*!
+ If the \l {QTimerEvent} {timer event} \a e is this
+ view's resize timer, sceneResized() is emitted.
+ */
+void QmlView::timerEvent(QTimerEvent* e)
+{
+ if (!e || e->timerId() == d->resizetimer.timerId()) {
+ if (d->root) {
+ QSize sz(d->root->width(),d->root->height());
+ emit sceneResized(sz);
+ //if (!d->resizable)
+ //resize(sz);
+ }
+ d->resizetimer.stop();
+ updateGeometry();
+ }
+}
+
+// modelled on QScrollArea::widgetResizable
+/*!
+ \property QmlView::contentResizable
+ \brief whether the view should resize the canvas contents
+
+ If this property is set to false (the default), the view
+ resizes with the root item in the QML.
+
+ If this property is set to true, the view will
+ automatically resize the root item.
+
+ Regardless of this property, the sizeHint of the view
+ is the initial size of the root item. Note though that
+ since QML may load dynamically, that size may change.
+
+ \sa initialSize()
+*/
+
+void QmlView::setContentResizable(bool on)
+{
+ if (d->resizable != on) {
+ d->resizable = on;
+ if (d->root) {
+ if (on) {
+ d->root->setWidth(width());
+ d->root->setHeight(height());
+ } else {
+ d->root->setWidth(d->initialSize.width());
+ d->root->setHeight(d->initialSize.height());
+ }
+ }
+ }
+}
+
+bool QmlView::contentResizable() const
+{
+ return d->resizable;
+}
+
+
+/*!
+ The size hint is the size of the root item.
+*/
+QSize QmlView::sizeHint() const
+{
+ if (d->root) {
+ if (d->initialSize.width() <= 0)
+ d->initialSize.setWidth(d->root->width());
+ if (d->initialSize.height() <= 0)
+ d->initialSize.setHeight(d->root->height());
+ }
+ return d->initialSize;
+}
+
+/*!
+ Creates a \l{QmlComponent} {component} from the \a qml
+ string, and returns it as an \l {QmlGraphicsItem} {item}. If the
+ \a parent item is provided, it becomes the new item's
+ parent. \a parent should be in this view's item hierarchy.
+ */
+QmlGraphicsItem* QmlView::addItem(const QString &qml, QmlGraphicsItem* parent)
+{
+ if (!d->root)
+ return 0;
+
+ QmlComponent component(&d->engine);
+ component.setData(qml.toUtf8(), QUrl());
+ if(d->component->isError()) {
+ QList<QmlError> errorList = d->component->errors();
+ foreach (const QmlError &error, errorList) {
+ qWarning() << error;
+ }
+ emit errors(errorList);
+
+ return 0;
+ }
+
+ QObject *obj = component.create();
+ if(d->component->isError()) {
+ QList<QmlError> errorList = d->component->errors();
+ foreach (const QmlError &error, errorList) {
+ qWarning() << error;
+ }
+ emit errors(errorList);
+
+ return 0;
+ }
+
+ if (obj){
+ QmlGraphicsItem *item = static_cast<QmlGraphicsItem *>(obj);
+ if (!parent)
+ parent = d->root;
+
+ item->setParentItem(parent);
+ return item;
+ }
+ return 0;
+}
+
+/*!
+ Deletes the view's \l {QmlGraphicsItem} {items} and clears the \l {QmlEngine}
+ {QML engine's} Component cache.
+ */
+void QmlView::reset()
+{
+ clearItems();
+ d->engine.clearComponentCache();
+ d->initialSize = QSize();
+}
+
+/*!
+ Deletes the view's \l {QmlGraphicsItem} {items}.
+ */
+void QmlView::clearItems()
+{
+ if (!d->root)
+ return;
+ delete d->root;
+ d->root = 0;
+}
+
+/*!
+ Returns the view's root \l {QmlGraphicsItem} {item}.
+ */
+QmlGraphicsItem *QmlView::root() const
+{
+ return d->root;
+}
+
+/*!
+ This function handles the \l {QResizeEvent} {resize event}
+ \a e.
+ */
+void QmlView::resizeEvent(QResizeEvent *e)
+{
+ if (d->resizable && d->root) {
+ d->root->setWidth(width());
+ d->root->setHeight(height());
+ }
+ if (d->root) {
+ setSceneRect(QRectF(0, 0, d->root->width(), d->root->height()));
+ } else {
+ setSceneRect(rect());
+ }
+ QGraphicsView::resizeEvent(e);
+}
+
+/*!
+ \reimp
+*/
+void QmlView::paintEvent(QPaintEvent *event)
+{
+ int time = 0;
+ if (frameRateDebug() || QmlViewDebugServer::isDebuggingEnabled())
+ time = d->frameTimer.restart();
+ QGraphicsView::paintEvent(event);
+ if (QmlViewDebugServer::isDebuggingEnabled())
+ qfxViewDebugServer()->addTiming(d->frameTimer.elapsed(), time);
+ if (frameRateDebug())
+ qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qmlview.h b/src/declarative/util/qmlview.h
new file mode 100644
index 0000000..f4f58fd
--- /dev/null
+++ b/src/declarative/util/qmlview.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QFXVIEW_H
+#define QFXVIEW_H
+
+#include <QtCore/qdatetime.h>
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlGraphicsItem;
+class QmlEngine;
+class QmlContext;
+class QmlError;
+
+class QmlViewPrivate;
+class Q_DECLARATIVE_EXPORT QmlView : public QGraphicsView
+{
+ Q_OBJECT
+ Q_PROPERTY(bool contentResizable READ contentResizable WRITE setContentResizable)
+public:
+ explicit QmlView(QWidget *parent = 0);
+
+ virtual ~QmlView();
+
+ void setUrl(const QUrl&);
+ QUrl url() const;
+ void setQml(const QString &qml, const QString &filename=QString());
+ QString qml() const;
+ QmlEngine* engine();
+ QmlContext* rootContext();
+ virtual void execute();
+ virtual void reset();
+
+ virtual QmlGraphicsItem* addItem(const QString &qml, QmlGraphicsItem* parent=0);
+ virtual void clearItems();
+
+ virtual QmlGraphicsItem *root() const;
+
+ void setContentResizable(bool);
+ bool contentResizable() const;
+ QSize sizeHint() const;
+
+Q_SIGNALS:
+ void initialSize(QSize size);
+ void sceneResized(QSize size);
+ void errors(const QList<QmlError> &error);
+ void quit ();
+
+private Q_SLOTS:
+ void continueExecute();
+ void sizeChanged();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *);
+ virtual void paintEvent(QPaintEvent *event);
+ void timerEvent(QTimerEvent*);
+
+private:
+ friend class QmlViewPrivate;
+ QmlViewPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXVIEW_H
diff --git a/src/declarative/util/qmlxmllistmodel.cpp b/src/declarative/util/qmlxmllistmodel.cpp
new file mode 100644
index 0000000..d31fadf
--- /dev/null
+++ b/src/declarative/util/qmlxmllistmodel.cpp
@@ -0,0 +1,728 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qmlxmllistmodel_p.h"
+
+#include <qmlcontext.h>
+#include <qmlengine.h>
+
+#include <QDebug>
+#include <QApplication>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QXmlQuery>
+#include <QXmlResultItems>
+#include <QXmlNodeModelIndex>
+#include <QBuffer>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(Qt,4,6,XmlRole,QmlXmlListModelRole)
+QML_DEFINE_TYPE(Qt,4,6,XmlListModel,QmlXmlListModel)
+
+/*!
+ \qmlclass XmlRole QmlXmlListModelRole
+ \brief The XmlRole element allows you to specify a role for an XmlListModel.
+*/
+
+/*!
+ \qmlproperty string XmlRole::name
+ The name for the role. This name is used to access the model data for this role from Qml.
+
+ \qml
+ XmlRole { name: "title"; query: "title/string()" }
+
+ ...
+
+ Component {
+ id: myDelegate
+ Text { text: title }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty string XmlRole::query
+ The relative XPath query for this role. The query should not start with a '/' (i.e. it must be
+ relative).
+
+ \qml
+ XmlRole { name: "title"; query: "title/string()" }
+ \endqml
+*/
+
+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)
+
+public:
+ QmlXmlListModelRole() {}
+ ~QmlXmlListModelRole() {}
+
+ QString name() const { return m_name; }
+ void setName(const QString &name) { m_name = name; }
+
+ QString query() const { return m_query; }
+ void setQuery(const QString &query)
+ {
+ if (query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << tr("An XmlRole query must not start with '/'");
+ return;
+ }
+ m_query = query;
+ }
+
+ bool isValid() {
+ return !m_name.isEmpty() && !m_query.isEmpty();
+ }
+
+private:
+ QString m_name;
+ QString m_query;
+};
+
+QML_DECLARE_TYPE(QmlXmlListModelRole)
+
+class QmlXmlListModelPrivate;
+struct QmlXmlRoleList : public QmlConcreteList<QmlXmlListModelRole *>
+{
+ QmlXmlRoleList(QmlXmlListModelPrivate *p)
+ : model(p) {}
+ virtual void append(QmlXmlListModelRole *role);
+ virtual void clear();
+ virtual void removeAt(int i);
+ virtual void insert(int i, QmlXmlListModelRole *role);
+
+ QmlXmlListModelPrivate *model;
+};
+
+class QmlXmlQuery : public QThread
+{
+ Q_OBJECT
+public:
+ QmlXmlQuery(QObject *parent=0)
+ : QThread(parent), m_quit(false), m_restart(false), m_abort(false), m_queryId(0) {
+ }
+ ~QmlXmlQuery() {
+ m_mutex.lock();
+ m_quit = true;
+ m_condition.wakeOne();
+ m_mutex.unlock();
+
+ wait();
+ }
+
+ void abort() {
+ QMutexLocker locker(&m_mutex);
+ m_abort = true;
+ }
+
+ int doQuery(QString query, QString namespaces, QByteArray data, QmlXmlRoleList *roleObjects) {
+ QMutexLocker locker(&m_mutex);
+ m_modelData.clear();
+ m_size = 0;
+ m_data = data;
+ m_query = QLatin1String("doc($src)") + query;
+ m_namespaces = namespaces;
+ m_roleObjects = roleObjects;
+ if (!isRunning()) {
+ m_abort = false;
+ start();
+ } else {
+ m_restart = true;
+ m_condition.wakeOne();
+ }
+ m_queryId++;
+ return m_queryId;
+ }
+
+ QList<QList<QVariant> > modelData() {
+ QMutexLocker locker(&m_mutex);
+ return m_modelData;
+ }
+
+Q_SIGNALS:
+ void queryCompleted(int queryId, int size);
+
+protected:
+ void run() {
+ while (!m_quit) {
+ m_mutex.lock();
+ int queryId = m_queryId;
+ doQueryJob();
+ if (m_size > 0)
+ doSubQueryJob();
+ m_data.clear(); // no longer needed
+ m_mutex.unlock();
+
+ m_mutex.lock();
+ if (!m_abort && m_size > 0)
+ emit queryCompleted(queryId, m_size);
+ if (!m_restart)
+ m_condition.wait(&m_mutex);
+ m_abort = false;
+ m_restart = false;
+ m_mutex.unlock();
+ }
+ }
+
+private:
+ void doQueryJob();
+ void doSubQueryJob();
+
+private:
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+ bool m_quit;
+ bool m_restart;
+ bool m_abort;
+ QByteArray m_data;
+ QString m_query;
+ QString m_namespaces;
+ QString m_prefix;
+ int m_size;
+ int m_queryId;
+ const QmlXmlRoleList *m_roleObjects;
+ QList<QList<QVariant> > m_modelData;
+};
+
+void QmlXmlQuery::doQueryJob()
+{
+ QString r;
+ QXmlQuery query;
+ QBuffer buffer(&m_data);
+ buffer.open(QIODevice::ReadOnly);
+ query.bindVariable(QLatin1String("src"), &buffer);
+ query.setQuery(m_namespaces + m_query);
+ query.evaluateTo(&r);
+
+ //qDebug() << r;
+
+ //always need a single root element
+ QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>";
+ QBuffer b(&xml);
+ b.open(QIODevice::ReadOnly);
+ //qDebug() << xml;
+
+ QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + m_namespaces;
+ QString prefix = QLatin1String("doc($inputDocument)/dummy:items") +
+ m_query.mid(m_query.lastIndexOf(QLatin1Char('/')));
+
+ //figure out how many items we are dealing with
+ int count = -1;
+ {
+ QXmlResultItems result;
+ QXmlQuery countquery;
+ countquery.bindVariable(QLatin1String("inputDocument"), &b);
+ countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1Char(')'));
+ countquery.evaluateTo(&result);
+ QXmlItem item(result.next());
+ if (item.isAtomicValue())
+ count = item.toAtomicValue().toInt();
+ }
+ //qDebug() << count;
+
+ m_prefix = namespaces + prefix + QLatin1Char('/');
+ m_data = xml;
+ if (count > 0)
+ m_size = count;
+}
+
+void QmlXmlQuery::doSubQueryJob()
+{
+ m_modelData.clear();
+
+ QBuffer b(&m_data);
+ b.open(QIODevice::ReadOnly);
+
+ QXmlQuery subquery;
+ subquery.bindVariable(QLatin1String("inputDocument"), &b);
+
+ //### 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);
+ if (!role->isValid()) {
+ QList<QVariant> resultList;
+ for (int j = 0; j < m_size; ++j)
+ resultList << QVariant();
+ m_modelData << resultList;
+ 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());
+ QList<QVariant> resultList;
+ while (!item.isNull()) {
+ resultList << item.toAtomicValue(); //### we used to trim strings
+ item = output3.next();
+ }
+ //### should warn here if things have gone wrong.
+ while (resultList.count() < m_size)
+ resultList << QVariant();
+ m_modelData << resultList;
+ b.seek(0);
+ }
+
+ //this method is much slower, but works better for incremental loading
+ /*for (int j = 0; j < m_size; ++j) {
+ QList<QVariant> resultList;
+ for (int i = 0; i < m_roleObjects->size(); ++i) {
+ QmlXmlListModelRole *role = m_roleObjects->at(i);
+ subquery.setQuery(m_prefix.arg(j+1) + role->query());
+ if (role->isStringList()) {
+ QStringList data;
+ subquery.evaluateTo(&data);
+ resultList << QVariant(data);
+ //qDebug() << data;
+ } else {
+ QString s;
+ subquery.evaluateTo(&s);
+ if (role->isCData()) {
+ //un-escape
+ s.replace(QLatin1String("&lt;"), QLatin1String("<"));
+ s.replace(QLatin1String("&gt;"), QLatin1String(">"));
+ s.replace(QLatin1String("&amp;"), QLatin1String("&"));
+ }
+ resultList << s.trimmed();
+ //qDebug() << s;
+ }
+ b.seek(0);
+ }
+ m_modelData << resultList;
+ }*/
+}
+
+class QmlXmlListModelPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QmlXmlListModel)
+public:
+ QmlXmlListModelPrivate()
+ : isComponentComplete(true), size(-1), highestRole(Qt::UserRole)
+ , reply(0), status(QmlXmlListModel::Null), progress(0.0)
+ , queryId(-1), roleObjects(this) {}
+
+ bool isComponentComplete;
+ QUrl src;
+ QString xml;
+ QString query;
+ QString namespaces;
+ int size;
+ QList<int> roles;
+ QStringList roleNames;
+ int highestRole;
+ QNetworkReply *reply;
+ QmlXmlListModel::Status status;
+ qreal progress;
+ QmlXmlQuery qmlXmlQuery;
+ int queryId;
+ QmlXmlRoleList roleObjects;
+ QList<QList<QVariant> > data;
+};
+
+
+void QmlXmlRoleList::append(QmlXmlListModelRole *role)
+{
+ insert(size(), role);
+}
+
+//### clear, removeAt, and insert need to invalidate any cached data (in data table) as well
+// (and the model should emit the appropriate signals)
+void QmlXmlRoleList::clear()
+{
+ model->roles.clear();
+ model->roleNames.clear();
+ QmlConcreteList<QmlXmlListModelRole *>::clear();
+}
+
+void QmlXmlRoleList::removeAt(int i)
+{
+ model->roles.removeAt(i);
+ model->roleNames.removeAt(i);
+ QmlConcreteList<QmlXmlListModelRole *>::removeAt(i);
+}
+
+void QmlXmlRoleList::insert(int i, QmlXmlListModelRole *role)
+{
+ QmlConcreteList<QmlXmlListModelRole *>::insert(i, role);
+ if (model->roleNames.contains(role->name())) {
+ qmlInfo(role) << QObject::tr("\"%1\" duplicates a previous role name and will be disabled.").arg(role->name());
+ return;
+ }
+ model->roles.insert(i, model->highestRole);
+ model->roleNames.insert(i, role->name());
+ ++model->highestRole;
+}
+
+/*!
+ \class QmlXmlListModel
+ \internal
+*/
+
+/*!
+ \qmlclass XmlListModel QmlXmlListModel
+ \brief The XmlListModel element allows you 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).
+
+ The following 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: "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.
+*/
+
+QmlXmlListModel::QmlXmlListModel(QObject *parent)
+ : QListModelInterface(*(new QmlXmlListModelPrivate), parent)
+{
+ Q_D(QmlXmlListModel);
+ connect(&d->qmlXmlQuery, SIGNAL(queryCompleted(int,int)),
+ this, SLOT(queryCompleted(int,int)));
+}
+
+QmlXmlListModel::~QmlXmlListModel()
+{
+}
+
+/*!
+ \qmlproperty list<XmlRole> XmlListModel::roles
+
+ The roles to make available for this model.
+*/
+QmlList<QmlXmlListModelRole *> *QmlXmlListModel::roleObjects()
+{
+ Q_D(QmlXmlListModel);
+ return &d->roleObjects;
+}
+
+QHash<int,QVariant> QmlXmlListModel::data(int index, const QList<int> &roles) const
+{
+ Q_D(const QmlXmlListModel);
+ QHash<int, QVariant> rv;
+ for (int i = 0; i < roles.size(); ++i) {
+ int role = roles.at(i);
+ int roleIndex = d->roles.indexOf(role);
+ rv.insert(role, roleIndex == -1 ? QVariant() : d->data.at(roleIndex).at(index));
+ }
+ return rv;
+}
+
+QVariant QmlXmlListModel::data(int index, int role) const
+{
+ Q_D(const QmlXmlListModel);
+ int roleIndex = d->roles.indexOf(role);
+ return (roleIndex == -1) ? QVariant() : d->data.at(roleIndex).at(index);
+}
+
+/*!
+ \qmlproperty int XmlListModel::count
+ The number of data entries in the model.
+*/
+int QmlXmlListModel::count() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->size;
+}
+
+QList<int> QmlXmlListModel::roles() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->roles;
+}
+
+QString QmlXmlListModel::toString(int role) const
+{
+ Q_D(const QmlXmlListModel);
+ int index = d->roles.indexOf(role);
+ if (index == -1)
+ return QString();
+ return d->roleNames.at(index);
+}
+
+/*!
+ \qmlproperty url XmlListModel::source
+ The location of the XML data source.
+
+ If both source and xml are set, xml will be used.
+*/
+QUrl QmlXmlListModel::source() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->src;
+}
+
+void QmlXmlListModel::setSource(const QUrl &src)
+{
+ Q_D(QmlXmlListModel);
+ if (d->src != src) {
+ d->src = src;
+ reload();
+ }
+}
+
+/*!
+ \qmlproperty string XmlListModel::xml
+ This property holds XML text set directly.
+
+ The text is assumed to be UTF-8 encoded.
+
+ If both source and xml are set, xml will be used.
+*/
+QString QmlXmlListModel::xml() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->xml;
+}
+
+void QmlXmlListModel::setXml(const QString &xml)
+{
+ Q_D(QmlXmlListModel);
+ d->xml = xml;
+ reload();
+}
+
+/*!
+ \qmlproperty url XmlListModel::query
+ An absolute XPath query representing the base query for the model items. The query should start with
+ a '/' or '//'.
+*/
+QString QmlXmlListModel::query() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->query;
+}
+
+void QmlXmlListModel::setQuery(const QString &query)
+{
+ Q_D(QmlXmlListModel);
+ if (!query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << tr("An XmlListModel query must start with '/' or \"//\"");
+ return;
+ }
+
+ if (d->query != query) {
+ d->query = query;
+ reload();
+ }
+}
+
+/*!
+ \qmlproperty string XmlListModel::namespaceDeclarations
+ A set of declarations for the namespaces used in the query.
+*/
+QString QmlXmlListModel::namespaceDeclarations() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->namespaces;
+}
+
+void QmlXmlListModel::setNamespaceDeclarations(const QString &declarations)
+{
+ Q_D(QmlXmlListModel);
+ if (d->namespaces != declarations) {
+ d->namespaces = declarations;
+ reload();
+ }
+}
+
+/*!
+ \qmlproperty enum XmlListModel::status
+
+ This property holds the status of data source loading. It can be one of:
+ \list
+ \o Null - no data source has been set
+ \o Ready - nthe data source has been loaded
+ \o Loading - the data source is currently being loaded
+ \o Error - an error occurred while loading the data source
+ \endlist
+
+ \sa progress
+
+*/
+QmlXmlListModel::Status QmlXmlListModel::status() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->status;
+}
+
+/*!
+ \qmlproperty real XmlListModel::progress
+
+ This property holds the progress of data source loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+qreal QmlXmlListModel::progress() const
+{
+ Q_D(const QmlXmlListModel);
+ return d->progress;
+}
+
+void QmlXmlListModel::classBegin()
+{
+ Q_D(QmlXmlListModel);
+ d->isComponentComplete = false;
+}
+
+void QmlXmlListModel::componentComplete()
+{
+ Q_D(QmlXmlListModel);
+ d->isComponentComplete = true;
+ reload();
+}
+
+/*!
+ \qmlmethod XmlListModel::reload()
+
+ Reloads the model. All the existing model data will be removed, and the model
+ will be rebuilt from scratch.
+*/
+void QmlXmlListModel::reload()
+{
+ Q_D(QmlXmlListModel);
+
+ if (!d->isComponentComplete)
+ return;
+
+ 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->src.isEmpty() && d->xml.isEmpty())
+ return;
+
+ if (d->reply) {
+ d->reply->abort();
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+
+ if (!d->xml.isEmpty()) {
+ 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);
+ emit statusChanged(d->status);
+ return;
+ }
+
+ d->progress = 0.0;
+ d->status = Loading;
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+
+ QNetworkRequest req(d->src);
+ d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished()));
+ QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+}
+
+void QmlXmlListModel::requestFinished()
+{
+ Q_D(QmlXmlListModel);
+ if (d->reply->error() != QNetworkReply::NoError) {
+ disconnect(d->reply, 0, this, 0);
+ d->reply->deleteLater();
+ d->reply = 0;
+ d->status = Error;
+ } else {
+ d->status = Ready;
+ QByteArray data = d->reply->readAll();
+ d->queryId = d->qmlXmlQuery.doQuery(d->query, d->namespaces, data, &d->roleObjects);
+ disconnect(d->reply, 0, this, 0);
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ emit statusChanged(d->status);
+}
+
+void QmlXmlListModel::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QmlXmlListModel);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+void QmlXmlListModel::queryCompleted(int id, int size)
+{
+ Q_D(QmlXmlListModel);
+ if (id != d->queryId)
+ return;
+ d->size = size;
+ if (size > 0) {
+ d->data = d->qmlXmlQuery.modelData();
+ emit itemsInserted(0, d->size);
+ emit countChanged();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include <qmlxmllistmodel.moc>
diff --git a/src/declarative/util/qmlxmllistmodel_p.h b/src/declarative/util/qmlxmllistmodel_p.h
new file mode 100644
index 0000000..e4b8cab
--- /dev/null
+++ b/src/declarative/util/qmlxmllistmodel_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QMLXMLLISTMODEL_H
+#define QMLXMLLISTMODEL_H
+
+#include <qml.h>
+#include <qmlinfo.h>
+
+#include "../3rdparty/qlistmodelinterface_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QmlContext;
+
+class QmlXmlListModelRole;
+
+class QmlXmlListModelPrivate;
+class Q_DECLARATIVE_EXPORT QmlXmlListModel : public QListModelInterface, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QmlParserStatus)
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource)
+ Q_PROPERTY(QString xml READ xml WRITE setXml)
+ Q_PROPERTY(QString query READ query WRITE setQuery)
+ Q_PROPERTY(QString namespaceDeclarations READ namespaceDeclarations WRITE setNamespaceDeclarations)
+ Q_PROPERTY(QmlList<QmlXmlListModelRole *> *roles READ roleObjects)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_CLASSINFO("DefaultProperty", "roles")
+
+public:
+ QmlXmlListModel(QObject *parent = 0);
+ ~QmlXmlListModel();
+
+ virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const;
+ virtual QVariant data(int index, int role) const;
+ virtual int count() const;
+ virtual QList<int> roles() const;
+ virtual QString toString(int role) const;
+
+ QmlList<QmlXmlListModelRole *> *roleObjects();
+
+ QUrl source() const;
+ void setSource(const QUrl&);
+
+ QString xml() const;
+ void setXml(const QString&);
+
+ QString query() const;
+ void setQuery(const QString&);
+
+ QString namespaceDeclarations() const;
+ void setNamespaceDeclarations(const QString&);
+
+ enum Status { Null, Ready, Loading, Error };
+ Status status() const;
+ qreal progress() const;
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void statusChanged(Status);
+ void progressChanged(qreal progress);
+ void countChanged();
+
+public Q_SLOTS:
+ // ### need to use/expose Expiry to guess when to call this?
+ // ### property to auto-call this on reasonable Expiry?
+ // ### LastModified/Age also useful to guess.
+ // ### Probably also applies to other network-requesting types.
+ void reload();
+
+private Q_SLOTS:
+ void requestFinished();
+ void requestProgress(qint64,qint64);
+ void queryCompleted(int,int);
+
+private:
+ Q_DECLARE_PRIVATE(QmlXmlListModel)
+ Q_DISABLE_COPY(QmlXmlListModel)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QmlXmlListModel)
+
+QT_END_HEADER
+
+#endif // QMLXMLLISTMODEL_H
diff --git a/src/declarative/util/qnumberformat.cpp b/src/declarative/util/qnumberformat.cpp
new file mode 100644
index 0000000..fd44db1
--- /dev/null
+++ b/src/declarative/util/qnumberformat.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qnumberformat_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_NOCREATE_TYPE(QNumberFormat)
+
+QNumberFormat::QNumberFormat(QObject *parent) : QObject(parent), _number(0), _type(Decimal),
+ _groupingSize(0)
+{
+ _locale = QLocale::system();
+ _groupingSeparator = _locale.groupSeparator();
+ _decimalSeparator = _locale.decimalPoint();
+ _currencySymbol = QLatin1Char('$');
+}
+
+QNumberFormat::~QNumberFormat()
+{
+
+}
+
+void QNumberFormat::updateText()
+{
+ QTime t;
+ t.start();
+ static int totalTime;
+
+ handleFormat();
+
+ totalTime += t.elapsed();
+ emit textChanged();
+}
+
+void QNumberFormat::handleFormat()
+{
+ // ### is extremely messy
+ if (_format.isEmpty()) {
+ _text = QString::number(_number, 'f', -1);
+ return;
+ }
+
+ QString inputString;
+
+ // ### possible to use the following parsed data in the future
+
+ int remainingLength = _format.size();
+ int currentIndex = _format.size()-1;
+
+ int maxDigits = 0;
+ int minDigits = 0;
+ int decimalLength = 0;
+
+ while (remainingLength > 0) {
+ switch(_format.at(currentIndex).unicode()) {
+ case ',':
+ if (decimalLength && !_groupingSize)
+ setGroupingSize(maxDigits - decimalLength);
+ else if (!_groupingSize)
+ setGroupingSize(maxDigits);
+ break;
+ case '.':
+ if (!decimalLength)
+ decimalLength = maxDigits;
+ break;
+ case '0':
+ minDigits++;
+ case '#':
+ maxDigits++;
+ break;
+ default:
+ break;
+ }
+ currentIndex--;
+ remainingLength--;
+ }
+
+ // round given the decimal length/precision
+ inputString = QString::number(_number, 'f', decimalLength);
+
+ QStringList parts = inputString.split(QLatin1Char('.'));
+ QStringList formatParts = _format.split(QLatin1Char('.'));
+
+ if (formatParts.size() > 2 || parts.size() > 2 )
+ return;
+
+ QString formatInt = formatParts.at(0);
+
+ QString formatDec;
+ if (formatParts.size() == 2)
+ formatDec = formatParts.at(1);
+
+ QString integer = parts.at(0);
+
+ QString decimal;
+ if (parts.size() == 2)
+ decimal = parts.at(1);
+
+ QString outputDecimal = formatDecimal(formatDec, decimal);
+ QString outputInteger = formatInteger(formatInt, integer);
+
+ // insert separators
+ if (_groupingSize) {
+ unsigned int count = 0;
+ for (int i = outputInteger.size()-1; i > 0; i--) {
+ if (outputInteger.at(i).digitValue() >= 0) {
+ if (count == _groupingSize - 1) {
+ count = 0;
+ outputInteger.insert(i, _groupingSeparator);
+ }
+ else
+ count++;
+ }
+ }
+ }
+ if (!outputDecimal.isEmpty())
+ _text = outputInteger + _decimalSeparator + outputDecimal;
+ else
+ _text = outputInteger;
+}
+
+QString QNumberFormat::formatInteger(const QString &formatInt, const QString &integer)
+{
+ if (formatInt.isEmpty() || integer.isEmpty())
+ return QString();
+
+ QString outputInteger;
+ int formatIndex = formatInt.size()-1;
+
+ //easier for carry?
+ for (int index= integer.size()-1; index >= 0; index--) {
+ if (formatIndex < 0) {
+ outputInteger.push_front(integer.at(index));
+ }
+ else {
+ switch(formatInt.at(formatIndex).unicode()) {
+ case '0':
+ if (index > integer.size()-1) {
+ outputInteger.push_front(QLatin1Char('0'));
+ break;
+ }
+ case '#':
+ outputInteger.push_front(integer.at(index));
+ break;
+ case ',':
+ index++;
+ break;
+ default:
+ outputInteger.push_front(formatInt.at(formatIndex));
+ index++;
+ break;
+ }
+ formatIndex--;
+ }
+ }
+ while (formatIndex >= 0) {
+ if (formatInt.at(formatIndex).unicode() != '#' && formatInt.at(formatIndex).unicode() != ',')
+ outputInteger.push_front(formatInt.at(formatIndex));
+ formatIndex--;
+ }
+ return outputInteger;
+}
+
+QString QNumberFormat::formatDecimal(const QString &formatDec, const QString &decimal)
+{
+ QString outputDecimal;
+
+ // up to max 6 decimal places
+ for (int index=formatDec.size()-1; index >= 0; index--) {
+ switch(formatDec.at(index).unicode()) {
+ case '0':
+ outputDecimal.push_front(decimal.at(index));
+ break;
+ case '#':
+ if (decimal.at(index) != QLatin1Char('0') || outputDecimal.size() > 0)
+ outputDecimal.push_front(decimal.at(index));
+ break;
+ default:
+ outputDecimal.push_front(formatDec.at(index));
+ break;
+ }
+ }
+ return outputDecimal;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qnumberformat_p.h b/src/declarative/util/qnumberformat_p.h
new file mode 100644
index 0000000..c73ef8a
--- /dev/null
+++ b/src/declarative/util/qnumberformat_p.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 NUMBERFORMAT_H
+#define NUMBERFORMAT_H
+
+#include <qml.h>
+
+#include <QtCore/QLocale>
+#include <QtCore/QTime>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+// TODO
+// be able to set Locale, instead of default system for dynamic formatting
+// add currency support
+// add additional syntax, extend to format scientific, percentiles, significant digits etc
+
+
+class QNumberFormat : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(NumberType)
+public:
+ QNumberFormat(QObject *parent=0);
+ ~QNumberFormat();
+
+ enum NumberType {
+ Percent,
+ Scientific,
+ Currency,
+ Decimal
+ };
+
+ //external property, only visible
+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
+
+ //mutatable properties to modify the output (text)
+ Q_PROPERTY(qreal number READ number WRITE setNumber)
+ Q_PROPERTY(QString format READ format WRITE setFormat)
+ Q_PROPERTY(QLocale locale READ locale WRITE setLocale)
+
+ //Format specific settings
+ Q_PROPERTY(unsigned short groupingSeparator READ groupingSeparator WRITE setGroupingSeparator)
+ Q_PROPERTY(unsigned short decimalSeperator READ decimalSeparator WRITE setDecimalSeparator)
+ Q_PROPERTY(unsigned int groupingSize READ groupingSize WRITE setGroupingSize)
+ Q_PROPERTY(unsigned short currencySymbol READ currencySymbol WRITE setCurrencySymbol)
+
+
+ QString text() const { return _text; }
+
+ qreal number() const { return _number; }
+ void setNumber(qreal n) {
+ if (_number == n)
+ return;
+ _number = n;
+ updateText();
+ }
+
+ QString format() const { return _format; }
+ void setFormat(const QString &format) {
+ if (format.isEmpty())
+ _format = QString::null;
+ else if (_format == format)
+ return;
+
+ _format = format;
+ updateText();
+ }
+
+ QLocale locale() const { return _locale; }
+ void setLocale(const QLocale &locale) { _locale = locale; updateText(); }
+
+ //Do we deal with unicode standard? or create our own
+ // ### since this is the backend for the number conversions, we will use the unicode
+ // the front-end will handle the QChar/QString -> short int
+
+ unsigned short groupingSeparator() { return _groupingSeparator.unicode(); }
+ void setGroupingSeparator(unsigned short unicodeSymbol)
+ {
+ _groupingSeparator = QChar(unicodeSymbol);
+ }
+
+ unsigned short decimalSeparator() { return _decimalSeparator.unicode(); }
+ void setDecimalSeparator(unsigned short unicodeSymbol)
+ {
+ _decimalSeparator = QChar(unicodeSymbol);
+ }
+
+ unsigned short currencySymbol() { return _currencySymbol.unicode(); }
+ void setCurrencySymbol(unsigned short unicodeSymbol)
+ {
+ _currencySymbol = QChar(unicodeSymbol);
+ }
+
+ unsigned int groupingSize() { return _groupingSize; }
+ void setGroupingSize(unsigned int size)
+ {
+ _groupingSize = size;
+ }
+
+Q_SIGNALS:
+ void textChanged();
+
+private:
+ void updateText();
+ void handleFormat();
+ QString formatInteger(const QString &formatInt, const QString &integer);
+ QString formatDecimal(const QString &formatDec, const QString &decimal);
+
+ qreal _number;
+ NumberType _type;
+ QChar _groupingSeparator;
+ QChar _decimalSeparator;
+ QChar _currencySymbol;
+ unsigned int _groupingSize;
+
+ QLocale _locale;
+ QString _format;
+
+ // only hooked member at the moment
+ QString _text;
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QNumberFormat)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/util/qperformancelog.cpp b/src/declarative/util/qperformancelog.cpp
new file mode 100644
index 0000000..2f91dfb
--- /dev/null
+++ b/src/declarative/util/qperformancelog.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qperformancelog_p_p.h"
+
+#include <QHash>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+
+struct QPerformanceLogData
+{
+ struct Log
+ {
+ Log()
+ : logDescription(0), maxId(-1) {}
+
+ QHash<int, const char *> descriptions;
+ const char *logDescription;
+ int maxId;
+ };
+
+ typedef QHash<QPerformanceLog::LogData *, Log> Logs;
+ Logs logs;
+};
+Q_GLOBAL_STATIC(QPerformanceLogData, performanceLogData);
+
+QPerformanceLog::LogData::LogData(const char *desc)
+: sumTime(0), data(0)
+{
+ QPerformanceLogData *logData = performanceLogData();
+
+ QPerformanceLogData::Log log;
+ log.logDescription = desc;
+ logData->logs.insert(this, log);
+
+ timer.start();
+}
+
+QPerformanceLog::LogMetric::LogMetric(LogData *l, int id, const char *desc)
+{
+ if (id < 0)
+ qFatal("QPerformanceLog: Invalid log id %d ('%s')", id, desc);
+
+ QPerformanceLogData *logData = performanceLogData();
+
+ QPerformanceLogData::Logs::Iterator logIter = logData->logs.find(l);
+ if (logIter == logData->logs.end())
+ qFatal("QPerformanceLog: Unable to locate log for metric '%s'", desc);
+ QPerformanceLogData::Log &log = *logIter;
+ if (log.descriptions.contains(id))
+ qFatal("QPerformanceLog: Duplicate log metric %d ('%s')", id, desc);
+ log.descriptions.insert(id, desc);
+
+ if (log.maxId < id) {
+ log.maxId = id;
+ if (l->data) delete [] l->data;
+ l->data = new unsigned int[2 * (log.maxId + 1)];
+ ::memset(l->data, 0, 2 * (log.maxId + 1) * sizeof(unsigned int));
+ }
+}
+
+static void QPerformanceLog_clear(QPerformanceLog::LogData *l, const QPerformanceLogData::Log *pl)
+{
+ ::memset(l->data, 0, 2 * (pl->maxId + 1) * sizeof(unsigned int));
+}
+
+static void QPerformanceLog_displayData(const QPerformanceLog::LogData *l, const QPerformanceLogData::Log *pl)
+{
+ qWarning() << pl->logDescription << "performance data";
+ unsigned int total = 0;
+ for (QHash<int, const char *>::ConstIterator iter = pl->descriptions.begin();
+ iter != pl->descriptions.end();
+ ++iter) {
+
+ int id = iter.key();
+ unsigned int ms = l->data[id * 2];
+ total += ms;
+ unsigned int inst = l->data[id * 2 + 1];
+ float pi = float(ms) / float(inst);
+ qWarning().nospace() << " " << *iter << ": " << ms << " ms over "
+ << inst << " instances (" << pi << " ms/instance)";
+ }
+ qWarning().nospace() << " TOTAL: " << total;
+}
+
+void QPerformanceLog::displayData()
+{
+ QPerformanceLogData *logData = performanceLogData();
+
+ for (QPerformanceLogData::Logs::ConstIterator iter = logData->logs.begin();
+ iter != logData->logs.end();
+ ++iter) {
+ QPerformanceLog_displayData(iter.key(), &(*iter));
+ }
+}
+
+void QPerformanceLog::clear()
+{
+ QPerformanceLogData *logData = performanceLogData();
+
+ for (QPerformanceLogData::Logs::ConstIterator iter = logData->logs.begin();
+ iter != logData->logs.end();
+ ++iter) {
+ QPerformanceLog_clear(iter.key(), &(*iter));
+ }
+}
+
+void QPerformanceLog::displayData(LogData *l)
+{
+ QPerformanceLogData *logData = performanceLogData();
+ QPerformanceLogData::Logs::ConstIterator iter = logData->logs.find(l);
+ if (iter == logData->logs.end())
+ qFatal("QPerformanceLog: Internal corruption - unable to locate log");
+
+ QPerformanceLog_displayData(iter.key(), &(*iter));
+}
+
+void QPerformanceLog::clear(LogData *l)
+{
+ QPerformanceLogData *logData = performanceLogData();
+ QPerformanceLogData::Logs::ConstIterator iter = logData->logs.find(l);
+ if (iter == logData->logs.end())
+ qFatal("QPerformanceLog: Internal corruption - unable to locate log");
+
+ QPerformanceLog_clear(iter.key(), &(*iter));
+}
+
+#else // Q_ENABLE_PERFORMANCE_LOG
+
+void QPerformanceLog::displayData()
+{
+}
+
+void QPerformanceLog::clear()
+{
+}
+
+#endif // Q_ENABLE_PERFORMANCE_LOG
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qperformancelog_p_p.h b/src/declarative/util/qperformancelog_p_p.h
new file mode 100644
index 0000000..e7a3b5e
--- /dev/null
+++ b/src/declarative/util/qperformancelog_p_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 QPERFORMANCELOG_H
+#define QPERFORMANCELOG_H
+
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QPerformanceLog
+{
+ Q_DECLARATIVE_EXPORT void displayData();
+ Q_DECLARATIVE_EXPORT void clear();
+
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ struct LogData {
+ LogData(const char *);
+ QTime timer;
+ int sumTime;
+ unsigned int *data;
+ };
+
+ struct LogMetric {
+ LogMetric(LogData *, int, const char *);
+ };
+
+ // Internal
+ void displayData(LogData *);
+ void clear(LogData *);
+#endif
+}
+
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+
+#define Q_DECLARE_PERFORMANCE_METRIC(name) \
+ enum { name = ValueChoice<0, ValueTracker<0, __LINE__>::value, __LINE__>::value }; \
+ template<int L> \
+ struct ValueTracker<name, L> \
+ { \
+ enum { value = name }; \
+ }; \
+ extern QPerformanceLog::LogMetric metric ## name;
+
+#define Q_DECLARE_PERFORMANCE_LOG(name) \
+ namespace name { \
+ extern QPerformanceLog::LogData log; \
+ inline void displayData() { QPerformanceLog::displayData(&log); } \
+ inline void clear() { QPerformanceLog::clear(&log); } \
+ } \
+ template<int N> \
+ class name ## Timer { \
+ public: \
+ name ## Timer() { \
+ lastSum = name::log.sumTime + name::log.timer.restart(); \
+ name::log.sumTime = 0; \
+ } \
+ ~ name ## Timer() { \
+ name::log.data[2 * N] += name::log.sumTime + name::log.timer.restart(); \
+ ++name::log.data[2 * N + 1]; \
+ name::log.sumTime = lastSum; \
+ } \
+ private: \
+ int lastSum; \
+ }; \
+ namespace name { \
+ template<int N, int L> \
+ struct ValueTracker \
+ { \
+ enum { value = -1 }; \
+ }; \
+ template<int DefNextValue, int NextValue, int L> \
+ struct ValueChoice \
+ { \
+ enum { value = ValueChoice<DefNextValue + 1, ValueTracker<DefNextValue + 1, L>::value, L>::value }; \
+ }; \
+ template<int DefNextValue, int L> \
+ struct ValueChoice<DefNextValue, -1, L> \
+ { \
+ enum { value = DefNextValue }; \
+ }; \
+ } \
+ namespace name
+
+#define Q_DEFINE_PERFORMANCE_LOG(name, desc) \
+ QPerformanceLog::LogData name::log(desc); \
+ namespace name
+
+#define Q_DEFINE_PERFORMANCE_METRIC(name, desc) \
+ QPerformanceLog::LogMetric metrix ## name(&log, name, desc);
+
+#else // Q_ENABLE_PERFORMANCE_LOG
+
+#define Q_DECLARE_PERFORMANCE_METRIC(name)
+#define Q_DECLARE_PERFORMANCE_LOG(name) namespace name
+#define Q_DEFINE_PERFORMANCE_LOG(name, desc) namespace name
+#define Q_DEFINE_PERFORMANCE_METRIC(name, desc)
+
+#endif // Q_ENABLE_PERFORMANCE_LOG
+
+QT_END_NAMESPACE
+
+#endif // QPERFORMANCELOG_H
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
new file mode 100644
index 0000000..b6a5c90
--- /dev/null
+++ b/src/declarative/util/util.pri
@@ -0,0 +1,72 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qmlview.cpp \
+ $$PWD/qfxperf.cpp \
+ $$PWD/qperformancelog.cpp \
+ $$PWD/qmlconnection.cpp \
+ $$PWD/qmlpackage.cpp \
+ $$PWD/qmlanimation.cpp \
+ $$PWD/qmlsystempalette.cpp \
+ $$PWD/qmlspringfollow.cpp \
+ $$PWD/qmleasefollow.cpp \
+ $$PWD/qmlstate.cpp\
+ $$PWD/qmltransitionmanager.cpp \
+ $$PWD/qmlstateoperations.cpp \
+ $$PWD/qmlpropertychanges.cpp \
+ $$PWD/qmlstategroup.cpp \
+ $$PWD/qmltransition.cpp \
+ $$PWD/qmllistmodel.cpp\
+ $$PWD/qmllistaccessor.cpp \
+ $$PWD/qmlopenmetaobject.cpp \
+ $$PWD/qmltimeline.cpp \
+ $$PWD/qmltimer.cpp \
+ $$PWD/qmlbind.cpp \
+ $$PWD/qmlpropertymap.cpp \
+ $$PWD/qmlpixmapcache.cpp \
+ $$PWD/qnumberformat.cpp \
+ $$PWD/qmlnumberformatter.cpp \
+ $$PWD/qmldatetimeformatter.cpp \
+ $$PWD/qmlbehavior.cpp \
+ $$PWD/qmlfontloader.cpp \
+ $$PWD/qmlstyledtext.cpp
+
+HEADERS += \
+ $$PWD/qmlview.h \
+ $$PWD/qfxperf_p_p.h \
+ $$PWD/qperformancelog_p_p.h \
+ $$PWD/qmlconnection_p.h \
+ $$PWD/qmlpackage_p.h \
+ $$PWD/qmlanimation_p.h \
+ $$PWD/qmlanimation_p_p.h \
+ $$PWD/qmlsystempalette_p.h \
+ $$PWD/qmlspringfollow_p.h \
+ $$PWD/qmleasefollow_p.h \
+ $$PWD/qmlstate_p.h\
+ $$PWD/qmlstateoperations_p.h \
+ $$PWD/qmlpropertychanges_p.h \
+ $$PWD/qmlstate_p_p.h\
+ $$PWD/qmltransitionmanager_p_p.h \
+ $$PWD/qmlstategroup_p.h \
+ $$PWD/qmltransition_p.h \
+ $$PWD/qmllistmodel_p.h\
+ $$PWD/qmllistaccessor_p.h \
+ $$PWD/qmlopenmetaobject_p.h \
+ $$PWD/qmlnullablevalue_p_p.h \
+ $$PWD/qmltimeline_p_p.h \
+ $$PWD/qmltimer_p.h \
+ $$PWD/qmlbind_p.h \
+ $$PWD/qmlpropertymap.h \
+ $$PWD/qmlpixmapcache_p.h \
+ $$PWD/qnumberformat_p.h \
+ $$PWD/qmlnumberformatter_p.h \
+ $$PWD/qmldatetimeformatter_p.h \
+ $$PWD/qmlbehavior_p.h \
+ $$PWD/qmlfontloader_p.h \
+ $$PWD/qmlstyledtext_p.h
+
+contains(QT_CONFIG, xmlpatterns) {
+ QT+=xmlpatterns
+ SOURCES += $$PWD/qmlxmllistmodel.cpp
+ HEADERS += $$PWD/qmlxmllistmodel_p.h
+}