aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2011-11-23 15:14:07 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-02 14:18:20 +0100
commit6c8378eaf1edbbefe6aaa3672b0127816a004fd7 (patch)
tree8ee08fb447e052f7a7a685fbeaaa04f04ea60126 /src/quick/util
parente01219b77b1e889e70437635905d7ff820568e23 (diff)
Say hello to QtQuick module
This change moves the QtQuick 2 types and C++ API (including SceneGraph) to a new module (AKA library), QtQuick. 99% of this change is moving files from src/declarative to src/quick, and from tests/auto/declarative to tests/auto/qtquick2. The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to a plugin, src/imports/qtquick2, just like it's done for QtQuick 1. All tools, examples, and tests that use QtQuick C++ API have gotten "QT += quick" or "QT += quick-private" added to their .pro file. A few additional internal QtDeclarative classes had to be exported (via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the QtQuick 2 implementation. The old header locations (e.g. QtDeclarative/qquickitem.h) will still be supported for some time, but will produce compile-time warnings. (To avoid the QtQuick implementation using the compatibility headers (since QtDeclarative's includepath comes first), a few include statements were modified, e.g. from "#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".) There's a change in qtbase that automatically adds QtQuick to the module list if QtDeclarative is used. Together with the compatibility headers, this should help reduce the migration pain for existing projects. In theory, simply getting an existing QtDeclarative-based project to compile and link shouldn't require any changes for now -- but porting to the new scheme is of course recommended, and will eventually become mandatory. Task-number: QTBUG-22889 Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
Diffstat (limited to 'src/quick/util')
-rw-r--r--src/quick/util/qdeclarativeanimation.cpp2441
-rw-r--r--src/quick/util/qdeclarativeanimation_p.h456
-rw-r--r--src/quick/util/qdeclarativeanimation_p_p.h366
-rw-r--r--src/quick/util/qdeclarativebehavior.cpp228
-rw-r--r--src/quick/util/qdeclarativebehavior_p.h95
-rw-r--r--src/quick/util/qdeclarativebind.cpp309
-rw-r--r--src/quick/util/qdeclarativebind_p.h96
-rw-r--r--src/quick/util/qdeclarativechangeset.cpp479
-rw-r--r--src/quick/util/qdeclarativechangeset_p.h166
-rw-r--r--src/quick/util/qdeclarativeconnections.cpp302
-rw-r--r--src/quick/util/qdeclarativeconnections_p.h100
-rw-r--r--src/quick/util/qdeclarativefontloader.cpp335
-rw-r--r--src/quick/util/qdeclarativefontloader_p.h95
-rw-r--r--src/quick/util/qdeclarativelistaccessor.cpp138
-rw-r--r--src/quick/util/qdeclarativelistaccessor_p.h78
-rw-r--r--src/quick/util/qdeclarativelistcompositor.cpp1203
-rw-r--r--src/quick/util/qdeclarativelistcompositor_p.h371
-rw-r--r--src/quick/util/qdeclarativepackage.cpp202
-rw-r--r--src/quick/util/qdeclarativepackage_p.h96
-rw-r--r--src/quick/util/qdeclarativepath.cpp1484
-rw-r--r--src/quick/util/qdeclarativepath_p.h450
-rw-r--r--src/quick/util/qdeclarativepath_p_p.h88
-rw-r--r--src/quick/util/qdeclarativepathinterpolator.cpp122
-rw-r--r--src/quick/util/qdeclarativepathinterpolator_p.h98
-rw-r--r--src/quick/util/qdeclarativepixmapcache.cpp1241
-rw-r--r--src/quick/util/qdeclarativepixmapcache_p.h142
-rw-r--r--src/quick/util/qdeclarativepropertychanges.cpp796
-rw-r--r--src/quick/util/qdeclarativepropertychanges_p.h110
-rw-r--r--src/quick/util/qdeclarativesmoothedanimation.cpp503
-rw-r--r--src/quick/util/qdeclarativesmoothedanimation_p.h101
-rw-r--r--src/quick/util/qdeclarativesmoothedanimation_p_p.h136
-rw-r--r--src/quick/util/qdeclarativespringanimation.cpp462
-rw-r--r--src/quick/util/qdeclarativespringanimation_p.h109
-rw-r--r--src/quick/util/qdeclarativestate.cpp734
-rw-r--r--src/quick/util/qdeclarativestate_p.h208
-rw-r--r--src/quick/util/qdeclarativestate_p_p.h264
-rw-r--r--src/quick/util/qdeclarativestategroup.cpp516
-rw-r--r--src/quick/util/qdeclarativestategroup_p.h95
-rw-r--r--src/quick/util/qdeclarativestateoperations.cpp158
-rw-r--r--src/quick/util/qdeclarativestateoperations_p.h85
-rw-r--r--src/quick/util/qdeclarativestyledtext.cpp624
-rw-r--r--src/quick/util/qdeclarativestyledtext_p.h69
-rw-r--r--src/quick/util/qdeclarativesvgparser.cpp614
-rw-r--r--src/quick/util/qdeclarativesvgparser_p.h60
-rw-r--r--src/quick/util/qdeclarativesystempalette.cpp312
-rw-r--r--src/quick/util/qdeclarativesystempalette_p.h120
-rw-r--r--src/quick/util/qdeclarativetimeline.cpp947
-rw-r--r--src/quick/util/qdeclarativetimeline_p_p.h200
-rw-r--r--src/quick/util/qdeclarativetimer.cpp324
-rw-r--r--src/quick/util/qdeclarativetimer_p.h113
-rw-r--r--src/quick/util/qdeclarativetransition.cpp392
-rw-r--r--src/quick/util/qdeclarativetransition_p.h109
-rw-r--r--src/quick/util/qdeclarativetransitionmanager.cpp282
-rw-r--r--src/quick/util/qdeclarativetransitionmanager_p_p.h85
-rw-r--r--src/quick/util/qdeclarativeutilmodule.cpp98
-rw-r--r--src/quick/util/qdeclarativeutilmodule_p.h61
-rw-r--r--src/quick/util/util.pri59
57 files changed, 19927 insertions, 0 deletions
diff --git a/src/quick/util/qdeclarativeanimation.cpp b/src/quick/util/qdeclarativeanimation.cpp
new file mode 100644
index 0000000000..8c21d11037
--- /dev/null
+++ b/src/quick/util/qdeclarativeanimation.cpp
@@ -0,0 +1,2441 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeanimation_p.h"
+#include "qdeclarativeanimation_p_p.h"
+
+#include <private/qdeclarativestateoperations_p.h>
+#include <private/qdeclarativecontext_p.h>
+
+#include <qdeclarativepropertyvaluesource.h>
+#include <qdeclarative.h>
+#include <qdeclarativeinfo.h>
+#include <qdeclarativeexpression.h>
+#include <private/qdeclarativestringconverters_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativemetatype_p.h>
+#include <private/qdeclarativevaluetype_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativeengine_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 <QtCore/qmath.h>
+
+#include <private/qvariantanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Animation QDeclarativeAbstractAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \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.
+*/
+
+QDeclarativeAbstractAnimation::QDeclarativeAbstractAnimation(QObject *parent)
+: QObject(*(new QDeclarativeAbstractAnimationPrivate), parent)
+{
+}
+
+QDeclarativeAbstractAnimation::~QDeclarativeAbstractAnimation()
+{
+}
+
+QDeclarativeAbstractAnimation::QDeclarativeAbstractAnimation(QDeclarativeAbstractAnimationPrivate &dd, QObject *parent)
+: QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 MouseArea is pressed.
+
+ \code
+ Rectangle {
+ width: 100; height: 100
+ NumberAnimation on x {
+ running: myMouse.pressed
+ from: 0; to: 100
+ }
+ MouseArea { 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. Though, when the animations are assigned to properties,
+ as property value sources using the \e on syntax, they are set to running by default.
+*/
+bool QDeclarativeAbstractAnimation::isRunning() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->running;
+}
+
+// the behavior calls this function
+void QDeclarativeAbstractAnimation::notifyRunningChanged(bool running)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->disableUserControl && d->running != running) {
+ d->running = running;
+ emit runningChanged(running);
+ }
+}
+
+//commence is called to start an animation when it is used as a
+//simple animation, and not as part of a transition
+void QDeclarativeAbstractAnimationPrivate::commence()
+{
+ Q_Q(QDeclarativeAbstractAnimation);
+
+ QDeclarativeStateActions actions;
+ QDeclarativeProperties properties;
+ q->transition(actions, properties, QDeclarativeAbstractAnimation::Forward);
+
+ q->qtAnimation()->start();
+ if (q->qtAnimation()->state() == QAbstractAnimation::Stopped) {
+ running = false;
+ emit q->completed();
+ }
+}
+
+QDeclarativeProperty QDeclarativeAbstractAnimationPrivate::createProperty(QObject *obj, const QString &str, QObject *infoObj)
+{
+ QDeclarativeProperty prop(obj, str, qmlContext(infoObj));
+ if (!prop.isValid()) {
+ qmlInfo(infoObj) << QDeclarativeAbstractAnimation::tr("Cannot animate non-existent property \"%1\"").arg(str);
+ return QDeclarativeProperty();
+ } else if (!prop.isWritable()) {
+ qmlInfo(infoObj) << QDeclarativeAbstractAnimation::tr("Cannot animate read-only property \"%1\"").arg(str);
+ return QDeclarativeProperty();
+ }
+ return prop;
+}
+
+void QDeclarativeAbstractAnimation::setRunning(bool r)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (!d->componentComplete) {
+ d->running = r;
+ if (r == false)
+ d->avoidPropertyValueSourceStart = true;
+ else if (!d->registered) {
+ d->registered = true;
+ QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+ }
+ return;
+ }
+
+ if (d->running == r)
+ return;
+
+ if (d->group || d->disableUserControl) {
+ qmlInfo(this) << "setRunning() cannot be used on non-root animation nodes.";
+ return;
+ }
+
+ d->running = r;
+ if (d->running) {
+ bool supressStart = false;
+ if (d->alwaysRunToEnd && d->loopCount != 1
+ && qtAnimation()->state() == QAbstractAnimation::Running) {
+ //we've restarted before the final loop finished; restore proper loop count
+ if (d->loopCount == -1)
+ qtAnimation()->setLoopCount(d->loopCount);
+ else
+ qtAnimation()->setLoopCount(qtAnimation()->currentLoop() + d->loopCount);
+ supressStart = true; //we want the animation to continue, rather than restart
+ }
+
+ if (!d->connectedTimeLine) {
+ FAST_CONNECT(qtAnimation(), SIGNAL(finished()), this, SLOT(timelineComplete()))
+ d->connectedTimeLine = true;
+ }
+ if (!supressStart)
+ d->commence();
+ emit started();
+ } else {
+ if (d->alwaysRunToEnd) {
+ if (d->loopCount != 1)
+ qtAnimation()->setLoopCount(qtAnimation()->currentLoop()+1); //finish the current loop
+ } else
+ qtAnimation()->stop();
+
+ emit completed();
+ }
+
+ emit runningChanged(d->running);
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 QDeclarativeAbstractAnimation::isPaused() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->paused;
+}
+
+void QDeclarativeAbstractAnimation::setPaused(bool p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->paused == p)
+ return;
+
+ if (d->group || d->disableUserControl) {
+ qmlInfo(this) << "setPaused() cannot be used on non-root animation nodes.";
+ return;
+ }
+
+ d->paused = p;
+
+ if (!d->componentComplete)
+ return;
+
+ if (d->paused)
+ qtAnimation()->pause();
+ else
+ qtAnimation()->resume();
+
+ emit pausedChanged(d->paused);
+}
+
+void QDeclarativeAbstractAnimation::classBegin()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->componentComplete = false;
+}
+
+void QDeclarativeAbstractAnimation::componentComplete()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->componentComplete = true;
+}
+
+void QDeclarativeAbstractAnimation::componentFinalized()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->running) {
+ d->running = false;
+ setRunning(true);
+ }
+ if (d->paused) {
+ d->paused = false;
+ setPaused(true);
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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.
+
+ \note alwaysRunToEnd has no effect on animations in a Transition.
+*/
+bool QDeclarativeAbstractAnimation::alwaysRunToEnd() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->alwaysRunToEnd;
+}
+
+void QDeclarativeAbstractAnimation::setAlwaysRunToEnd(bool f)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->alwaysRunToEnd == f)
+ return;
+
+ d->alwaysRunToEnd = f;
+ emit alwaysRunToEndChanged(f);
+}
+
+/*!
+ \qmlproperty int QtQuick2::Animation::loops
+ This property holds the number of times the animation should play.
+
+ By default, \c loops is 1: the animation will play through once and then stop.
+
+ If set to Animation.Infinite, 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 indefinitely.
+
+ \code
+ Rectangle {
+ width: 100; height: 100; color: "green"
+ RotationAnimation on rotation {
+ loops: Animation.Infinite
+ from: 0
+ to: 360
+ }
+ }
+ \endcode
+*/
+int QDeclarativeAbstractAnimation::loops() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->loopCount;
+}
+
+void QDeclarativeAbstractAnimation::setLoops(int loops)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (loops < 0)
+ loops = -1;
+
+ if (loops == d->loopCount)
+ return;
+
+ d->loopCount = loops;
+ qtAnimation()->setLoopCount(loops);
+ emit loopCountChanged(loops);
+}
+
+
+int QDeclarativeAbstractAnimation::currentTime()
+{
+ return qtAnimation()->currentLoopTime();
+}
+
+void QDeclarativeAbstractAnimation::setCurrentTime(int time)
+{
+ qtAnimation()->setCurrentTime(time);
+}
+
+QDeclarativeAnimationGroup *QDeclarativeAbstractAnimation::group() const
+{
+ Q_D(const QDeclarativeAbstractAnimation);
+ return d->group;
+}
+
+void QDeclarativeAbstractAnimation::setGroup(QDeclarativeAnimationGroup *g)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ if (d->group == g)
+ return;
+ if (d->group)
+ static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.removeAll(this);
+
+ d->group = g;
+
+ if (d->group && !static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.contains(this))
+ static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.append(this);
+
+ //if (g) //if removed from a group, then the group should no longer be the parent
+ setParent(g);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeAbstractAnimation::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeAbstractAnimation::pause()
+{
+ setPaused(true);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeAbstractAnimation::resume()
+{
+ setPaused(false);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 {
+ NumberAnimation on x { 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 QDeclarativeAbstractAnimation::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod QtQuick2::Animation::restart()
+ \brief Restarts the animation.
+
+ This is a convenience method, and is equivalent to calling \c stop() and
+ then \c start().
+*/
+void QDeclarativeAbstractAnimation::restart()
+{
+ stop();
+ start();
+}
+
+/*!
+ \qmlmethod QtQuick2::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 {
+ NumberAnimation on x { 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 QDeclarativeAbstractAnimation::complete()
+{
+ if (isRunning()) {
+ qtAnimation()->setCurrentTime(qtAnimation()->duration());
+ }
+}
+
+void QDeclarativeAbstractAnimation::setTarget(const QDeclarativeProperty &p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->defaultProperty = p;
+
+ if (!d->avoidPropertyValueSourceStart)
+ setRunning(true);
+}
+
+/*
+ we rely on setTarget only being called when used as a value source
+ so this function allows us to do the same thing as setTarget without
+ that assumption
+*/
+void QDeclarativeAbstractAnimation::setDefaultTarget(const QDeclarativeProperty &p)
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->defaultProperty = p;
+}
+
+/*
+ don't allow start/stop/pause/resume to be manually invoked,
+ because something else (like a Behavior) already has control
+ over the animation.
+*/
+void QDeclarativeAbstractAnimation::setDisableUserControl()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ d->disableUserControl = true;
+}
+
+void QDeclarativeAbstractAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_UNUSED(actions);
+ Q_UNUSED(modified);
+ Q_UNUSED(direction);
+}
+
+void QDeclarativeAbstractAnimation::timelineComplete()
+{
+ Q_D(QDeclarativeAbstractAnimation);
+ setRunning(false);
+ if (d->alwaysRunToEnd && d->loopCount != 1) {
+ //restore the proper loopCount for the next run
+ qtAnimation()->setLoopCount(d->loopCount);
+ }
+}
+
+/*!
+ \qmlclass PauseAnimation QDeclarativePauseAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \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
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativePauseAnimation::QDeclarativePauseAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePauseAnimationPrivate), parent)
+{
+ Q_D(QDeclarativePauseAnimation);
+ d->init();
+}
+
+QDeclarativePauseAnimation::~QDeclarativePauseAnimation()
+{
+}
+
+void QDeclarativePauseAnimationPrivate::init()
+{
+ Q_Q(QDeclarativePauseAnimation);
+ pa = new QPauseAnimation;
+ QDeclarative_setParent_noEvent(pa, q);
+}
+
+/*!
+ \qmlproperty int QtQuick2::PauseAnimation::duration
+ This property holds the duration of the pause in milliseconds
+
+ The default value is 250.
+*/
+int QDeclarativePauseAnimation::duration() const
+{
+ Q_D(const QDeclarativePauseAnimation);
+ return d->pa->duration();
+}
+
+void QDeclarativePauseAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QDeclarativePauseAnimation);
+ if (d->pa->duration() == duration)
+ return;
+ d->pa->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+QAbstractAnimation *QDeclarativePauseAnimation::qtAnimation()
+{
+ Q_D(QDeclarativePauseAnimation);
+ return d->pa;
+}
+
+/*!
+ \qmlclass ColorAnimation QDeclarativeColorAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits PropertyAnimation
+ \brief The ColorAnimation element animates changes in color values.
+
+ ColorAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a color value changes.
+
+ Here is a ColorAnimation applied to the \c color property of a \l Rectangle
+ as a property value source. It animates the \c color property's value from
+ its current value to a value of "red", over 1000 milliseconds:
+
+ \snippet doc/src/snippets/declarative/coloranimation.qml 0
+
+ Like any other animation element, a ColorAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ For convenience, when a ColorAnimation is used in a \l Transition, it will
+ animate any \c color properties that have been modified during the state
+ change. If a \l{PropertyAnimation::}{property} or
+ \l{PropertyAnimation::}{properties} are explicitly set for the animation,
+ then those are used instead.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeColorAnimation::QDeclarativeColorAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QColor;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QDeclarativeColorAnimation::~QDeclarativeColorAnimation()
+{
+}
+
+/*!
+ \qmlproperty color QtQuick2::ColorAnimation::from
+ This property holds the color value at which the animation should begin.
+
+ For example, the following animation is not applied until a color value
+ has reached "#c0c0c0":
+
+ \qml
+ Item {
+ states: [
+ // States are defined here...
+ ]
+
+ transition: Transition {
+ NumberAnimation { from: "#c0c0c0"; duration: 2000 }
+ }
+ }
+ \endqml
+
+ If the ColorAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QColor QDeclarativeColorAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.value<QColor>();
+}
+
+void QDeclarativeColorAnimation::setFrom(const QColor &f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty color QtQuick2::ColorAnimation::to
+
+ This property holds the color value at which the animation should end.
+
+ If the ColorAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QColor QDeclarativeColorAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.value<QColor>();
+}
+
+void QDeclarativeColorAnimation::setTo(const QColor &t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass ScriptAction QDeclarativeScriptAction
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits Animation
+ \brief The ScriptAction element allows scripts to be run during an animation.
+
+ ScriptAction can be used to run a script at a specific point in an animation.
+
+ \qml
+ SequentialAnimation {
+ NumberAnimation {
+ // ...
+ }
+ ScriptAction { script: doSomething(); }
+ NumberAnimation {
+ // ...
+ }
+ }
+ \endqml
+
+ When used as part of a Transition, you can also target a specific
+ StateChangeScript to run using the \c scriptName property.
+
+ \snippet doc/src/snippets/declarative/states/statechangescript.qml state and transition
+
+ \sa StateChangeScript
+*/
+QDeclarativeScriptAction::QDeclarativeScriptAction(QObject *parent)
+ :QDeclarativeAbstractAnimation(*(new QDeclarativeScriptActionPrivate), parent)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->init();
+}
+
+QDeclarativeScriptAction::~QDeclarativeScriptAction()
+{
+}
+
+void QDeclarativeScriptActionPrivate::init()
+{
+ Q_Q(QDeclarativeScriptAction);
+ rsa = new QActionAnimation(&proxy);
+ QDeclarative_setParent_noEvent(rsa, q);
+}
+
+/*!
+ \qmlproperty script QtQuick2::ScriptAction::script
+ This property holds the script to run.
+*/
+QDeclarativeScriptString QDeclarativeScriptAction::script() const
+{
+ Q_D(const QDeclarativeScriptAction);
+ return d->script;
+}
+
+void QDeclarativeScriptAction::setScript(const QDeclarativeScriptString &script)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->script = script;
+}
+
+/*!
+ \qmlproperty string QtQuick2::ScriptAction::scriptName
+ 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 scriptName are set, scriptName will be used.
+
+ \note When using scriptName in a reversible transition, the script will only
+ be run when the transition is being run forwards.
+*/
+QString QDeclarativeScriptAction::stateChangeScriptName() const
+{
+ Q_D(const QDeclarativeScriptAction);
+ return d->name;
+}
+
+void QDeclarativeScriptAction::setStateChangeScriptName(const QString &name)
+{
+ Q_D(QDeclarativeScriptAction);
+ d->name = name;
+}
+
+void QDeclarativeScriptActionPrivate::execute()
+{
+ Q_Q(QDeclarativeScriptAction);
+ if (hasRunScriptScript && reversing)
+ return;
+
+ QDeclarativeScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
+
+ if (!scriptStr.script().isEmpty()) {
+ QDeclarativeExpression expr(scriptStr);
+ expr.evaluate();
+ if (expr.hasError())
+ qmlInfo(q) << expr.error();
+ }
+}
+
+void QDeclarativeScriptAction::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeScriptAction);
+ Q_UNUSED(modified);
+
+ d->hasRunScriptScript = false;
+ d->reversing = (direction == Backward);
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ if (action.event && action.event->typeName() == QLatin1String("StateChangeScript")
+ && static_cast<QDeclarativeStateChangeScript*>(action.event)->name() == d->name) {
+ d->runScriptScript = static_cast<QDeclarativeStateChangeScript*>(action.event)->script();
+ d->hasRunScriptScript = true;
+ action.actionDone = true;
+ break; //only match one (names should be unique)
+ }
+ }
+}
+
+QAbstractAnimation *QDeclarativeScriptAction::qtAnimation()
+{
+ Q_D(QDeclarativeScriptAction);
+ return d->rsa;
+}
+
+
+
+/*!
+ \qmlclass PropertyAction QDeclarativePropertyAction
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits Animation
+ \brief The PropertyAction element allows immediate property changes during animation.
+
+ PropertyAction is used to specify an immediate property change during an
+ animation. The property change is not animated.
+
+ It is useful for setting non-animated property values during an animation.
+
+ For example, here is a SequentialAnimation that sets the image's
+ \l {Image::}{smooth} property to \c true, animates the width of the image,
+ then sets \l {Image::}{smooth} back to \c false:
+
+ \snippet doc/src/snippets/declarative/propertyaction.qml standalone
+
+ PropertyAction is also useful for setting the exact point at which a property
+ change should occur during a \l Transition. For example, if PropertyChanges
+ was used in a \l State to rotate an item around a particular
+ \l {Item::}{transformOrigin}, it might be implemented like this:
+
+ \snippet doc/src/snippets/declarative/propertyaction.qml transition
+
+ However, with this code, the \c transformOrigin is not set until \e after
+ the animation, as a \l State is taken to define the values at the \e end of
+ a transition. The animation would rotate at the default \c transformOrigin,
+ then jump to \c Item.BottomRight. To fix this, insert a PropertyAction
+ before the RotationAnimation begins:
+
+ \snippet doc/src/snippets/declarative/propertyaction-sequential.qml sequential
+
+ This immediately sets the \c transformOrigin property to the value defined
+ in the end state of the \l Transition (i.e. the value defined in the
+ PropertyAction object) so that the rotation animation begins with the
+ correct transform origin.
+
+ \sa {QML Animation and Transitions}, QtDeclarative
+*/
+QDeclarativePropertyAction::QDeclarativePropertyAction(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePropertyActionPrivate), parent)
+{
+ Q_D(QDeclarativePropertyAction);
+ d->init();
+}
+
+QDeclarativePropertyAction::~QDeclarativePropertyAction()
+{
+}
+
+void QDeclarativePropertyActionPrivate::init()
+{
+ Q_Q(QDeclarativePropertyAction);
+ spa = new QActionAnimation;
+ QDeclarative_setParent_noEvent(spa, q);
+}
+
+QObject *QDeclarativePropertyAction::target() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->target;
+}
+
+void QDeclarativePropertyAction::setTarget(QObject *o)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->target == o)
+ return;
+ d->target = o;
+ emit targetChanged();
+}
+
+QString QDeclarativePropertyAction::property() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->propertyName;
+}
+
+void QDeclarativePropertyAction::setProperty(const QString &n)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->propertyName == n)
+ return;
+ d->propertyName = n;
+ emit propertyChanged();
+}
+
+/*!
+ \qmlproperty Object QtQuick2::PropertyAction::target
+ \qmlproperty list<Object> QtQuick2::PropertyAction::targets
+ \qmlproperty string QtQuick2::PropertyAction::property
+ \qmlproperty string QtQuick2::PropertyAction::properties
+
+ These properties determine the items and their properties that are
+ affected by this action.
+
+ The details of how these properties are interpreted in different situations
+ is covered in the \l{PropertyAnimation::properties}{corresponding} PropertyAnimation
+ documentation.
+
+ \sa exclude
+*/
+QString QDeclarativePropertyAction::properties() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->properties;
+}
+
+void QDeclarativePropertyAction::setProperties(const QString &p)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->properties == p)
+ return;
+ d->properties = p;
+ emit propertiesChanged(p);
+}
+
+QDeclarativeListProperty<QObject> QDeclarativePropertyAction::targets()
+{
+ Q_D(QDeclarativePropertyAction);
+ return QDeclarativeListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick2::PropertyAction::exclude
+ This property holds the objects that should not be affected by this action.
+
+ \sa targets
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAction::exclude()
+{
+ Q_D(QDeclarativePropertyAction);
+ return QDeclarativeListProperty<QObject>(this, d->exclude);
+}
+
+/*!
+ \qmlproperty any QtQuick2::PropertyAction::value
+ This property holds the value to be set on the property.
+
+ If the PropertyAction is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+*/
+QVariant QDeclarativePropertyAction::value() const
+{
+ Q_D(const QDeclarativePropertyAction);
+ return d->value;
+}
+
+void QDeclarativePropertyAction::setValue(const QVariant &v)
+{
+ Q_D(QDeclarativePropertyAction);
+ if (d->value.isNull || d->value != v) {
+ d->value = v;
+ emit valueChanged(v);
+ }
+}
+
+QAbstractAnimation *QDeclarativePropertyAction::qtAnimation()
+{
+ Q_D(QDeclarativePropertyAction);
+ return d->spa;
+}
+
+void QDeclarativePropertyAction::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativePropertyAction);
+ Q_UNUSED(direction);
+
+ struct QDeclarativeSetPropertyAnimationAction : public QAbstractAnimationAction
+ {
+ QDeclarativeStateActions actions;
+ virtual void doAction()
+ {
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ const QDeclarativeAction &action = actions.at(ii);
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::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();
+ if (!d->propertyName.isEmpty())
+ props << d->propertyName;
+
+ QList<QObject*> targets = d->targets;
+ if (d->target)
+ targets.append(d->target);
+
+ bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
+
+ if (d->defaultProperty.isValid() && !hasSelectors) {
+ props << d->defaultProperty.name();
+ targets << d->defaultProperty.object();
+ }
+
+ QDeclarativeSetPropertyAnimationAction *data = new QDeclarativeSetPropertyAnimationAction;
+
+ bool hasExplicit = false;
+ //an explicit animation has been specified
+ if (d->value.isValid()) {
+ for (int i = 0; i < props.count(); ++i) {
+ for (int j = 0; j < targets.count(); ++j) {
+ QDeclarativeAction myAction;
+ myAction.property = d->createProperty(targets.at(j), props.at(i), this);
+ if (myAction.property.isValid()) {
+ myAction.toValue = d->value;
+ QDeclarativePropertyAnimationPrivate::convertVariant(myAction.toValue, myAction.property.propertyType());
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &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) {
+ QDeclarativeAction &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 ((targets.isEmpty() || targets.contains(obj) || (!same && targets.contains(sObj))) &&
+ (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) &&
+ (props.contains(propertyName) || (!same && props.contains(sPropertyName)))) {
+ QDeclarativeAction myAction = action;
+
+ if (d->value.isValid())
+ myAction.toValue = d->value;
+ QDeclarativePropertyAnimationPrivate::convertVariant(myAction.toValue, myAction.property.propertyType());
+
+ modified << action.property;
+ data->actions << myAction;
+ action.fromValue = myAction.toValue;
+ }
+ }
+
+ if (data->actions.count()) {
+ d->spa->setAnimAction(data, QAbstractAnimation::DeleteWhenStopped);
+ } else {
+ delete data;
+ }
+}
+
+/*!
+ \qmlclass NumberAnimation QDeclarativeNumberAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits PropertyAnimation
+ \brief The NumberAnimation element animates changes in qreal-type values.
+
+ NumberAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a numerical value changes.
+
+ Here is a NumberAnimation applied to the \c x property of a \l Rectangle
+ as a property value source. It animates the \c x value from its current
+ value to a value of 50, over 1000 milliseconds:
+
+ \snippet doc/src/snippets/declarative/numberanimation.qml 0
+
+ Like any other animation element, a NumberAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ Note that NumberAnimation may not animate smoothly if there are irregular
+ changes in the number value that it is tracking. If this is the case, use
+ SmoothedAnimation instead.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ init();
+}
+
+QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent)
+: QDeclarativePropertyAnimation(dd, parent)
+{
+ init();
+}
+
+QDeclarativeNumberAnimation::~QDeclarativeNumberAnimation()
+{
+}
+
+void QDeclarativeNumberAnimation::init()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QReal;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+}
+
+/*!
+ \qmlproperty real QtQuick2::NumberAnimation::from
+ This property holds the starting value for the animation.
+
+ For example, the following animation is not applied until the \c x value
+ has reached 100:
+
+ \qml
+ Item {
+ states: [
+ // ...
+ ]
+
+ transition: Transition {
+ NumberAnimation { properties: "x"; from: 100; duration: 200 }
+ }
+ }
+ \endqml
+
+ If the NumberAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+
+qreal QDeclarativeNumberAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.toReal();
+}
+
+void QDeclarativeNumberAnimation::setFrom(qreal f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real QtQuick2::NumberAnimation::to
+ This property holds the end value for the animation.
+
+ If the NumberAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeNumberAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.toReal();
+}
+
+void QDeclarativeNumberAnimation::setTo(qreal t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass Vector3dAnimation QDeclarativeVector3dAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits PropertyAnimation
+ \brief The Vector3dAnimation element animates changes in QVector3d values.
+
+ Vector3dAnimation is a specialized PropertyAnimation that defines an
+ animation to be applied when a Vector3d value changes.
+
+ Like any other animation element, a Vector3dAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeVector3dAnimation::QDeclarativeVector3dAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->interpolatorType = QMetaType::QVector3D;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultToInterpolatorType = true;
+}
+
+QDeclarativeVector3dAnimation::~QDeclarativeVector3dAnimation()
+{
+}
+
+/*!
+ \qmlproperty real QtQuick2::Vector3dAnimation::from
+ This property holds the starting value for the animation.
+
+ If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QVector3D QDeclarativeVector3dAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from.value<QVector3D>();
+}
+
+void QDeclarativeVector3dAnimation::setFrom(QVector3D f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real QtQuick2::Vector3dAnimation::to
+ This property holds the end value for the animation.
+
+ If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QVector3D QDeclarativeVector3dAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to.value<QVector3D>();
+}
+
+void QDeclarativeVector3dAnimation::setTo(QVector3D t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+
+
+/*!
+ \qmlclass RotationAnimation QDeclarativeRotationAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits PropertyAnimation
+ \brief The RotationAnimation element animates changes in rotation values.
+
+ RotationAnimation is a specialized PropertyAnimation that gives control
+ over the direction of rotation during an animation.
+
+ By default, it rotates in the direction
+ of the numerical change; a rotation from 0 to 240 will rotate 240 degrees
+ clockwise, while a rotation from 240 to 0 will rotate 240 degrees
+ counterclockwise. The \l direction property can be set to specify the
+ direction in which the rotation should occur.
+
+ In the following example we use RotationAnimation to animate the rotation
+ between states via the shortest path:
+
+ \snippet doc/src/snippets/declarative/rotationanimation.qml 0
+
+ Notice the RotationAnimation did not need to set a \l target
+ value. As a convenience, when used in a transition, RotationAnimation will rotate all
+ properties named "rotation" or "angle". You can override this by providing
+ your own properties via \l {PropertyAnimation::properties}{properties} or
+ \l {PropertyAnimation::property}{property}.
+
+ Also, note the \l Rectangle will be rotated around its default
+ \l {Item::}{transformOrigin} (which is \c Item.Center). To use a different
+ transform origin, set the origin in the PropertyChanges object and apply
+ the change at the start of the animation using PropertyAction. See the
+ PropertyAction documentation for more details.
+
+ Like any other animation element, a RotationAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff > 180.0){
+ newt -= 360.0;
+ diff -= 360.0;
+ }
+ while(diff < -180.0){
+ newt += 360.0;
+ diff += 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff < 0.0){
+ newt += 360.0;
+ diff += 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress)
+{
+ qreal newt = t;
+ qreal diff = t-f;
+ while(diff > 0.0){
+ newt -= 360.0;
+ diff -= 360.0;
+ }
+ return QVariant(f + (newt - f) * progress);
+}
+
+QDeclarativeRotationAnimation::QDeclarativeRotationAnimation(QObject *parent)
+: QDeclarativePropertyAnimation(*(new QDeclarativeRotationAnimationPrivate), parent)
+{
+ Q_D(QDeclarativeRotationAnimation);
+ d->interpolatorType = QMetaType::QReal;
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ d->defaultProperties = QLatin1String("rotation,angle");
+}
+
+QDeclarativeRotationAnimation::~QDeclarativeRotationAnimation()
+{
+}
+
+/*!
+ \qmlproperty real QtQuick2::RotationAnimation::from
+ This property holds the starting value for the animation.
+
+ For example, the following animation is not applied until the \c angle value
+ has reached 100:
+
+ \qml
+ Item {
+ states: [
+ // ...
+ ]
+
+ transition: Transition {
+ RotationAnimation { properties: "angle"; from: 100; duration: 2000 }
+ }
+ }
+ \endqml
+
+ If the RotationAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeRotationAnimation::from() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->from.toReal();
+}
+
+void QDeclarativeRotationAnimation::setFrom(qreal f)
+{
+ QDeclarativePropertyAnimation::setFrom(f);
+}
+
+/*!
+ \qmlproperty real QtQuick2::RotationAnimation::to
+ This property holds the end value for the animation..
+
+ If the RotationAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+qreal QDeclarativeRotationAnimation::to() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->to.toReal();
+}
+
+void QDeclarativeRotationAnimation::setTo(qreal t)
+{
+ QDeclarativePropertyAnimation::setTo(t);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::RotationAnimation::direction
+ This property holds the direction of the rotation.
+
+ Possible values are:
+
+ \list
+ \o RotationAnimation.Numerical (default) - Rotate by linearly interpolating between the two numbers.
+ A rotation from 10 to 350 will rotate 340 degrees clockwise.
+ \o RotationAnimation.Clockwise - Rotate clockwise between the two values
+ \o RotationAnimation.Counterclockwise - Rotate counterclockwise between the two values
+ \o RotationAnimation.Shortest - Rotate in the direction that produces the shortest animation path.
+ A rotation from 10 to 350 will rotate 20 degrees counterclockwise.
+ \endlist
+*/
+QDeclarativeRotationAnimation::RotationDirection QDeclarativeRotationAnimation::direction() const
+{
+ Q_D(const QDeclarativeRotationAnimation);
+ return d->direction;
+}
+
+void QDeclarativeRotationAnimation::setDirection(QDeclarativeRotationAnimation::RotationDirection direction)
+{
+ Q_D(QDeclarativeRotationAnimation);
+ if (d->direction == direction)
+ return;
+
+ d->direction = direction;
+ switch(d->direction) {
+ case Clockwise:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateClockwiseRotation);
+ break;
+ case Counterclockwise:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateCounterclockwiseRotation);
+ break;
+ case Shortest:
+ d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(&_q_interpolateShortestRotation);
+ break;
+ default:
+ d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
+ break;
+ }
+
+ emit directionChanged();
+}
+
+
+
+QDeclarativeAnimationGroup::QDeclarativeAnimationGroup(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativeAnimationGroupPrivate), parent)
+{
+}
+
+QDeclarativeAnimationGroup::QDeclarativeAnimationGroup(QDeclarativeAnimationGroupPrivate &dd, QObject *parent)
+ : QDeclarativeAbstractAnimation(dd, parent)
+{
+}
+
+void QDeclarativeAnimationGroupPrivate::append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a)
+{
+ QDeclarativeAnimationGroup *q = qobject_cast<QDeclarativeAnimationGroup *>(list->object);
+ if (q) {
+ a->setGroup(q);
+ // This is an optimization for the parenting that already occurs via addAnimation
+ QDeclarative_setParent_noEvent(a->qtAnimation(), q->d_func()->ag);
+ q->d_func()->ag->addAnimation(a->qtAnimation());
+ }
+}
+
+void QDeclarativeAnimationGroupPrivate::clear_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list)
+{
+ QDeclarativeAnimationGroup *q = qobject_cast<QDeclarativeAnimationGroup *>(list->object);
+ if (q) {
+ while (q->d_func()->animations.count()) {
+ QDeclarativeAbstractAnimation *firstAnim = q->d_func()->animations.at(0);
+ QDeclarative_setParent_noEvent(firstAnim->qtAnimation(), 0);
+ q->d_func()->ag->removeAnimation(firstAnim->qtAnimation());
+ firstAnim->setGroup(0);
+ }
+ }
+}
+
+QDeclarativeAnimationGroup::~QDeclarativeAnimationGroup()
+{
+}
+
+QDeclarativeListProperty<QDeclarativeAbstractAnimation> QDeclarativeAnimationGroup::animations()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> list(this, d->animations);
+ list.append = &QDeclarativeAnimationGroupPrivate::append_animation;
+ list.clear = &QDeclarativeAnimationGroupPrivate::clear_animation;
+ return list;
+}
+
+/*!
+ \qmlclass SequentialAnimation QDeclarativeSequentialAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits Animation
+ \brief The SequentialAnimation element allows animations to be run sequentially.
+
+ The SequentialAnimation and ParallelAnimation elements allow multiple
+ animations to be run together. Animations defined in a SequentialAnimation
+ are run one after the other, while animations defined in a ParallelAnimation
+ are run at the same time.
+
+ The following example runs two number animations in a sequence. The \l Rectangle
+ animates to a \c x position of 50, then to a \c y position of 50.
+
+ \snippet doc/src/snippets/declarative/sequentialanimation.qml 0
+
+ Animations defined within a \l Transition are automatically run in parallel,
+ so SequentialAnimation can be used to enclose the animations in a \l Transition
+ if this is the preferred behavior.
+
+ Like any other animation element, a SequentialAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \note Once an animation has been grouped into a SequentialAnimation or
+ ParallelAnimation, it cannot be individually started and stopped; the
+ SequentialAnimation or ParallelAnimation must be started and stopped as a group.
+
+ \sa ParallelAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativeSequentialAnimation::QDeclarativeSequentialAnimation(QObject *parent) :
+ QDeclarativeAnimationGroup(parent)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ d->ag = new QSequentialAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, this);
+}
+
+QDeclarativeSequentialAnimation::~QDeclarativeSequentialAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeSequentialAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ return d->ag;
+}
+
+void QDeclarativeSequentialAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeAnimationGroup);
+
+ int inc = 1;
+ int from = 0;
+ if (direction == Backward) {
+ inc = -1;
+ from = d->animations.count() - 1;
+ }
+
+ bool valid = d->defaultProperty.isValid();
+ for (int ii = from; ii < d->animations.count() && ii >= 0; ii += inc) {
+ if (valid)
+ d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+}
+
+
+
+/*!
+ \qmlclass ParallelAnimation QDeclarativeParallelAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits Animation
+ \brief The ParallelAnimation element allows animations to be run in parallel.
+
+ The SequentialAnimation and ParallelAnimation elements allow multiple
+ animations to be run together. Animations defined in a SequentialAnimation
+ are run one after the other, while animations defined in a ParallelAnimation
+ are run at the same time.
+
+ The following animation runs two number animations in parallel. The \l Rectangle
+ moves to (50,50) by animating its \c x and \c y properties at the same time.
+
+ \snippet doc/src/snippets/declarative/parallelanimation.qml 0
+
+ Like any other animation element, a ParallelAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \note Once an animation has been grouped into a SequentialAnimation or
+ ParallelAnimation, it cannot be individually started and stopped; the
+ SequentialAnimation or ParallelAnimation must be started and stopped as a group.
+
+ \sa SequentialAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+QDeclarativeParallelAnimation::QDeclarativeParallelAnimation(QObject *parent) :
+ QDeclarativeAnimationGroup(parent)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ d->ag = new QParallelAnimationGroup;
+ QDeclarative_setParent_noEvent(d->ag, this);
+}
+
+QDeclarativeParallelAnimation::~QDeclarativeParallelAnimation()
+{
+}
+
+QAbstractAnimation *QDeclarativeParallelAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeAnimationGroup);
+ return d->ag;
+}
+
+void QDeclarativeParallelAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeAnimationGroup);
+ bool valid = d->defaultProperty.isValid();
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ if (valid)
+ d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+ d->animations.at(ii)->transition(actions, modified, direction);
+ }
+}
+
+
+
+//convert a variant from string type to another animatable type
+void QDeclarativePropertyAnimationPrivate::convertVariant(QVariant &variant, int type)
+{
+ if (variant.userType() != QVariant::String) {
+ variant.convert((QVariant::Type)type);
+ return;
+ }
+
+ switch (type) {
+ case QVariant::Rect: {
+ variant.setValue(QDeclarativeStringConverters::rectFFromString(variant.toString()).toRect());
+ break;
+ }
+ case QVariant::RectF: {
+ variant.setValue(QDeclarativeStringConverters::rectFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Point: {
+ variant.setValue(QDeclarativeStringConverters::pointFFromString(variant.toString()).toPoint());
+ break;
+ }
+ case QVariant::PointF: {
+ variant.setValue(QDeclarativeStringConverters::pointFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Size: {
+ variant.setValue(QDeclarativeStringConverters::sizeFFromString(variant.toString()).toSize());
+ break;
+ }
+ case QVariant::SizeF: {
+ variant.setValue(QDeclarativeStringConverters::sizeFFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Color: {
+ variant.setValue(QDeclarativeStringConverters::colorFromString(variant.toString()));
+ break;
+ }
+ case QVariant::Vector3D: {
+ variant.setValue(QDeclarativeStringConverters::vector3DFromString(variant.toString()));
+ break;
+ }
+ default:
+ if (QDeclarativeValueTypeFactory::isValueType((uint)type)) {
+ variant.convert((QVariant::Type)type);
+ } else {
+ QDeclarativeMetaType::StringConverter converter = QDeclarativeMetaType::customStringConverter(type);
+ if (converter)
+ variant = converter(variant.toString());
+ }
+ break;
+ }
+}
+
+/*!
+ \qmlclass PropertyAnimation QDeclarativePropertyAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits Animation
+ \brief The PropertyAnimation element animates changes in property values.
+
+ PropertyAnimation provides a way to animate changes to a property's value.
+
+ It can be used to define animations in a number of ways:
+
+ \list
+ \o In a \l Transition
+
+ For example, to animate any objects that have changed their \c x or \c y properties
+ as a result of a state change, using an \c InOutQuad easing curve:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml transition
+
+
+ \o In a \l Behavior
+
+ For example, to animate all changes to a rectangle's \c x property:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml behavior
+
+
+ \o As a property value source
+
+ For example, to repeatedly animate the rectangle's \c x property:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml propertyvaluesource
+
+
+ \o In a signal handler
+
+ For example, to fade out \c theObject when clicked:
+ \qml
+ MouseArea {
+ anchors.fill: theObject
+ onClicked: PropertyAnimation { target: theObject; property: "opacity"; to: 0 }
+ }
+ \endqml
+
+ \o Standalone
+
+ For example, to animate \c rect's \c width property over 500ms, from its current width to 30:
+
+ \snippet doc/src/snippets/declarative/propertyanimation.qml standalone
+
+ \endlist
+
+ Depending on how the animation is used, the set of properties normally used will be
+ different. For more information see the individual property documentation, as well
+ as the \l{QML Animation and Transitions} introduction.
+
+ Note that PropertyAnimation inherits the abstract \l Animation element.
+ This includes additional properties and methods for controlling the animation.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativePropertyAnimation::QDeclarativePropertyAnimation(QObject *parent)
+: QDeclarativeAbstractAnimation(*(new QDeclarativePropertyAnimationPrivate), parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->init();
+}
+
+QDeclarativePropertyAnimation::QDeclarativePropertyAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent)
+: QDeclarativeAbstractAnimation(dd, parent)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ d->init();
+}
+
+QDeclarativePropertyAnimation::~QDeclarativePropertyAnimation()
+{
+}
+
+void QDeclarativePropertyAnimationPrivate::init()
+{
+ Q_Q(QDeclarativePropertyAnimation);
+ va = new QDeclarativeBulkValueAnimator;
+ QDeclarative_setParent_noEvent(va, q);
+}
+
+/*!
+ \qmlproperty int QtQuick2::PropertyAnimation::duration
+ This property holds the duration of the animation, in milliseconds.
+
+ The default value is 250.
+*/
+int QDeclarativePropertyAnimation::duration() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->va->duration();
+}
+
+void QDeclarativePropertyAnimation::setDuration(int duration)
+{
+ if (duration < 0) {
+ qmlInfo(this) << tr("Cannot set a duration of < 0");
+ return;
+ }
+
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->va->duration() == duration)
+ return;
+ d->va->setDuration(duration);
+ emit durationChanged(duration);
+}
+
+/*!
+ \qmlproperty real QtQuick2::PropertyAnimation::from
+ This property holds the starting value for the animation.
+
+ If the PropertyAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the starting state of the
+ \l Transition, or the current value of the property at the moment the
+ \l Behavior is triggered.
+
+ \sa {QML Animation and Transitions}
+*/
+QVariant QDeclarativePropertyAnimation::from() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->from;
+}
+
+void QDeclarativePropertyAnimation::setFrom(const QVariant &f)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->fromIsDefined && f == d->from)
+ return;
+ d->from = f;
+ d->fromIsDefined = f.isValid();
+ emit fromChanged(f);
+}
+
+/*!
+ \qmlproperty real QtQuick2::PropertyAnimation::to
+ This property holds the end value for the animation.
+
+ If the PropertyAnimation is defined within a \l Transition or \l Behavior,
+ this value defaults to the value defined in the end state of the
+ \l Transition, or the value of the property change that triggered the
+ \l Behavior.
+
+ \sa {QML Animation and Transitions}
+*/
+QVariant QDeclarativePropertyAnimation::to() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->to;
+}
+
+void QDeclarativePropertyAnimation::setTo(const QVariant &t)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->toIsDefined && t == d->to)
+ return;
+ d->to = t;
+ d->toIsDefined = t.isValid();
+ emit toChanged(t);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::PropertyAnimation::easing.type
+ \qmlproperty real QtQuick2::PropertyAnimation::easing.amplitude
+ \qmlproperty real QtQuick2::PropertyAnimation::easing.overshoot
+ \qmlproperty real QtQuick2::PropertyAnimation::easing.period
+ \brief the easing curve used for the animation.
+
+ To specify an easing curve you need to specify at least the type. For some curves you can also specify
+ amplitude, period and/or overshoot (more details provided after the table). The default easing curve is
+ \c Easing.Linear.
+
+ \qml
+ PropertyAnimation { properties: "y"; easing.type: Easing.InOutElastic; easing.amplitude: 2.0; easing.period: 1.5 }
+ \endqml
+
+ Available types are:
+
+ \table
+ \row
+ \o \c Easing.Linear
+ \o Easing curve for a linear (t) function: velocity is constant.
+ \o \inlineimage qeasingcurve-linear.png
+ \row
+ \o \c Easing.InQuad
+ \o Easing curve for a quadratic (t^2) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquad.png
+ \row
+ \o \c Easing.OutQuad
+ \o Easing curve for a quadratic (t^2) function: decelerating to zero velocity.
+ \o \inlineimage qeasingcurve-outquad.png
+ \row
+ \o \c Easing.InOutQuad
+ \o Easing curve for a quadratic (t^2) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquad.png
+ \row
+ \o \c Easing.OutInQuad
+ \o Easing curve for a quadratic (t^2) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquad.png
+ \row
+ \o \c Easing.InCubic
+ \o Easing curve for a cubic (t^3) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incubic.png
+ \row
+ \o \c Easing.OutCubic
+ \o Easing curve for a cubic (t^3) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcubic.png
+ \row
+ \o \c Easing.InOutCubic
+ \o Easing curve for a cubic (t^3) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcubic.png
+ \row
+ \o \c Easing.OutInCubic
+ \o Easing curve for a cubic (t^3) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincubic.png
+ \row
+ \o \c Easing.InQuart
+ \o Easing curve for a quartic (t^4) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquart.png
+ \row
+ \o \c Easing.OutQuart
+ \o Easing curve for a quartic (t^4) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquart.png
+ \row
+ \o \c Easing.InOutQuart
+ \o Easing curve for a quartic (t^4) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquart.png
+ \row
+ \o \c Easing.OutInQuart
+ \o Easing curve for a quartic (t^4) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquart.png
+ \row
+ \o \c Easing.InQuint
+ \o Easing curve for a quintic (t^5) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inquint.png
+ \row
+ \o \c Easing.OutQuint
+ \o Easing curve for a quintic (t^5) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outquint.png
+ \row
+ \o \c Easing.InOutQuint
+ \o Easing curve for a quintic (t^5) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutquint.png
+ \row
+ \o \c Easing.OutInQuint
+ \o Easing curve for a quintic (t^5) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinquint.png
+ \row
+ \o \c Easing.InSine
+ \o Easing curve for a sinusoidal (sin(t)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-insine.png
+ \row
+ \o \c Easing.OutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outsine.png
+ \row
+ \o \c Easing.InOutSine
+ \o Easing curve for a sinusoidal (sin(t)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutsine.png
+ \row
+ \o \c Easing.OutInSine
+ \o Easing curve for a sinusoidal (sin(t)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinsine.png
+ \row
+ \o \c Easing.InExpo
+ \o Easing curve for an exponential (2^t) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inexpo.png
+ \row
+ \o \c Easing.OutExpo
+ \o Easing curve for an exponential (2^t) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outexpo.png
+ \row
+ \o \c Easing.InOutExpo
+ \o Easing curve for an exponential (2^t) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutexpo.png
+ \row
+ \o \c Easing.OutInExpo
+ \o Easing curve for an exponential (2^t) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinexpo.png
+ \row
+ \o \c Easing.InCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-incirc.png
+ \row
+ \o \c Easing.OutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outcirc.png
+ \row
+ \o \c Easing.InOutCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutcirc.png
+ \row
+ \o \c Easing.OutInCirc
+ \o Easing curve for a circular (sqrt(1-t^2)) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outincirc.png
+ \row
+ \o \c Easing.InElastic
+ \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 Easing.OutElastic
+ \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 Easing.InOutElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: acceleration until halfway, then deceleration.
+ \o \inlineimage qeasingcurve-inoutelastic.png
+ \row
+ \o \c Easing.OutInElastic
+ \o Easing curve for an elastic (exponentially decaying sine wave) function: deceleration until halfway, then acceleration.
+ \o \inlineimage qeasingcurve-outinelastic.png
+ \row
+ \o \c Easing.InBack
+ \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 Easing.OutBack
+ \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 Easing.InOutBack
+ \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 Easing.OutInBack
+ \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 Easing.InBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: accelerating from zero velocity.
+ \o \inlineimage qeasingcurve-inbounce.png
+ \row
+ \o \c Easing.OutBounce
+ \o Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating from zero velocity.
+ \o \inlineimage qeasingcurve-outbounce.png
+ \row
+ \o \c Easing.InOutBounce
+ \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 Easing.OutInBounce
+ \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
+
+ \c easing.amplitude is only applicable for bounce and elastic curves (curves of type
+ \c Easing.InBounce, \c Easing.OutBounce, \c Easing.InOutBounce, \c Easing.OutInBounce, \c Easing.InElastic,
+ \c Easing.OutElastic, \c Easing.InOutElastic or \c Easing.OutInElastic).
+
+ \c easing.overshoot is only applicable if \c easing.type is: \c Easing.InBack, \c Easing.OutBack,
+ \c Easing.InOutBack or \c Easing.OutInBack.
+
+ \c easing.period is only applicable if easing.type is: \c Easing.InElastic, \c Easing.OutElastic,
+ \c Easing.InOutElastic or \c Easing.OutInElastic.
+
+ See the \l {declarative/animation/easing}{easing} example for a demonstration of
+ the different easing settings.
+*/
+QEasingCurve QDeclarativePropertyAnimation::easing() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->va->easingCurve();
+}
+
+void QDeclarativePropertyAnimation::setEasing(const QEasingCurve &e)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->va->easingCurve() == e)
+ return;
+
+ d->va->setEasingCurve(e);
+ emit easingChanged(e);
+}
+
+QObject *QDeclarativePropertyAnimation::target() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->target;
+}
+
+void QDeclarativePropertyAnimation::setTarget(QObject *o)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->target == o)
+ return;
+ d->target = o;
+ emit targetChanged();
+}
+
+QString QDeclarativePropertyAnimation::property() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->propertyName;
+}
+
+void QDeclarativePropertyAnimation::setProperty(const QString &n)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->propertyName == n)
+ return;
+ d->propertyName = n;
+ emit propertyChanged();
+}
+
+QString QDeclarativePropertyAnimation::properties() const
+{
+ Q_D(const QDeclarativePropertyAnimation);
+ return d->properties;
+}
+
+void QDeclarativePropertyAnimation::setProperties(const QString &prop)
+{
+ Q_D(QDeclarativePropertyAnimation);
+ if (d->properties == prop)
+ return;
+
+ d->properties = prop;
+ emit propertiesChanged(prop);
+}
+
+/*!
+ \qmlproperty string QtQuick2::PropertyAnimation::properties
+ \qmlproperty list<Object> QtQuick2::PropertyAnimation::targets
+ \qmlproperty string QtQuick2::PropertyAnimation::property
+ \qmlproperty Object QtQuick2::PropertyAnimation::target
+
+ These properties are used as a set to determine which properties should be animated.
+ The singular and plural forms are functionally identical, e.g.
+ \qml
+ NumberAnimation { target: theItem; property: "x"; to: 500 }
+ \endqml
+ has the same meaning as
+ \qml
+ NumberAnimation { targets: theItem; properties: "x"; to: 500 }
+ \endqml
+ The singular forms are slightly optimized, so if you do have only a single target/property
+ to animate you should try to use them.
+
+ The \c targets property allows multiple targets to be set. For example, this animates the
+ \c x property of both \c itemA and \c itemB:
+
+ \qml
+ NumberAnimation { targets: [itemA, itemB]; properties: "x"; to: 500 }
+ \endqml
+
+ In many cases these properties do not need to be explicitly specified, as they can be
+ inferred from the animation framework:
+
+ \table 80%
+ \row
+ \o Value Source / Behavior
+ \o When an animation is used as a value source or in a Behavior, the default target and property
+ name to be animated can both be inferred.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ NumberAnimation on x { to: 500; loops: Animation.Infinite } //animate theRect's x property
+ Behavior on y { NumberAnimation {} } //animate theRect's y property
+ }
+ \endqml
+ \row
+ \o Transition
+ \o When used in a transition, a property animation is assumed to match \e all targets
+ but \e no properties. In practice, that means you need to specify at least the properties
+ in order for the animation to do anything.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ Item { id: uselessItem }
+ states: State {
+ name: "state1"
+ PropertyChanges { target: theRect; x: 200; y: 200; z: 4 }
+ PropertyChanges { target: uselessItem; x: 10; y: 10; z: 2 }
+ }
+ transitions: Transition {
+ //animate both theRect's and uselessItem's x and y to their final values
+ NumberAnimation { properties: "x,y" }
+
+ //animate theRect's z to its final value
+ NumberAnimation { target: theRect; property: "z" }
+ }
+ }
+ \endqml
+ \row
+ \o Standalone
+ \o When an animation is used standalone, both the target and property need to be
+ explicitly specified.
+ \qml
+ Rectangle {
+ id: theRect
+ width: 100; height: 100
+ color: Qt.rgba(0,0,1)
+ //need to explicitly specify target and property
+ NumberAnimation { id: theAnim; target: theRect; property: "x"; to: 500 }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: theAnim.start()
+ }
+ }
+ \endqml
+ \endtable
+
+ As seen in the above example, properties is specified as a comma-separated string of property names to animate.
+
+ \sa exclude, {QML Animation and Transitions}
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAnimation::targets()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return QDeclarativeListProperty<QObject>(this, d->targets);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick2::PropertyAnimation::exclude
+ This property holds the items not to be affected by this animation.
+ \sa PropertyAnimation::targets
+*/
+QDeclarativeListProperty<QObject> QDeclarativePropertyAnimation::exclude()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return QDeclarativeListProperty<QObject>(this, d->exclude);
+}
+
+QAbstractAnimation *QDeclarativePropertyAnimation::qtAnimation()
+{
+ Q_D(QDeclarativePropertyAnimation);
+ return d->va;
+}
+
+void QDeclarativeAnimationPropertyUpdater::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;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &action = actions[ii];
+
+ if (v == 1.)
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ else {
+ if (!fromSourced && !fromDefined) {
+ action.fromValue = action.property.read();
+ if (interpolatorType)
+ QDeclarativePropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType);
+ }
+ if (!interpolatorType) {
+ int propType = action.property.propertyType();
+ if (!prevInterpolatorType || prevInterpolatorType != propType) {
+ prevInterpolatorType = propType;
+ interpolator = QVariantAnimationPrivate::getInterpolator(prevInterpolatorType);
+ }
+ }
+ if (interpolator)
+ QDeclarativePropertyPrivate::write(action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ if (deleted)
+ return;
+ }
+ wasDeleted = 0;
+ fromSourced = true;
+}
+
+void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativePropertyAnimation);
+
+ QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(QLatin1Char(','));
+ for (int ii = 0; ii < props.count(); ++ii)
+ props[ii] = props.at(ii).trimmed();
+ if (!d->propertyName.isEmpty())
+ props << d->propertyName;
+
+ QList<QObject*> targets = d->targets;
+ if (d->target)
+ targets.append(d->target);
+
+ bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
+ bool useType = (props.isEmpty() && d->defaultToInterpolatorType) ? true : false;
+
+ if (d->defaultProperty.isValid() && !hasSelectors) {
+ props << d->defaultProperty.name();
+ targets << d->defaultProperty.object();
+ }
+
+ if (props.isEmpty() && !d->defaultProperties.isEmpty()) {
+ props << d->defaultProperties.split(QLatin1Char(','));
+ }
+
+ QDeclarativeAnimationPropertyUpdater *data = new QDeclarativeAnimationPropertyUpdater;
+ data->interpolatorType = d->interpolatorType;
+ data->interpolator = d->interpolator;
+ data->reverse = direction == Backward ? true : false;
+ data->fromSourced = false;
+ data->fromDefined = d->fromIsDefined;
+
+ bool hasExplicit = false;
+ //an explicit animation has been specified
+ if (d->toIsDefined) {
+ for (int i = 0; i < props.count(); ++i) {
+ for (int j = 0; j < targets.count(); ++j) {
+ QDeclarativeAction myAction;
+ myAction.property = d->createProperty(targets.at(j), props.at(i), this);
+ if (myAction.property.isValid()) {
+ if (d->fromIsDefined) {
+ myAction.fromValue = d->from;
+ d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ }
+ myAction.toValue = d->to;
+ d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType());
+ data->actions << myAction;
+ hasExplicit = true;
+ for (int ii = 0; ii < actions.count(); ++ii) {
+ QDeclarativeAction &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) {
+ QDeclarativeAction &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 ((targets.isEmpty() || targets.contains(obj) || (!same && 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))) {
+ QDeclarativeAction 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);
+ d->va->setFromSourcedValue(&data->fromSourced);
+ d->actions = &data->actions;
+ } else {
+ delete data;
+ d->va->setFromSourcedValue(0); //clear previous data
+ d->va->setAnimValue(0, QAbstractAnimation::DeleteWhenStopped); //clear previous data
+ d->actions = 0;
+ }
+}
+
+
+QDeclarativeScriptActionPrivate::QDeclarativeScriptActionPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), hasRunScriptScript(false), reversing(false), proxy(this), rsa(0) {}
+
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativeanimation_p.h b/src/quick/util/qdeclarativeanimation_p.h
new file mode 100644
index 0000000000..6c8f552888
--- /dev/null
+++ b/src/quick/util/qdeclarativeanimation_p.h
@@ -0,0 +1,456 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEANIMATION_H
+#define QDECLARATIVEANIMATION_H
+
+#include "qdeclarativestate_p.h"
+#include <QtGui/qvector3d.h>
+
+#include <qdeclarativepropertyvaluesource.h>
+#include <qdeclarative.h>
+#include <qdeclarativescriptstring.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtCore/QAbstractAnimation>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAbstractAnimationPrivate;
+class QDeclarativeAnimationGroup;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativeAbstractAnimation : public QObject, public QDeclarativePropertyValueSource, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAbstractAnimation)
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_INTERFACES(QDeclarativePropertyValueSource)
+ Q_ENUMS(Loops)
+ 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(int loops READ loops WRITE setLoops NOTIFY loopCountChanged)
+ Q_CLASSINFO("DefaultMethod", "start()")
+
+public:
+ QDeclarativeAbstractAnimation(QObject *parent=0);
+ virtual ~QDeclarativeAbstractAnimation();
+
+ enum Loops { Infinite = -2 };
+
+ bool isRunning() const;
+ void setRunning(bool);
+ bool isPaused() const;
+ void setPaused(bool);
+ bool alwaysRunToEnd() const;
+ void setAlwaysRunToEnd(bool);
+
+ int loops() const;
+ void setLoops(int);
+
+ int currentTime();
+ void setCurrentTime(int);
+
+ QDeclarativeAnimationGroup *group() const;
+ void setGroup(QDeclarativeAnimationGroup *);
+
+ void setDefaultTarget(const QDeclarativeProperty &);
+ void setDisableUserControl();
+
+ void classBegin();
+ void componentComplete();
+
+Q_SIGNALS:
+ void started();
+ void completed();
+ void runningChanged(bool);
+ void pausedChanged(bool);
+ void alwaysRunToEndChanged(bool);
+ void loopCountChanged(int);
+
+public Q_SLOTS:
+ void restart();
+ void start();
+ void pause();
+ void resume();
+ void stop();
+ void complete();
+
+protected:
+ QDeclarativeAbstractAnimation(QDeclarativeAbstractAnimationPrivate &dd, QObject *parent);
+
+public:
+ enum TransitionDirection { Forward, Backward };
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation() = 0;
+
+private Q_SLOTS:
+ void timelineComplete();
+ void componentFinalized();
+private:
+ virtual void setTarget(const QDeclarativeProperty &);
+ void notifyRunningChanged(bool running);
+ friend class QDeclarativeBehavior;
+
+
+};
+
+class QDeclarativePauseAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePauseAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePauseAnimation)
+
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+
+public:
+ QDeclarativePauseAnimation(QObject *parent=0);
+ virtual ~QDeclarativePauseAnimation();
+
+ int duration() const;
+ void setDuration(int);
+
+Q_SIGNALS:
+ void durationChanged(int);
+
+protected:
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeScriptActionPrivate;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativeScriptAction : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeScriptAction)
+
+ Q_PROPERTY(QDeclarativeScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString scriptName READ stateChangeScriptName WRITE setStateChangeScriptName)
+
+public:
+ QDeclarativeScriptAction(QObject *parent=0);
+ virtual ~QDeclarativeScriptAction();
+
+ QDeclarativeScriptString script() const;
+ void setScript(const QDeclarativeScriptString &);
+
+ QString stateChangeScriptName() const;
+ void setStateChangeScriptName(const QString &);
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativePropertyActionPrivate;
+class QDeclarativePropertyAction : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAction)
+
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(QString properties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> targets READ targets)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> exclude READ exclude)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ QDeclarativePropertyAction(QObject *parent=0);
+ virtual ~QDeclarativePropertyAction();
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QDeclarativeListProperty<QObject> targets();
+ QDeclarativeListProperty<QObject> exclude();
+
+ QVariant value() const;
+ void setValue(const QVariant &);
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &);
+ void propertiesChanged(const QString &);
+ void targetChanged();
+ void propertyChanged();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativePropertyAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePropertyAnimation : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ 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(QEasingCurve 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 propertyChanged)
+ Q_PROPERTY(QString properties READ properties WRITE setProperties NOTIFY propertiesChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> targets READ targets)
+ Q_PROPERTY(QDeclarativeListProperty<QObject> exclude READ exclude)
+
+public:
+ QDeclarativePropertyAnimation(QObject *parent=0);
+ virtual ~QDeclarativePropertyAnimation();
+
+ virtual int duration() const;
+ virtual void setDuration(int);
+
+ QVariant from() const;
+ void setFrom(const QVariant &);
+
+ QVariant to() const;
+ void setTo(const QVariant &);
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &);
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QString properties() const;
+ void setProperties(const QString &);
+
+ QDeclarativeListProperty<QObject> targets();
+ QDeclarativeListProperty<QObject> exclude();
+
+protected:
+ QDeclarativePropertyAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent);
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+
+Q_SIGNALS:
+ void durationChanged(int);
+ void fromChanged(QVariant);
+ void toChanged(QVariant);
+ void easingChanged(const QEasingCurve &);
+ void propertiesChanged(const QString &);
+ void targetChanged();
+ void propertyChanged();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeColorAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+ Q_PROPERTY(QColor from READ from WRITE setFrom)
+ Q_PROPERTY(QColor to READ to WRITE setTo)
+
+public:
+ QDeclarativeColorAnimation(QObject *parent=0);
+ virtual ~QDeclarativeColorAnimation();
+
+ QColor from() const;
+ void setFrom(const QColor &);
+
+ QColor to() const;
+ void setTo(const QColor &);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeNumberAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ Q_PROPERTY(qreal from READ from WRITE setFrom)
+ Q_PROPERTY(qreal to READ to WRITE setTo)
+
+public:
+ QDeclarativeNumberAnimation(QObject *parent=0);
+ virtual ~QDeclarativeNumberAnimation();
+
+ qreal from() const;
+ void setFrom(qreal);
+
+ qreal to() const;
+ void setTo(qreal);
+
+protected:
+ QDeclarativeNumberAnimation(QDeclarativePropertyAnimationPrivate &dd, QObject *parent);
+
+private:
+ void init();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeVector3dAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyAnimation)
+
+ Q_PROPERTY(QVector3D from READ from WRITE setFrom)
+ Q_PROPERTY(QVector3D to READ to WRITE setTo)
+
+public:
+ QDeclarativeVector3dAnimation(QObject *parent=0);
+ virtual ~QDeclarativeVector3dAnimation();
+
+ QVector3D from() const;
+ void setFrom(QVector3D);
+
+ QVector3D to() const;
+ void setTo(QVector3D);
+};
+
+class QDeclarativeRotationAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeRotationAnimation : public QDeclarativePropertyAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeRotationAnimation)
+ Q_ENUMS(RotationDirection)
+
+ Q_PROPERTY(qreal from READ from WRITE setFrom)
+ Q_PROPERTY(qreal to READ to WRITE setTo)
+ Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+
+public:
+ QDeclarativeRotationAnimation(QObject *parent=0);
+ virtual ~QDeclarativeRotationAnimation();
+
+ qreal from() const;
+ void setFrom(qreal);
+
+ qreal to() const;
+ void setTo(qreal);
+
+ enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise };
+ RotationDirection direction() const;
+ void setDirection(RotationDirection direction);
+
+Q_SIGNALS:
+ void directionChanged();
+};
+
+class QDeclarativeAnimationGroupPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeAnimationGroup : public QDeclarativeAbstractAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations READ animations)
+
+public:
+ QDeclarativeAnimationGroup(QObject *parent);
+ virtual ~QDeclarativeAnimationGroup();
+
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations();
+ friend class QDeclarativeAbstractAnimation;
+
+protected:
+ QDeclarativeAnimationGroup(QDeclarativeAnimationGroupPrivate &dd, QObject *parent);
+};
+
+class QDeclarativeSequentialAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+public:
+ QDeclarativeSequentialAnimation(QObject *parent=0);
+ virtual ~QDeclarativeSequentialAnimation();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+class QDeclarativeParallelAnimation : public QDeclarativeAnimationGroup
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeAnimationGroup)
+
+public:
+ QDeclarativeParallelAnimation(QObject *parent=0);
+ virtual ~QDeclarativeParallelAnimation();
+
+protected:
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ virtual QAbstractAnimation *qtAnimation();
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeAbstractAnimation)
+QML_DECLARE_TYPE(QDeclarativePauseAnimation)
+QML_DECLARE_TYPE(QDeclarativeScriptAction)
+QML_DECLARE_TYPE(QDeclarativePropertyAction)
+QML_DECLARE_TYPE(QDeclarativePropertyAnimation)
+QML_DECLARE_TYPE(QDeclarativeColorAnimation)
+QML_DECLARE_TYPE(QDeclarativeNumberAnimation)
+QML_DECLARE_TYPE(QDeclarativeSequentialAnimation)
+QML_DECLARE_TYPE(QDeclarativeParallelAnimation)
+QML_DECLARE_TYPE(QDeclarativeVector3dAnimation)
+QML_DECLARE_TYPE(QDeclarativeRotationAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEANIMATION_H
diff --git a/src/quick/util/qdeclarativeanimation_p_p.h b/src/quick/util/qdeclarativeanimation_p_p.h
new file mode 100644
index 0000000000..dfeb767877
--- /dev/null
+++ b/src/quick/util/qdeclarativeanimation_p_p.h
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEANIMATION_P_H
+#define QDECLARATIVEANIMATION_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 "qdeclarativeanimation_p.h"
+
+#include <private/qdeclarativenullablevalue_p_p.h>
+
+#include <qdeclarative.h>
+#include <qdeclarativecontext.h>
+
+#include <QtCore/QPauseAnimation>
+#include <QtCore/QVariantAnimation>
+#include <QtCore/QAnimationGroup>
+#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 QDeclarativeAbstractAnimationAction)
+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 Q_AUTOTEST_EXPORT QActionAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+public:
+ QActionAnimation(QObject *parent = 0) : QAbstractAnimation(parent), animAction(0), policy(KeepWhenStopped) {}
+ QActionAnimation(QAbstractAnimationAction *action, QObject *parent = 0)
+ : QAbstractAnimation(parent), animAction(action), policy(KeepWhenStopped) {}
+ ~QActionAnimation() { if (policy == DeleteWhenStopped) { delete animAction; animAction = 0; } }
+ virtual int duration() const { return 0; }
+ void setAnimAction(QAbstractAnimationAction *action, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ if (policy == DeleteWhenStopped)
+ delete animAction;
+ animAction = action;
+ policy = p;
+ }
+protected:
+ virtual void updateCurrentTime(int) {}
+
+ virtual void updateState(State newState, State /*oldState*/)
+ {
+ if (newState == Running) {
+ if (animAction) {
+ animAction->doAction();
+ if (state() == Stopped && policy == DeleteWhenStopped) {
+ delete animAction;
+ animAction = 0;
+ }
+ }
+ }
+ }
+
+private:
+ QAbstractAnimationAction *animAction;
+ DeletionPolicy policy;
+};
+
+class QDeclarativeBulkValueUpdater
+{
+public:
+ virtual ~QDeclarativeBulkValueUpdater() {}
+ virtual void setValue(qreal value) = 0;
+};
+
+//animates QDeclarativeBulkValueUpdater (assumes start and end values will be reals or compatible)
+class Q_AUTOTEST_EXPORT QDeclarativeBulkValueAnimator : public QVariantAnimation
+{
+ Q_OBJECT
+public:
+ QDeclarativeBulkValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {}
+ ~QDeclarativeBulkValueAnimator() { if (policy == DeleteWhenStopped) { delete animValue; animValue = 0; } }
+ void setAnimValue(QDeclarativeBulkValueUpdater *value, DeletionPolicy p)
+ {
+ if (state() == Running)
+ stop();
+ if (policy == DeleteWhenStopped)
+ delete animValue;
+ animValue = value;
+ policy = p;
+ }
+ QDeclarativeBulkValueUpdater *getAnimValue() const
+ {
+ return animValue;
+ }
+ void setFromSourcedValue(bool *value)
+ {
+ fromSourced = value;
+ }
+protected:
+ virtual void updateCurrentValue(const QVariant &value)
+ {
+ if (state() == QAbstractAnimation::Stopped)
+ return;
+
+ 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;
+ }
+ }
+
+private:
+ QDeclarativeBulkValueUpdater *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 QDeclarativeAbstractAnimationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAbstractAnimation)
+public:
+ QDeclarativeAbstractAnimationPrivate()
+ : running(false), paused(false), alwaysRunToEnd(false),
+ connectedTimeLine(false), componentComplete(true),
+ avoidPropertyValueSourceStart(false), disableUserControl(false),
+ registered(false), loopCount(1), group(0) {}
+
+ bool running:1;
+ bool paused:1;
+ bool alwaysRunToEnd:1;
+ bool connectedTimeLine:1;
+ bool componentComplete:1;
+ bool avoidPropertyValueSourceStart:1;
+ bool disableUserControl:1;
+ bool registered:1;
+
+ int loopCount;
+
+ void commence();
+
+ QDeclarativeProperty defaultProperty;
+
+ QDeclarativeAnimationGroup *group;
+
+ static QDeclarativeProperty createProperty(QObject *obj, const QString &str, QObject *infoObj);
+};
+
+class QDeclarativePauseAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePauseAnimation)
+public:
+ QDeclarativePauseAnimationPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), pa(0) {}
+
+ void init();
+
+ QPauseAnimation *pa;
+};
+
+class QDeclarativeScriptActionPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeScriptAction)
+public:
+ QDeclarativeScriptActionPrivate();
+
+ void init();
+
+ QDeclarativeScriptString script;
+ QString name;
+ QDeclarativeScriptString runScriptScript;
+ bool hasRunScriptScript;
+ bool reversing;
+
+ void execute();
+
+ QAnimationActionProxy<QDeclarativeScriptActionPrivate,
+ &QDeclarativeScriptActionPrivate::execute> proxy;
+ QActionAnimation *rsa;
+};
+
+class QDeclarativePropertyActionPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyAction)
+public:
+ QDeclarativePropertyActionPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), target(0), spa(0) {}
+
+ void init();
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+
+ QDeclarativeNullableValue<QVariant> value;
+
+ QActionAnimation *spa;
+};
+
+class QDeclarativeAnimationGroupPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeAnimationGroup)
+public:
+ QDeclarativeAnimationGroupPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), ag(0) {}
+
+ static void append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *role);
+ static void clear_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list);
+ QList<QDeclarativeAbstractAnimation *> animations;
+ QAnimationGroup *ag;
+};
+
+class QDeclarativePropertyAnimationPrivate : public QDeclarativeAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyAnimation)
+public:
+ QDeclarativePropertyAnimationPrivate()
+ : QDeclarativeAbstractAnimationPrivate(), target(0), fromSourced(false), fromIsDefined(false), toIsDefined(false),
+ rangeIsSet(false), defaultToInterpolatorType(0), interpolatorType(0), interpolator(0), va(0), actions(0) {}
+
+ void init();
+
+ QVariant from;
+ QVariant to;
+
+ QObject *target;
+ QString propertyName;
+ QString properties;
+ QList<QObject *> targets;
+ QList<QObject *> exclude;
+ QString defaultProperties;
+
+ bool fromSourced;
+ bool fromIsDefined:1;
+ bool toIsDefined:1;
+ bool rangeIsSet:1;
+ bool defaultToInterpolatorType:1;
+ int interpolatorType;
+ QVariantAnimation::Interpolator interpolator;
+
+ QDeclarativeBulkValueAnimator *va;
+
+ // for animations that don't use the QDeclarativeBulkValueAnimator
+ QDeclarativeStateActions *actions;
+
+ static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress);
+ static void convertVariant(QVariant &variant, int type);
+};
+
+class QDeclarativeRotationAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeRotationAnimation)
+public:
+ QDeclarativeRotationAnimationPrivate() : direction(QDeclarativeRotationAnimation::Numerical) {}
+
+ QDeclarativeRotationAnimation::RotationDirection direction;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeAnimationPropertyUpdater : public QDeclarativeBulkValueUpdater
+{
+public:
+ QDeclarativeStateActions actions;
+ int interpolatorType; //for Number/ColorAnimation
+ int prevInterpolatorType; //for generic
+ QVariantAnimation::Interpolator interpolator;
+ bool reverse;
+ bool fromSourced;
+ bool fromDefined;
+ bool *wasDeleted;
+ QDeclarativeAnimationPropertyUpdater() : prevInterpolatorType(0), wasDeleted(0) {}
+ ~QDeclarativeAnimationPropertyUpdater() { if (wasDeleted) *wasDeleted = true; }
+ void setValue(qreal v);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEANIMATION_P_H
diff --git a/src/quick/util/qdeclarativebehavior.cpp b/src/quick/util/qdeclarativebehavior.cpp
new file mode 100644
index 0000000000..6fb36197ef
--- /dev/null
+++ b/src/quick/util/qdeclarativebehavior.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativebehavior_p.h"
+
+#include "qdeclarativeanimation_p.h"
+#include <qdeclarativecontext.h>
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBehaviorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeBehavior)
+public:
+ QDeclarativeBehaviorPrivate() : animation(0), enabled(true), finalized(false)
+ , blockRunningChanged(false) {}
+
+ QDeclarativeProperty property;
+ QVariant targetValue;
+ QDeclarativeGuard<QDeclarativeAbstractAnimation> animation;
+ bool enabled;
+ bool finalized;
+ bool blockRunningChanged;
+};
+
+/*!
+ \qmlclass Behavior QDeclarativeBehavior
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \brief The Behavior element allows you to specify a default animation for a property change.
+
+ A Behavior defines the default animation to be applied whenever a
+ particular property value changes.
+
+ For example, the following Behavior defines a NumberAnimation to be run
+ whenever the \l Rectangle's \c width value changes. When the MouseArea
+ is clicked, the \c width is changed, triggering the behavior's animation:
+
+ \snippet doc/src/snippets/declarative/behavior.qml 0
+
+ Note that a property cannot have more than one assigned Behavior. To provide
+ multiple animations within a Behavior, use ParallelAnimation or
+ SequentialAnimation.
+
+ If a \l{QML States}{state change} has a \l Transition that matches the same property as a
+ Behavior, the \l Transition animation overrides the Behavior for that
+ state change. For general advice on using Behaviors to animate state changes, see
+ \l{Using QML Behaviors with States}.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/behaviors}{Behavior example}, QtDeclarative
+*/
+
+
+QDeclarativeBehavior::QDeclarativeBehavior(QObject *parent)
+ : QObject(*(new QDeclarativeBehaviorPrivate), parent)
+{
+}
+
+QDeclarativeBehavior::~QDeclarativeBehavior()
+{
+}
+
+/*!
+ \qmlproperty Animation QtQuick2::Behavior::animation
+ \default
+
+ This property holds the animation to run when the behavior is triggered.
+*/
+
+QDeclarativeAbstractAnimation *QDeclarativeBehavior::animation()
+{
+ Q_D(QDeclarativeBehavior);
+ return d->animation;
+}
+
+void QDeclarativeBehavior::setAnimation(QDeclarativeAbstractAnimation *animation)
+{
+ Q_D(QDeclarativeBehavior);
+ if (d->animation) {
+ qmlInfo(this) << tr("Cannot change the animation assigned to a Behavior.");
+ return;
+ }
+
+ d->animation = animation;
+ if (d->animation) {
+ d->animation->setDefaultTarget(d->property);
+ d->animation->setDisableUserControl();
+ FAST_CONNECT(d->animation->qtAnimation(),
+ SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)),
+ this,
+ SLOT(qtAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State)))
+ }
+}
+
+
+void QDeclarativeBehavior::qtAnimationStateChanged(QAbstractAnimation::State newState,QAbstractAnimation::State)
+{
+ Q_D(QDeclarativeBehavior);
+ if (!d->blockRunningChanged)
+ d->animation->notifyRunningChanged(newState == QAbstractAnimation::Running);
+}
+
+
+/*!
+ \qmlproperty bool QtQuick2::Behavior::enabled
+
+ This property holds whether the behavior will be triggered when the tracked
+ property changes value.
+
+ By default a Behavior is enabled.
+*/
+
+bool QDeclarativeBehavior::enabled() const
+{
+ Q_D(const QDeclarativeBehavior);
+ return d->enabled;
+}
+
+void QDeclarativeBehavior::setEnabled(bool enabled)
+{
+ Q_D(QDeclarativeBehavior);
+ if (d->enabled == enabled)
+ return;
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+void QDeclarativeBehavior::write(const QVariant &value)
+{
+ Q_D(QDeclarativeBehavior);
+ bool bypass = !d->enabled || !d->finalized;
+ if (!bypass)
+ qmlExecuteDeferred(this);
+ if (!d->animation || bypass) {
+ QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ d->targetValue = value;
+ return;
+ }
+
+ if (d->animation->isRunning() && value == d->targetValue)
+ return;
+
+ const QVariant &currentValue = d->property.read();
+ d->targetValue = value;
+
+ if (d->animation->qtAnimation()->duration() != -1
+ && d->animation->qtAnimation()->state() != QAbstractAnimation::Stopped) {
+ d->blockRunningChanged = true;
+ d->animation->qtAnimation()->stop();
+ }
+
+ QDeclarativeStateOperation::ActionList actions;
+ QDeclarativeAction action;
+ action.property = d->property;
+ action.fromValue = currentValue;
+ action.toValue = value;
+ actions << action;
+
+ QList<QDeclarativeProperty> after;
+ d->animation->transition(actions, after, QDeclarativeAbstractAnimation::Forward);
+ d->animation->qtAnimation()->start();
+ d->blockRunningChanged = false;
+ if (!after.contains(d->property))
+ QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+}
+
+void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property)
+{
+ Q_D(QDeclarativeBehavior);
+ d->property = property;
+ if (d->animation)
+ d->animation->setDefaultTarget(property);
+
+ QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this));
+ engPriv->registerFinalizeCallback(this, this->metaObject()->indexOfSlot("componentFinalized()"));
+}
+
+void QDeclarativeBehavior::componentFinalized()
+{
+ Q_D(QDeclarativeBehavior);
+ d->finalized = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativebehavior_p.h b/src/quick/util/qdeclarativebehavior_p.h
new file mode 100644
index 0000000000..1f8873de22
--- /dev/null
+++ b/src/quick/util/qdeclarativebehavior_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEBEHAVIOR_H
+#define QDECLARATIVEBEHAVIOR_H
+
+#include <private/qtquickglobal_p.h>
+
+#include <private/qdeclarativepropertyvalueinterceptor_p.h>
+#include <qdeclarative.h>
+#include <QtCore/QAbstractAnimation>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAbstractAnimation;
+class QDeclarativeBehaviorPrivate;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativeBehavior : public QObject, public QDeclarativePropertyValueInterceptor
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeBehavior)
+
+ Q_INTERFACES(QDeclarativePropertyValueInterceptor)
+ Q_CLASSINFO("DefaultProperty", "animation")
+ Q_PROPERTY(QDeclarativeAbstractAnimation *animation READ animation WRITE setAnimation)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_CLASSINFO("DeferredPropertyNames", "animation")
+
+public:
+ QDeclarativeBehavior(QObject *parent=0);
+ ~QDeclarativeBehavior();
+
+ virtual void setTarget(const QDeclarativeProperty &);
+ virtual void write(const QVariant &value);
+
+ QDeclarativeAbstractAnimation *animation();
+ void setAnimation(QDeclarativeAbstractAnimation *);
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+Q_SIGNALS:
+ void enabledChanged();
+
+private Q_SLOTS:
+ void componentFinalized();
+ void qtAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeBehavior)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEBEHAVIOR_H
diff --git a/src/quick/util/qdeclarativebind.cpp b/src/quick/util/qdeclarativebind.cpp
new file mode 100644
index 0000000000..20b2caa582
--- /dev/null
+++ b/src/quick/util/qdeclarativebind.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativebind_p.h"
+
+#include <private/qdeclarativenullablevalue_p_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativebinding_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+#include <qdeclarativeengine.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeproperty.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBindPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeBindPrivate() : componentComplete(true), obj(0), prevBind(0) {}
+ ~QDeclarativeBindPrivate() { if (prevBind) prevBind->destroy(); }
+
+ QDeclarativeNullableValue<bool> when;
+ bool componentComplete;
+ QDeclarativeGuard<QObject> obj;
+ QString propName;
+ QDeclarativeNullableValue<QVariant> value;
+ QDeclarativeProperty prop;
+ QDeclarativeAbstractBinding *prevBind;
+};
+
+
+/*!
+ \qmlclass Binding QDeclarativeBind
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief The Binding element allows arbitrary property bindings to be created.
+
+ \section1 Binding to an inaccessible property
+
+ 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.
+
+ \section1 "Single-branch" conditional binding
+
+ In some circumstances you may want to control the value of a property
+ only when a certain condition is true (and relinquish control in all
+ other cirumstances). This often isn't possible to accomplish with a direct
+ binding, as you need to supply values for all possible branches.
+
+ \qml
+ // warning: "Unable to assign [undefined] to double value"
+ value: if (mouse.pressed) mouse.mouseX
+ \endqml
+
+ The above example will produce a warning whenever we release the mouse, as the value
+ of the binding is undefined when the mouse isn't pressed. We can use the Binding
+ element to rewrite the above code and avoid the warning.
+
+ \qml
+ Binding on value {
+ when: mouse.pressed
+ value: mouse.mouseX
+ }
+ \endqml
+
+ The Binding element will also restore any previously set direct bindings on
+ the property. In that sense, it functions much like a simplified State.
+
+ \qml
+ // this is equivilant to the above Binding
+ State {
+ name: "pressed"
+ when: mouse.pressed
+ PropertyChanges {
+ target: obj
+ value: mouse.mouseX
+ }
+ }
+ \endqml
+
+ If the binding target or binding property is changed, the bound value is
+ immediately pushed onto the new target.
+
+ \sa QtDeclarative
+*/
+QDeclarativeBind::QDeclarativeBind(QObject *parent)
+ : QObject(*(new QDeclarativeBindPrivate), parent)
+{
+}
+
+QDeclarativeBind::~QDeclarativeBind()
+{
+}
+
+/*!
+ \qmlproperty bool QtQuick2::Binding::when
+
+ This property holds when the binding is active.
+ This should be set to an expression that evaluates to true when you want the binding to be active.
+
+ \code
+ Binding {
+ target: contactName; property: 'text'
+ value: name; when: list.ListView.isCurrentItem
+ }
+ \endcode
+
+ When the binding becomes inactive again, any direct bindings that were previously
+ set on the property will be restored.
+*/
+bool QDeclarativeBind::when() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->when;
+}
+
+void QDeclarativeBind::setWhen(bool v)
+{
+ Q_D(QDeclarativeBind);
+ if (!d->when.isNull && d->when == v)
+ return;
+
+ d->when = v;
+ eval();
+}
+
+/*!
+ \qmlproperty Object QtQuick2::Binding::target
+
+ The object to be updated.
+*/
+QObject *QDeclarativeBind::object()
+{
+ Q_D(const QDeclarativeBind);
+ return d->obj;
+}
+
+void QDeclarativeBind::setObject(QObject *obj)
+{
+ Q_D(QDeclarativeBind);
+ if (d->obj && d->when.isValid() && d->when) {
+ /* if we switch the object at runtime, we need to restore the
+ previous binding on the old object before continuing */
+ d->when = false;
+ eval();
+ d->when = true;
+ }
+ d->obj = obj;
+ if (d->componentComplete)
+ d->prop = QDeclarativeProperty(d->obj, d->propName);
+ eval();
+}
+
+/*!
+ \qmlproperty string QtQuick2::Binding::property
+
+ The property to be updated.
+*/
+QString QDeclarativeBind::property() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->propName;
+}
+
+void QDeclarativeBind::setProperty(const QString &p)
+{
+ Q_D(QDeclarativeBind);
+ if (!d->propName.isEmpty() && d->when.isValid() && d->when) {
+ /* if we switch the property name at runtime, we need to restore the
+ previous binding on the old object before continuing */
+ d->when = false;
+ eval();
+ d->when = true;
+ }
+ d->propName = p;
+ if (d->componentComplete)
+ d->prop = QDeclarativeProperty(d->obj, d->propName);
+ eval();
+}
+
+/*!
+ \qmlproperty any QtQuick2::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 QDeclarativeBind::value() const
+{
+ Q_D(const QDeclarativeBind);
+ return d->value.value;
+}
+
+void QDeclarativeBind::setValue(const QVariant &v)
+{
+ Q_D(QDeclarativeBind);
+ d->value = v;
+ eval();
+}
+
+void QDeclarativeBind::setTarget(const QDeclarativeProperty &p)
+{
+ Q_D(QDeclarativeBind);
+ d->prop = p;
+}
+
+void QDeclarativeBind::classBegin()
+{
+ Q_D(QDeclarativeBind);
+ d->componentComplete = false;
+}
+
+void QDeclarativeBind::componentComplete()
+{
+ Q_D(QDeclarativeBind);
+ d->componentComplete = true;
+ if (!d->prop.isValid())
+ d->prop = QDeclarativeProperty(d->obj, d->propName);
+ eval();
+}
+
+void QDeclarativeBind::eval()
+{
+ Q_D(QDeclarativeBind);
+ if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
+ return;
+
+ if (d->when.isValid()) {
+ if (!d->when) {
+ //restore any previous binding
+ if (d->prevBind) {
+ QDeclarativeAbstractBinding *tmp = d->prevBind;
+ d->prevBind = 0;
+ tmp = QDeclarativePropertyPrivate::setBinding(d->prop, tmp);
+ if (tmp) //should this ever be true?
+ tmp->destroy();
+ }
+ return;
+ }
+
+ //save any set binding for restoration
+ QDeclarativeAbstractBinding *tmp;
+ tmp = QDeclarativePropertyPrivate::setBinding(d->prop, 0);
+ if (tmp && d->prevBind)
+ d->prevBind->destroy();
+ else if (!d->prevBind)
+ d->prevBind = tmp;
+ }
+
+ d->prop.write(d->value.value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativebind_p.h b/src/quick/util/qdeclarativebind_p.h
new file mode 100644
index 0000000000..dfb6103a37
--- /dev/null
+++ b/src/quick/util/qdeclarativebind_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEBIND_H
+#define QDECLARATIVEBIND_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBindPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeBind : public QObject, public QDeclarativePropertyValueSource, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeBind)
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_INTERFACES(QDeclarativePropertyValueSource)
+ 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:
+ QDeclarativeBind(QObject *parent=0);
+ ~QDeclarativeBind();
+
+ 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 setTarget(const QDeclarativeProperty &);
+ virtual void classBegin();
+ virtual void componentComplete();
+
+private:
+ void eval();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeBind)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/quick/util/qdeclarativechangeset.cpp b/src/quick/util/qdeclarativechangeset.cpp
new file mode 100644
index 0000000000..81cbe3e10a
--- /dev/null
+++ b/src/quick/util/qdeclarativechangeset.cpp
@@ -0,0 +1,479 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativechangeset_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeChangeSet::QDeclarativeChangeSet()
+ : m_moveCounter(0)
+ , m_difference(0)
+{
+}
+
+QDeclarativeChangeSet::QDeclarativeChangeSet(const QDeclarativeChangeSet &changeSet)
+ : m_removes(changeSet.m_removes)
+ , m_inserts(changeSet.m_inserts)
+ , m_changes(changeSet.m_changes)
+ , m_moveCounter(changeSet.m_moveCounter)
+ , m_difference(0)
+{
+}
+
+QDeclarativeChangeSet::~QDeclarativeChangeSet()
+{
+}
+
+QDeclarativeChangeSet &QDeclarativeChangeSet::operator =(const QDeclarativeChangeSet &changeSet)
+{
+ m_removes = changeSet.m_removes;
+ m_inserts = changeSet.m_inserts;
+ m_changes = changeSet.m_changes;
+ m_moveCounter = changeSet.m_moveCounter;
+ m_difference = changeSet.m_difference;
+ return *this;
+}
+
+void QDeclarativeChangeSet::insert(int index, int count)
+{
+ applyInsertions(QVector<Insert>() << Insert(index, count));
+}
+
+void QDeclarativeChangeSet::remove(int index, int count)
+{
+ QVector<Insert> i;
+ applyRemovals(QVector<Remove>() << Remove(index, count), i);
+}
+
+void QDeclarativeChangeSet::move(int from, int to, int count)
+{
+ apply(QVector<Remove>() << Remove(from, count, -2), QVector<Insert>() << Insert(to, count, -2));
+}
+
+void QDeclarativeChangeSet::change(int index, int count)
+{
+ applyChanges(QVector<Change>() << Change(index, count));
+}
+
+void QDeclarativeChangeSet::apply(const QDeclarativeChangeSet &changeSet)
+{
+ apply(changeSet.m_removes, changeSet.m_inserts, changeSet.m_changes);
+}
+
+void QDeclarativeChangeSet::apply(const QVector<Remove> &removals)
+{
+ QVector<Remove> r = removals;
+ QVector<Insert> i;
+ applyRemovals(r, i);
+}
+
+void QDeclarativeChangeSet::apply(const QVector<Insert> &insertions)
+{
+ QVector<Insert> i = insertions;
+ applyInsertions(i);
+}
+
+void QDeclarativeChangeSet::apply(const QVector<Change> &changes)
+{
+ QVector<Change> c = changes;
+ applyChanges(c);
+}
+
+void QDeclarativeChangeSet::apply(const QVector<Remove> &removals, const QVector<Insert> &insertions, const QVector<Change> &changes)
+{
+ QVector<Remove> r = removals;
+ QVector<Insert> i = insertions;
+ QVector<Change> c = changes;
+ applyRemovals(r, i);
+ applyInsertions(i);
+ applyChanges(c);
+}
+
+void QDeclarativeChangeSet::applyRemovals(QVector<Remove> &removals, QVector<Insert> &insertions)
+{
+ int removeCount = 0;
+ int insertCount = 0;
+ QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator change = m_changes.begin();
+ QVector<Remove>::iterator rit = removals.begin();
+ for (; rit != removals.end(); ++rit) {
+ int index = rit->index + removeCount;
+ int count = rit->count;
+
+ QVector<Insert>::iterator iit = insertions.begin();
+ for (; rit->moveId != -1 && iit != insertions.end() && iit->moveId != rit->moveId; ++iit) {}
+
+ for (QVector<Remove>::iterator nrit = rit + 1; nrit != removals.end(); nrit = rit + 1) {
+ if (nrit->index != rit->index || (rit->moveId == -1) != (nrit->moveId == -1))
+ break;
+ if (nrit->moveId != -1) {
+ QVector<Insert>::iterator niit = iit + 1;
+ if (niit->moveId != nrit->moveId || niit->index != iit->index + iit->count)
+ break;
+ niit->index = iit->index;
+ niit->count += iit->count;
+ iit = insertions.erase(iit);
+ }
+ nrit->count += rit->count;
+ rit = removals.erase(rit);
+ }
+
+ for (; change != m_changes.end() && change->end() < rit->index; ++change) {}
+ for (; change != m_changes.end() && change->index > rit->end(); ++change) {
+ change->count -= qMin(change->end(), rit->end()) - qMax(change->index, rit->index);
+ if (change->count == 0) {
+ change = m_changes.erase(change);
+ } else if (rit->index < change->index) {
+ change->index = rit->index;
+ }
+ }
+ for (; insert != m_inserts.end() && insert->end() <= index; ++insert) {
+ insertCount += insert->count;
+ insert->index -= removeCount;
+ }
+ for (; insert != m_inserts.end() && insert->index < index + count; ++insert) {
+ const int offset = insert->index - index;
+ const int difference = qMin(insert->end(), index + count) - qMax(insert->index, index);
+ const int moveId = rit->moveId != -1 ? m_moveCounter++ : -1;
+ if (insert->moveId != -1) {
+ QVector<Remove>::iterator remove = m_removes.begin();
+ for (; remove != m_removes.end() && remove->moveId != insert->moveId; ++remove) {}
+ Q_ASSERT(remove != m_removes.end());
+ const int offset = index - insert->index;
+ if (rit->moveId != -1 && offset < 0) {
+ const int moveId = m_moveCounter++;
+ iit = insertions.insert(iit, Insert(iit->index, -offset, moveId));
+ ++iit;
+ iit->index += -offset;
+ iit->count -= -offset;
+ rit = removals.insert(rit, Remove(rit->index, -offset, moveId));
+ ++rit;
+ rit->count -= -offset;
+ }
+
+ if (offset > 0) {
+ const int moveId = m_moveCounter++;
+ insert = m_inserts.insert(insert, Insert(insert->index, offset, moveId));
+ ++insert;
+ insert->index += offset;
+ insert->count -= offset;
+ remove = m_removes.insert(remove, Remove(remove->index, offset, moveId));
+ ++remove;
+ remove->count -= offset;
+ rit->index -= offset;
+ index += offset;
+ count -= offset;
+ }
+
+ if (remove->count == difference) {
+ remove->moveId = moveId;
+ } else {
+ remove = m_removes.insert(remove, Remove(remove->index, difference, moveId));
+ ++remove;
+ remove->count -= difference;
+ }
+ } else if (rit->moveId != -1 && offset > 0) {
+ const int moveId = m_moveCounter++;
+ iit = insertions.insert(iit, Insert(iit->index, offset, moveId));
+ ++iit;
+ iit->index += offset;
+ iit->count -= offset;
+ rit = removals.insert(rit, Remove(rit->index, offset, moveId));
+ ++rit;
+ rit->count -= offset;
+ index += offset;
+ count -= offset;
+ }
+
+ if (rit->moveId != -1 && difference > 0) {
+ iit = insertions.insert(iit, Insert(
+ iit->index, difference, insert->moveId != -1 ? moveId : -1));
+ ++iit;
+ iit->index += difference;
+ iit->count -= difference;
+ }
+
+ insert->count -= difference;
+ rit->count -= difference;
+ if (insert->count == 0) {
+ insert = m_inserts.erase(insert);
+ --insert;
+ } else if (index <= insert->index) {
+ insert->index = rit->index;
+ } else {
+ rit->index -= insert->count;
+ }
+ index += difference;
+ count -= difference;
+ removeCount += difference;
+ }
+ rit->index -= insertCount;
+ removeCount += rit->count;
+
+ if (rit->count == 0) {
+ if (rit->moveId != -1 && iit->count == 0)
+ insertions.erase(iit);
+ rit = removals.erase(rit);
+ --rit;
+ } else if (rit->moveId != -1) {
+ const int moveId = m_moveCounter++;
+ rit->moveId = moveId;
+ iit->moveId = moveId;
+ }
+ }
+ for (; change != m_changes.end(); ++change)
+ change->index -= removeCount;
+ for (; insert != m_inserts.end(); ++insert)
+ insert->index -= removeCount;
+
+ removeCount = 0;
+ QVector<Remove>::iterator remove = m_removes.begin();
+ for (rit = removals.begin(); rit != removals.end(); ++rit) {
+ QVector<Insert>::iterator iit = insertions.begin();
+ int index = rit->index + removeCount;
+ for (; rit->moveId != -1 && iit != insertions.end() && iit->moveId != rit->moveId; ++iit) {}
+ for (; remove != m_removes.end() && index > remove->index; ++remove)
+ remove->index -= removeCount;
+ while (remove != m_removes.end() && index + rit->count > remove->index) {
+ int count = 0;
+ const int offset = remove->index - index - removeCount;
+ QVector<Remove>::iterator rend = remove;
+ for (; rend != m_removes.end()
+ && rit->moveId == -1
+ && rend->moveId == -1
+ && rit->index + rit->count >= rend->index; ++rend) {
+ count += rend->count;
+ }
+ if (remove != rend) {
+ const int difference = rend == m_removes.end() || rit->index + rit->count < rend->index - removeCount
+ ? rit->count
+ : offset;
+ count += difference;
+
+ index += difference;
+ rit->count -= difference;
+ removeCount += difference;
+ remove->index = rit->index;
+ remove->count = count;
+ remove = m_removes.erase(++remove, rend);
+ } else if (rit->moveId != -1) {
+ if (offset > 0) {
+ const int moveId = m_moveCounter++;
+ iit = insertions.insert(iit, Insert(iit->index, offset, moveId));
+ ++iit;
+ iit->index += offset;
+ iit->count -= offset;
+ remove = m_removes.insert(remove, Remove(rit->index, offset, moveId));
+ ++remove;
+ rit->count -= offset;
+ removeCount += offset;
+ }
+ remove->index = rit->index;
+ index += offset;
+
+ ++remove;
+ } else {
+ if (offset > 0) {
+ remove = m_removes.insert(remove, Remove(rit->index, offset));
+ ++remove;
+ rit->count -= offset;
+ removeCount += offset;
+ }
+ remove->index = rit->index;
+ index += offset;
+
+ ++remove;
+ }
+ index += count;
+ }
+
+ if (rit->count > 0) {
+ remove = m_removes.insert(remove, *rit);
+ ++remove;
+ }
+ removeCount += rit->count;
+ }
+ for (; remove != m_removes.end(); ++remove)
+ remove->index -= removeCount;
+ m_difference -= removeCount;
+}
+
+void QDeclarativeChangeSet::applyInsertions(QVector<Insert> &insertions)
+{
+ int insertCount = 0;
+ QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator change = m_changes.begin();
+ for (QVector<Insert>::iterator iit = insertions.begin(); iit != insertions.end(); ++iit) {
+ int index = iit->index - insertCount;
+ int count = iit->count;
+ for (; change != m_changes.end() && change->index >= index; ++change)
+ change->index += insertCount;
+ if (change != m_changes.end() && change->index < index + count) {
+ int offset = index - change->index;
+ change = m_changes.insert(change, Change(change->index + insertCount, offset));
+ ++change;
+ change->index += count + offset;
+ change->count -= offset;
+ }
+ for (; insert != m_inserts.end() && iit->index > insert->index + insert->count; ++insert)
+ insert->index += insertCount;
+ if (insert == m_inserts.end()) {
+ insert = m_inserts.insert(insert, *iit);
+ ++insert;
+ insertCount += iit->count;
+ } else {
+ const int offset = index - insert->index;
+ if (offset < 0 || (offset == 0 && (iit->moveId != -1 || insert->moveId != -1))) {
+ insert = m_inserts.insert(insert, *iit);
+ ++insert;
+ } else if (iit->moveId == -1 && insert->moveId == -1) {
+ insert->index -= iit->count;
+ insert->count += iit->count;
+ } else if (offset < insert->count) {
+ const int moveId = insert->moveId != -1 ? m_moveCounter++ : -1;
+ insert = m_inserts.insert(insert, Insert(insert->index + insertCount, offset, moveId));
+ ++insert;
+ insert->index += offset;
+ insert->count -= offset;
+ insert = m_inserts.insert(insert, *iit);
+ ++insert;
+
+ if (insert->moveId != -1) {
+ QVector<Remove>::iterator remove = m_removes.begin();
+ for (; remove != m_removes.end() && remove->moveId != insert->moveId; ++remove) {}
+ Q_ASSERT(remove != m_removes.end());
+ if (remove->count == offset) {
+ remove->moveId = moveId;
+ } else {
+ remove = m_removes.insert(remove, Remove(remove->index, offset, moveId));
+ ++remove;
+ remove->count -= offset;
+ }
+ }
+ } else {
+ ++insert;
+ insert = m_inserts.insert(insert, *iit);
+ ++insert;
+ }
+ insertCount += iit->count;
+ }
+ }
+ for (; change != m_changes.end(); ++change)
+ change->index += insertCount;
+ for (; insert != m_inserts.end(); ++insert)
+ insert->index += insertCount;
+ m_difference += insertCount;
+}
+
+void QDeclarativeChangeSet::applyChanges(QVector<Change> &changes)
+{
+ QVector<Insert>::iterator insert = m_inserts.begin();
+ QVector<Change>::iterator change = m_changes.begin();
+ for (QVector<Change>::iterator cit = changes.begin(); cit != changes.end(); ++cit) {
+ for (; insert != m_inserts.end() && insert->end() < cit->index; ++insert) {}
+ for (; insert != m_inserts.end() && insert->index < cit->end(); ++insert) {
+ const int offset = insert->index - cit->index;
+ const int count = cit->count + cit->index - insert->index - insert->count;
+ if (offset == 0) {
+ cit->index = insert->index + insert->count;
+ cit->count = count;
+ } else {
+ cit = changes.insert(++cit, Change(insert->index + insert->count, count));
+ --cit;
+ cit->count = offset;
+ }
+ }
+
+ for (; change != m_changes.end() && change->index + change->count < cit->index; ++change) {}
+ if (change == m_changes.end() || change->index > cit->index + cit->count) {
+ if (cit->count > 0) {
+ change = m_changes.insert(change, *cit);
+ ++change;
+ }
+ } else {
+ if (cit->index < change->index) {
+ change->count += change->index - cit->index;
+ change->index = cit->index;
+ }
+
+ if (cit->index + cit->count > change->index + change->count) {
+ change->count = cit->index + cit->count - change->index;
+ QVector<Change>::iterator rbegin = change;
+ QVector<Change>::iterator rend = ++rbegin;
+ for (; rend != m_changes.end() && rend->index <= change->index + change->count; ++rend) {
+ if (rend->index + rend->count > change->index + change->count)
+ change->count = rend->index + rend->count - change->index;
+ }
+ if (rbegin != rend) {
+ change = m_changes.erase(rbegin, rend);
+ --change;
+ }
+ }
+ }
+ }
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeChangeSet &set)
+{
+ debug.nospace() << "QDeclarativeChangeSet(";
+ foreach (const QDeclarativeChangeSet::Remove &remove, set.removes()) debug << remove;
+ foreach (const QDeclarativeChangeSet::Insert &insert, set.inserts()) debug << insert;
+ foreach (const QDeclarativeChangeSet::Change &change, set.changes()) debug << change;
+ return debug.nospace() << ")";
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Remove &remove)
+{
+ return (debug.nospace() << "Remove(" << remove.index << "," << remove.count << "," << remove.moveId << ")").space();
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Insert &insert)
+{
+ return (debug.nospace() << "Insert(" << insert.index << "," << insert.count << "," << insert.moveId << ")").space();
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Change &change)
+{
+ return (debug.nospace() << "Change(" << change.index << "," << change.count << ")").space();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quick/util/qdeclarativechangeset_p.h b/src/quick/util/qdeclarativechangeset_p.h
new file mode 100644
index 0000000000..b7554da503
--- /dev/null
+++ b/src/quick/util/qdeclarativechangeset_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECHANGESET_P_H
+#define QDECLARATIVECHANGESET_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 <QtCore/qdebug.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QDeclarativeChangeSet
+{
+public:
+ struct MoveKey
+ {
+ MoveKey() : moveId(-1), offset(0) {}
+ MoveKey(int moveId, int offset) : moveId(moveId), offset(offset) {}
+ int moveId;
+ int offset;
+ };
+
+ struct Change
+ {
+ Change() : index(0), count(0), moveId(-1) {}
+ Change(int index, int count) : index(index), count(count), moveId(-1) {}
+ Change(int index, int count, int moveId) : index(index), count(count), moveId(moveId) {}
+
+ int index;
+ int count;
+ int moveId;
+
+ bool isMove() const { return moveId >= 0; }
+
+ MoveKey moveKey(int index) const { return MoveKey(moveId, index - Change::index); }
+
+ int start() const { return index; }
+ int end() const { return index + count; }
+ };
+
+
+ struct Insert : public Change
+ {
+ Insert() {}
+ Insert(int index, int count) : Change(index, count) {}
+ Insert(int index, int count, int moveId) : Change(index, count, moveId) {}
+ };
+
+ struct Remove : public Change
+ {
+ Remove() {}
+ Remove(int index, int count) : Change(index, count) {}
+ Remove(int index, int count, int moveId) : Change(index, count, moveId) {}
+ };
+
+ QDeclarativeChangeSet();
+ QDeclarativeChangeSet(const QDeclarativeChangeSet &changeSet);
+ ~QDeclarativeChangeSet();
+
+ QDeclarativeChangeSet &operator =(const QDeclarativeChangeSet &changeSet);
+
+ const QVector<Remove> &removes() const { return m_removes; }
+ const QVector<Insert> &inserts() const { return m_inserts; }
+ const QVector<Change> &changes() const {return m_changes; }
+
+ void insert(int index, int count);
+ void remove(int index, int count);
+ void move(int from, int to, int count);
+ void change(int index, int count);
+
+ void apply(const QDeclarativeChangeSet &changeSet);
+ void apply(const QVector<Remove> &removals);
+ void apply(const QVector<Insert> &insertions);
+ void apply(const QVector<Change> &changes);
+ void apply(
+ const QVector<Remove> &removals,
+ const QVector<Insert> &insertions,
+ const QVector<Change> &changes = QVector<Change>());
+
+ bool isEmpty() const { return m_removes.empty() && m_inserts.empty() && m_changes.empty(); }
+
+ void clear()
+ {
+ m_removes.clear();
+ m_inserts.clear();
+ m_changes.clear();
+ m_moveCounter = 0;
+ m_difference = 0;
+ }
+
+ int moveCounter() const { return m_moveCounter; }
+ int difference() const { return m_difference; }
+
+private:
+ void applyRemovals(QVector<Remove> &removals, QVector<Insert> &insertions);
+ void applyInsertions(QVector<Insert> &insertions);
+ void applyChanges(QVector<Change> &changes);
+
+ QVector<Remove> m_removes;
+ QVector<Insert> m_inserts;
+ QVector<Change> m_changes;
+ int m_moveCounter;
+ int m_difference;
+};
+
+inline uint qHash(const QDeclarativeChangeSet::MoveKey &key) { return qHash(qMakePair(key.moveId, key.offset)); }
+inline bool operator ==(const QDeclarativeChangeSet::MoveKey &l, const QDeclarativeChangeSet::MoveKey &r) {
+ return l.moveId == r.moveId && l.offset == r.offset; }
+
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeChangeSet &change);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Remove &remove);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Insert &insert);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeChangeSet::Change &change);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/util/qdeclarativeconnections.cpp b/src/quick/util/qdeclarativeconnections.cpp
new file mode 100644
index 0000000000..ee2c6edcc5
--- /dev/null
+++ b/src/quick/util/qdeclarativeconnections.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeconnections_p.h"
+
+#include <private/qdeclarativeexpression_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativeboundsignal_p.h>
+#include <qdeclarativecontext.h>
+#include <private/qdeclarativecontext_p.h>
+#include <qdeclarativeinfo.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstringlist.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeConnectionsPrivate : public QObjectPrivate
+{
+public:
+ QDeclarativeConnectionsPrivate() : target(0), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
+
+ QList<QDeclarativeBoundSignal*> boundsignals;
+ QObject *target;
+
+ bool targetSet;
+ bool ignoreUnknownSignals;
+ bool componentcomplete;
+
+ QByteArray data;
+};
+
+/*!
+ \qmlclass Connections QDeclarativeConnections
+ \inqmlmodule QtQuick 2
+ \ingroup qml-utility-elements
+ \brief A Connections element describes generalized connections to signals.
+
+ A Connections object creates a connection to a QML signal.
+
+ 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
+ MouseArea {
+ onClicked: { foo(parameters) }
+ }
+ \endqml
+
+ However, it is not possible to connect to a signal in this way in some
+ cases, such as when:
+
+ \list
+ \i Multiple connections to the same signal are required
+ \i Creating connections outside the scope of the signal sender
+ \i Connecting to targets not defined in QML
+ \endlist
+
+ When any of these are needed, the Connections element can be used instead.
+
+ For example, the above code can be changed to use a Connections object,
+ like this:
+
+ \qml
+ MouseArea {
+ Connections {
+ onClicked: foo(parameters)
+ }
+ }
+ \endqml
+
+ More generally, the Connections object can be a child of some object other than
+ the sender of the signal:
+
+ \qml
+ MouseArea {
+ id: area
+ }
+ // ...
+ \endqml
+ \qml
+ Connections {
+ target: area
+ onClicked: foo(parameters)
+ }
+ \endqml
+
+ \sa QtDeclarative
+*/
+QDeclarativeConnections::QDeclarativeConnections(QObject *parent) :
+ QObject(*(new QDeclarativeConnectionsPrivate), parent)
+{
+}
+
+QDeclarativeConnections::~QDeclarativeConnections()
+{
+}
+
+/*!
+ \qmlproperty Object QtQuick2::Connections::target
+ This property holds the object that sends the signal.
+
+ If this property is not set, the \c target defaults to the parent of the Connection.
+
+ If set to null, no connection is made and any signal handlers are ignored
+ until the target is not null.
+*/
+QObject *QDeclarativeConnections::target() const
+{
+ Q_D(const QDeclarativeConnections);
+ return d->targetSet ? d->target : parent();
+}
+
+void QDeclarativeConnections::setTarget(QObject *obj)
+{
+ Q_D(QDeclarativeConnections);
+ d->targetSet = true; // even if setting to 0, it is *set*
+ if (d->target == obj)
+ return;
+ foreach (QDeclarativeBoundSignal *s, d->boundsignals) {
+ // It is possible that target is being changed due to one of our signal
+ // handlers -> use deleteLater().
+ if (s->isEvaluating())
+ s->deleteLater();
+ else
+ delete s;
+ }
+ d->boundsignals.clear();
+ d->target = obj;
+ connectSignals();
+ emit targetChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::Connections::ignoreUnknownSignals
+
+ Normally, a connection to a non-existent signal produces runtime errors.
+
+ If this property is set to \c true, such errors are ignored.
+ This is useful if you intend to connect to different types of objects, handling
+ a different set of signals for each object.
+*/
+bool QDeclarativeConnections::ignoreUnknownSignals() const
+{
+ Q_D(const QDeclarativeConnections);
+ return d->ignoreUnknownSignals;
+}
+
+void QDeclarativeConnections::setIgnoreUnknownSignals(bool ignore)
+{
+ Q_D(QDeclarativeConnections);
+ d->ignoreUnknownSignals = ignore;
+}
+
+
+
+QByteArray
+QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
+{
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ for(int ii = 0; ii < props.count(); ++ii)
+ {
+ QString propName = props.at(ii).name();
+ int propLine = props.at(ii).location().line;
+
+ if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
+ return QByteArray();
+ }
+
+ QList<QVariant> values = props.at(ii).assignedValues();
+
+ for (int i = 0; i < values.count(); ++i) {
+ const QVariant &value = values.at(i);
+
+ if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed"));
+ return QByteArray();
+ } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error"));
+ return QByteArray();
+ } else {
+ QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
+ if (v.isScript()) {
+ ds << propName;
+ ds << rewriteSignalHandler(v.asScript(), propName);
+ ds << propLine;
+ } else {
+ error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected"));
+ return QByteArray();
+ }
+ }
+ }
+ }
+
+ return rv;
+}
+
+void QDeclarativeConnectionsParser::setCustomData(QObject *object,
+ const QByteArray &data)
+{
+ QDeclarativeConnectionsPrivate *p =
+ static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object));
+ p->data = data;
+}
+
+
+void QDeclarativeConnections::connectSignals()
+{
+ Q_D(QDeclarativeConnections);
+ if (!d->componentcomplete || (d->targetSet && !target()))
+ return;
+
+ QDataStream ds(d->data);
+ while (!ds.atEnd()) {
+ QString propName;
+ ds >> propName;
+ QString script;
+ ds >> script;
+ int line;
+ ds >> line;
+ QDeclarativeProperty prop(target(), propName);
+ if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) {
+ QDeclarativeBoundSignal *signal =
+ new QDeclarativeBoundSignal(target(), prop.method(), this);
+
+ QString location;
+ QDeclarativeContextData *ctxtdata = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(this);
+ if (ddata) {
+ ctxtdata = ddata->outerContext;
+ if (ctxtdata && !ctxtdata->url.isEmpty())
+ location = ddata->outerContext->url.toString();
+ }
+
+ QDeclarativeExpression *expression = ctxtdata ?
+ QDeclarativeExpressionPrivate::create(ctxtdata, 0, script, true, location, line) : 0;
+ signal->setExpression(expression);
+ d->boundsignals += signal;
+ } else {
+ if (!d->ignoreUnknownSignals)
+ qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName);
+ }
+ }
+}
+
+void QDeclarativeConnections::classBegin()
+{
+ Q_D(QDeclarativeConnections);
+ d->componentcomplete=false;
+}
+
+void QDeclarativeConnections::componentComplete()
+{
+ Q_D(QDeclarativeConnections);
+ d->componentcomplete=true;
+ connectSignals();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativeconnections_p.h b/src/quick/util/qdeclarativeconnections_p.h
new file mode 100644
index 0000000000..bab29e5521
--- /dev/null
+++ b/src/quick/util/qdeclarativeconnections_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECONNECTIONS_H
+#define QDECLARATIVECONNECTIONS_H
+
+#include <qdeclarative.h>
+#include <private/qdeclarativecustomparser_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeBoundSignal;
+class QDeclarativeContext;
+class QDeclarativeConnectionsPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeConnections : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeConnections)
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
+
+public:
+ QDeclarativeConnections(QObject *parent=0);
+ ~QDeclarativeConnections();
+
+ QObject *target() const;
+ void setTarget(QObject *);
+
+ bool ignoreUnknownSignals() const;
+ void setIgnoreUnknownSignals(bool ignore);
+
+Q_SIGNALS:
+ void targetChanged();
+
+private:
+ void connectSignals();
+ void classBegin();
+ void componentComplete();
+};
+
+class QDeclarativeConnectionsParser : public QDeclarativeCustomParser
+{
+public:
+ virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &);
+ virtual void setCustomData(QObject *, const QByteArray &);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeConnections)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/quick/util/qdeclarativefontloader.cpp b/src/quick/util/qdeclarativefontloader.cpp
new file mode 100644
index 0000000000..e95bd11a7b
--- /dev/null
+++ b/src/quick/util/qdeclarativefontloader.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativefontloader_p.h"
+
+#include <qdeclarativecontext.h>
+#include <qdeclarativeengine.h>
+
+#include <QStringList>
+#include <QUrl>
+#include <QDebug>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QFontDatabase>
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+#define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
+
+class QDeclarativeFontObject : public QObject
+{
+Q_OBJECT
+
+public:
+ QDeclarativeFontObject(int _id);
+
+ void download(const QUrl &url, QNetworkAccessManager *manager);
+
+Q_SIGNALS:
+ void fontDownloaded(const QString&, QDeclarativeFontLoader::Status);
+
+private Q_SLOTS:
+ void replyFinished();
+
+public:
+ int id;
+
+private:
+ QNetworkReply *reply;
+ int redirectCount;
+
+ Q_DISABLE_COPY(QDeclarativeFontObject)
+};
+
+QDeclarativeFontObject::QDeclarativeFontObject(int _id = -1)
+ : QObject(0), id(_id), reply(0), redirectCount(0) {}
+
+
+void QDeclarativeFontObject::download(const QUrl &url, QNetworkAccessManager *manager)
+{
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ reply = manager->get(req);
+ QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
+}
+
+void QDeclarativeFontObject::replyFinished()
+{
+ if (reply) {
+ redirectCount++;
+ if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkAccessManager *manager = reply->manager();
+ reply->deleteLater();
+ reply = 0;
+ download(url, manager);
+ return;
+ }
+ }
+ redirectCount = 0;
+
+ if (!reply->error()) {
+ id = QFontDatabase::addApplicationFontFromData(reply->readAll());
+ if (id != -1)
+ emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarativeFontLoader::Ready);
+ else
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ } else {
+ emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
+ }
+ reply->deleteLater();
+ reply = 0;
+ }
+}
+
+
+class QDeclarativeFontLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeFontLoader)
+
+public:
+ QDeclarativeFontLoaderPrivate() : status(QDeclarativeFontLoader::Null) {}
+
+ QUrl url;
+ QString name;
+ QDeclarativeFontLoader::Status status;
+ static QHash<QUrl, QDeclarativeFontObject*> fonts;
+};
+
+QHash<QUrl, QDeclarativeFontObject*> QDeclarativeFontLoaderPrivate::fonts;
+
+/*!
+ \qmlclass FontLoader QDeclarativeFontLoader
+ \inqmlmodule QtQuick 2
+ \ingroup qml-utility-elements
+ \brief The FontLoader element allows fonts to be loaded by name or URL.
+
+ The FontLoader element is used to load fonts by name or URL.
+
+ The \l status indicates when the font has been loaded, which is useful
+ for fonts loaded from remote sources.
+
+ For example:
+ \qml
+ import QtQuick 1.0
+
+ Column {
+ 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
+
+ \sa {declarative/text/fonts}{Fonts example}
+*/
+QDeclarativeFontLoader::QDeclarativeFontLoader(QObject *parent)
+ : QObject(*(new QDeclarativeFontLoaderPrivate), parent)
+{
+}
+
+QDeclarativeFontLoader::~QDeclarativeFontLoader()
+{
+}
+
+/*!
+ \qmlproperty url QtQuick2::FontLoader::source
+ The url of the font to load.
+*/
+QUrl QDeclarativeFontLoader::source() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->url;
+}
+
+void QDeclarativeFontLoader::setSource(const QUrl &url)
+{
+ Q_D(QDeclarativeFontLoader);
+ if (url == d->url)
+ return;
+ d->url = url;
+ emit sourceChanged();
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
+ if (!localFile.isEmpty()) {
+ if (!d->fonts.contains(d->url)) {
+ int id = QFontDatabase::addApplicationFont(localFile);
+ if (id != -1) {
+ updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready);
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject(id);
+ d->fonts[d->url] = fo;
+ } else {
+ updateFontInfo(QString(), Error);
+ }
+ } else {
+ updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready);
+ }
+ } else {
+ if (!d->fonts.contains(d->url)) {
+ QDeclarativeFontObject *fo = new QDeclarativeFontObject;
+ d->fonts[d->url] = fo;
+ fo->download(d->url, qmlEngine(this)->networkAccessManager());
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
+ } else {
+ QDeclarativeFontObject *fo = d->fonts[d->url];
+ if (fo->id == -1) {
+ d->status = Loading;
+ emit statusChanged();
+ QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
+ this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
+ }
+ else
+ updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready);
+ }
+ }
+}
+
+void QDeclarativeFontLoader::updateFontInfo(const QString& name, QDeclarativeFontLoader::Status status)
+{
+ Q_D(QDeclarativeFontLoader);
+
+ if (name != d->name) {
+ d->name = name;
+ emit nameChanged();
+ }
+ if (status != d->status) {
+ if (status == Error)
+ qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\"";
+ d->status = status;
+ emit statusChanged();
+ }
+}
+
+/*!
+ \qmlproperty string QtQuick2::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
+ Item {
+ width: 200; height: 50
+
+ FontLoader {
+ id: webFont
+ source: "http://www.mysite.com/myfont.ttf"
+ }
+ Text {
+ text: "Fancy font"
+ font.family: webFont.name
+ }
+ }
+ \endqml
+*/
+QString QDeclarativeFontLoader::name() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->name;
+}
+
+void QDeclarativeFontLoader::setName(const QString &name)
+{
+ Q_D(QDeclarativeFontLoader);
+ if (d->name == name)
+ return;
+ d->name = name;
+ emit nameChanged();
+ d->status = Ready;
+ emit statusChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::FontLoader::status
+
+ This property holds the status of font loading. It can be one of:
+ \list
+ \o FontLoader.Null - no font has been set
+ \o FontLoader.Ready - the font has been loaded
+ \o FontLoader.Loading - the font is currently being loaded
+ \o FontLoader.Error - an error occurred while loading the font
+ \endlist
+
+ Use this status to provide an update or respond to the status change in some way.
+ For example, you could:
+
+ \list
+ \o Trigger a state change:
+ \qml
+ State { name: 'loaded'; when: loader.status == FontLoader.Ready }
+ \endqml
+
+ \o Implement an \c onStatusChanged signal handler:
+ \qml
+ FontLoader {
+ id: loader
+ onStatusChanged: if (loader.status == FontLoader.Ready) console.log('Loaded')
+ }
+ \endqml
+
+ \o Bind to the status value:
+ \qml
+ Text { text: loader.status == FontLoader.Ready ? 'Loaded' : 'Not loaded' }
+ \endqml
+ \endlist
+*/
+QDeclarativeFontLoader::Status QDeclarativeFontLoader::status() const
+{
+ Q_D(const QDeclarativeFontLoader);
+ return d->status;
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativefontloader.moc>
diff --git a/src/quick/util/qdeclarativefontloader_p.h b/src/quick/util/qdeclarativefontloader_p.h
new file mode 100644
index 0000000000..2511908a8e
--- /dev/null
+++ b/src/quick/util/qdeclarativefontloader_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEFONTLOADER_H
+#define QDECLARATIVEFONTLOADER_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeFontLoaderPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeFontLoader : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeFontLoader)
+ 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 };
+
+ QDeclarativeFontLoader(QObject *parent = 0);
+ ~QDeclarativeFontLoader();
+
+ QUrl source() const;
+ void setSource(const QUrl &url);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ Status status() const;
+
+private Q_SLOTS:
+ void updateFontInfo(const QString&, QDeclarativeFontLoader::Status);
+
+Q_SIGNALS:
+ void sourceChanged();
+ void nameChanged();
+ void statusChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeFontLoader)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEFONTLOADER_H
+
diff --git a/src/quick/util/qdeclarativelistaccessor.cpp b/src/quick/util/qdeclarativelistaccessor.cpp
new file mode 100644
index 0000000000..0063514e59
--- /dev/null
+++ b/src/quick/util/qdeclarativelistaccessor.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativelistaccessor_p.h"
+
+#include <private/qdeclarativemetatype_p.h>
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdebug.h>
+
+// ### Remove me
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativeListAccessor::QDeclarativeListAccessor()
+: m_type(Invalid)
+{
+}
+
+QDeclarativeListAccessor::~QDeclarativeListAccessor()
+{
+}
+
+QVariant QDeclarativeListAccessor::list() const
+{
+ return d;
+}
+
+void QDeclarativeListAccessor::setList(const QVariant &v, QDeclarativeEngine *engine)
+{
+ d = v;
+
+ QDeclarativeEnginePrivate *enginePrivate = engine?QDeclarativeEnginePrivate::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 && QDeclarativeMetaType::isQObject(d.userType())) ||
+ (enginePrivate && enginePrivate->isQObject(d.userType()))) {
+ QObject *data = enginePrivate?enginePrivate->toQObject(v):QDeclarativeMetaType::toQObject(v);
+ d = QVariant::fromValue(data);
+ m_type = Instance;
+ } else if (d.userType() == qMetaTypeId<QDeclarativeListReference>()) {
+ m_type = ListProperty;
+ } else {
+ m_type = Instance;
+ }
+}
+
+int QDeclarativeListAccessor::count() const
+{
+ switch(m_type) {
+ case StringList:
+ return qvariant_cast<QStringList>(d).count();
+ case VariantList:
+ return qvariant_cast<QVariantList>(d).count();
+ case ListProperty:
+ return ((QDeclarativeListReference *)d.constData())->count();
+ case Instance:
+ return 1;
+ case Integer:
+ return d.toInt();
+ default:
+ case Invalid:
+ return 0;
+ }
+}
+
+QVariant QDeclarativeListAccessor::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 ListProperty:
+ return QVariant::fromValue(((QDeclarativeListReference *)d.constData())->at(idx));
+ case Instance:
+ return d;
+ case Integer:
+ return QVariant(idx);
+ default:
+ case Invalid:
+ return QVariant();
+ }
+}
+
+bool QDeclarativeListAccessor::isValid() const
+{
+ return m_type != Invalid;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativelistaccessor_p.h b/src/quick/util/qdeclarativelistaccessor_p.h
new file mode 100644
index 0000000000..b9fcdd01d2
--- /dev/null
+++ b/src/quick/util/qdeclarativelistaccessor_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELISTACCESSOR_H
+#define QDECLARATIVELISTACCESSOR_H
+
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class Q_AUTOTEST_EXPORT QDeclarativeListAccessor
+{
+public:
+ QDeclarativeListAccessor();
+ ~QDeclarativeListAccessor();
+
+ QVariant list() const;
+ void setList(const QVariant &, QDeclarativeEngine * = 0);
+
+ bool isValid() const;
+
+ int count() const;
+ QVariant at(int) const;
+
+ enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer };
+ Type type() const { return m_type; }
+
+private:
+ Type m_type;
+ QVariant d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVELISTACCESSOR_H
diff --git a/src/quick/util/qdeclarativelistcompositor.cpp b/src/quick/util/qdeclarativelistcompositor.cpp
new file mode 100644
index 0000000000..d73d76e386
--- /dev/null
+++ b/src/quick/util/qdeclarativelistcompositor.cpp
@@ -0,0 +1,1203 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativelistcompositor_p.h"
+
+#include <QtCore/qvarlengtharray.h>
+
+//#define QT_DECLARATIVE_VERIFY_MINIMAL
+//#define QT_DECLARATIVE_VERIFY_INTEGRITY
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_DECLARATIVE_VERIFY_MINIMAL
+#define QT_DECLARATIVE_VERIFY_INTEGRITY
+static bool qt_verifyMinimal(
+ const QDeclarativeListCompositor::iterator &begin,
+ const QDeclarativeListCompositor::iterator &end)
+{
+ bool minimal = true;
+ int index = 0;
+
+ for (const QDeclarativeListCompositor::Range *range = begin->next; range != *end; range = range->next, ++index) {
+ if (range->previous->list == range->list
+ && range->previous->flags == (range->flags & ~QDeclarativeListCompositor::AppendFlag)
+ && range->previous->end() == range->index) {
+ qWarning() << index << "Consecutive ranges";
+ qWarning() << *range->previous;
+ qWarning() << *range;
+ minimal = false;
+ }
+ }
+
+ return minimal;
+}
+
+#endif
+
+#ifdef QT_DECLARATIVE_VERIFY_INTEGRITY
+static bool qt_printInfo(const QDeclarativeListCompositor &compositor)
+{
+ qWarning() << compositor;
+ return true;
+}
+
+static bool qt_verifyIntegrity(
+ const QDeclarativeListCompositor::iterator &begin,
+ const QDeclarativeListCompositor::iterator &end,
+ const QDeclarativeListCompositor::iterator &cachedIt)
+{
+ bool valid = true;
+
+ int index = 0;
+ QDeclarativeListCompositor::iterator it;
+ for (it = begin; *it != *end; *it = it->next) {
+ if (it->count == 0 && !it->append()) {
+ qWarning() << index << "Empty non-append range";
+ valid = false;
+ }
+ if (it->count < 0) {
+ qWarning() << index << "Negative count";
+ valid = false;
+ }
+ if (it->list && it->flags != QDeclarativeListCompositor::CacheFlag && it->index < 0) {
+ qWarning() << index <<"Negative index";
+ valid = false;
+ }
+ if (it->previous->next != it.range) {
+ qWarning() << index << "broken list: it->previous->next != it.range";
+ valid = false;
+ }
+ if (it->next->previous != it.range) {
+ qWarning() << index << "broken list: it->next->previous != it.range";
+ valid = false;
+ }
+ if (*it == *cachedIt) {
+ for (int i = 0; i < end.groupCount; ++i) {
+ int groupIndex = it.index[i];
+ if (cachedIt->flags & (1 << i))
+ groupIndex += cachedIt.offset;
+ if (groupIndex != cachedIt.index[i]) {
+ qWarning() << index
+ << "invalid cached index"
+ << QDeclarativeListCompositor::Group(i)
+ << "Expected:"
+ << groupIndex
+ << "Actual"
+ << cachedIt.index[i]
+ << cachedIt;
+ valid = false;
+ }
+ }
+ }
+ it.incrementIndexes(it->count);
+ ++index;
+ }
+
+ for (int i = 0; i < end.groupCount; ++i) {
+ if (end.index[i] != it.index[i]) {
+ qWarning() << "Group" << i << "count invalid. Expected:" << end.index[i] << "Actual:" << it.index[i];
+ valid = false;
+ }
+ }
+ return valid;
+}
+#endif
+
+#if defined(QT_DECLARATIVE_VERIFY_MINIMAL)
+# define QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!(qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
+ && qt_verifyMinimal(iterator(m_ranges.next, 0, Default, m_groupCount), m_end)) \
+ && qt_printInfo(*this)));
+#elif defined(QT_DECLARATIVE_VERIFY_INTEGRITY)
+# define QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR Q_ASSERT(!(!qt_verifyIntegrity(iterator(m_ranges.next, 0, Default, m_groupCount), m_end, m_cacheIt) \
+ && qt_printInfo(*this)));
+#else
+# define QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+#endif
+
+//#define QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(args) qDebug() << m_end.index[1] << m_end.index[0] << Q_FUNC_INFO args;
+#define QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(args)
+
+QDeclarativeListCompositor::iterator &QDeclarativeListCompositor::iterator::operator +=(int difference)
+{
+ Q_ASSERT(difference >= 0);
+ while (!(range->flags & groupFlag)) {
+ incrementIndexes(range->count - offset);
+ offset = 0;
+ range = range->next;
+ }
+ decrementIndexes(offset);
+ offset += difference;
+ while (offset >= range->count || !(range->flags & groupFlag)) {
+ if (range->flags & groupFlag)
+ offset -= range->count;
+ incrementIndexes(range->count);
+ range = range->next;
+ }
+ incrementIndexes(offset);
+ return *this;
+}
+
+QDeclarativeListCompositor::iterator &QDeclarativeListCompositor::iterator::operator -=(int difference)
+{
+ Q_ASSERT(difference >= 0);
+ while (!(range->flags & groupFlag)) {
+ decrementIndexes(offset);
+ range = range->previous;
+ offset = range->count;
+ }
+ decrementIndexes(offset);
+ offset -= difference;
+ while (offset < 0) {
+ range = range->previous;
+ if (range->flags & groupFlag)
+ offset += range->count;
+ decrementIndexes(range->count);
+ }
+ incrementIndexes(offset);
+ return *this;
+}
+
+QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_iterator::operator +=(int difference)
+{
+ Q_ASSERT(difference >= 0);
+ while (!(range->flags & groupFlag)) {
+ incrementIndexes(range->count - offset);
+ offset = 0;
+ range = range->next;
+ }
+ decrementIndexes(offset);
+ offset += difference;
+ while (offset > range->count
+ || (offset == range->count && !range->append() && offset > 0)
+ || (!(range->flags & groupFlag) && offset > 0)) {
+ if (range->flags & groupFlag)
+ offset -= range->count;
+ incrementIndexes(range->count);
+ range = range->next;
+ }
+ incrementIndexes(offset);
+ return *this;
+}
+
+QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_iterator::operator -=(int difference)
+{
+ Q_ASSERT(difference >= 0);
+ while (!(range->flags & groupFlag) && range->previous->flags) {
+ decrementIndexes(offset);
+ range = range->previous;
+ offset = (range->flags & (GroupMask | CacheFlag)) ? range->count : 0;
+ }
+ decrementIndexes(offset);
+ offset -= difference;
+ while (offset < 0) {
+ range = range->previous;
+ if (range->flags & groupFlag)
+ offset += range->count;
+ decrementIndexes(range->count);
+ }
+ incrementIndexes(offset);
+ for (Range *previous = range->previous; offset == 0 && previous->prepend(); previous = previous->previous) {
+ if (previous->append() && previous->inGroup()) {
+ offset = previous->count;
+ range = previous;
+ } else if (!previous->inGroup()) {
+ break;
+ }
+ }
+
+ return *this;
+}
+
+QDeclarativeListCompositor::QDeclarativeListCompositor()
+ : m_end(m_ranges.next, 0, Default, 2)
+ , m_cacheIt(m_end)
+ , m_groupCount(2)
+ , m_defaultFlags(PrependFlag | DefaultFlag)
+ , m_removeFlags(AppendFlag | PrependFlag | GroupMask)
+{
+}
+
+QDeclarativeListCompositor::~QDeclarativeListCompositor()
+{
+ for (Range *next, *range = m_ranges.next; range != &m_ranges; range = next) {
+ next = range->next;
+ delete range;
+ }
+}
+
+inline QDeclarativeListCompositor::Range *QDeclarativeListCompositor::insert(
+ Range *before, void *list, int index, int count, int flags)
+{
+ return new Range(before, list, index, count, flags);
+}
+
+inline QDeclarativeListCompositor::Range *QDeclarativeListCompositor::erase(
+ Range *range)
+{
+ Range *next = range->next;
+ next->previous = range->previous;
+ next->previous->next = range->next;
+ delete range;
+ return next;
+}
+
+void QDeclarativeListCompositor::setGroupCount(int count)
+{
+ m_groupCount = count;
+ m_end = iterator(&m_ranges, 0, Default, m_groupCount);
+ m_cacheIt = m_end;
+}
+
+int QDeclarativeListCompositor::count(Group group) const
+{
+ return m_end.index[group];
+}
+
+QDeclarativeListCompositor::iterator QDeclarativeListCompositor::find(Group group, int index)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group << index)
+ Q_ASSERT(index >=0 && index < count(group));
+ if (m_cacheIt == m_end) {
+ m_cacheIt = iterator(m_ranges.next, 0, group, m_groupCount);
+ m_cacheIt += index;
+ } else {
+ const int offset = index - m_cacheIt.index[group];
+ m_cacheIt.setGroup(group);
+ if (offset > 0) {
+ m_cacheIt += offset;
+ } else if (offset < 0) {
+ m_cacheIt -= -offset;
+ } else if (offset == 0) {
+ m_cacheIt -= 0;
+ m_cacheIt += 0;
+ }
+ }
+ Q_ASSERT(m_cacheIt.index[group] == index);
+ Q_ASSERT(m_cacheIt->inGroup(group));
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+ return m_cacheIt;
+}
+
+QDeclarativeListCompositor::iterator QDeclarativeListCompositor::find(Group group, int index) const
+{
+ return const_cast<QDeclarativeListCompositor *>(this)->find(group, index);
+}
+
+QDeclarativeListCompositor::insert_iterator QDeclarativeListCompositor::findInsertPosition(Group group, int index)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group << index)
+ Q_ASSERT(index >=0 && index <= count(group));
+ insert_iterator it;
+ if (m_cacheIt == m_end) {
+ it = iterator(m_ranges.next, 0, group, m_groupCount);
+ it += index;
+ } else {
+ const int offset = index - m_cacheIt.index[group];
+ it = m_cacheIt;
+ it.setGroup(group);
+ if (offset > 0) {
+ it += offset;
+ } else if (offset < 0) {
+ it -= -offset;
+ } else if (offset == 0) {
+ it -= 0;
+ it += 0;
+ }
+ }
+ Q_ASSERT(it.index[group] == index);
+ return it;
+}
+
+QDeclarativeListCompositor::iterator QDeclarativeListCompositor::begin(Group group)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group)
+ m_cacheIt = iterator(m_ranges.next, 0, group, m_groupCount);
+ m_cacheIt += 0;
+ return m_cacheIt;
+}
+
+void QDeclarativeListCompositor::append(
+ void *list, int index, int count, int flags, QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << index << count << flags)
+ insert(m_end, list, index, count, flags, inserts);
+}
+
+void QDeclarativeListCompositor::insert(
+ Group group, int before, void *list, int index, int count, int flags, QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group << before << list << index << count << flags)
+ insert(findInsertPosition(group, before), list, index, count, flags, inserts);
+}
+
+QDeclarativeListCompositor::iterator QDeclarativeListCompositor::insert(
+ iterator before, void *list, int index, int count, int flags, QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< before << list << index << count << flags)
+ if (inserts) {
+ inserts->append(Insert(before, count, flags & GroupMask));
+ }
+ if (before.offset > 0) {
+ *before = insert(
+ *before, before->list, before->index, before.offset, before->flags & ~AppendFlag)->next;
+ before->index += before.offset;
+ before->count -= before.offset;
+ before.offset = 0;
+ }
+
+ if (!(flags & AppendFlag) && *before != m_ranges.next
+ && before->previous->list == list
+ && before->previous->flags == flags
+ && (!list || before->previous->end() == index)) {
+ before->previous->count += count;
+ before.incrementIndexes(count, flags);
+ } else {
+ *before = insert(*before, list, index, count, flags);
+ before.offset = 0;
+ }
+
+ if (!(flags & AppendFlag) && before->next != &m_ranges
+ && before->list == before->next->list
+ && before->flags == before->next->flags
+ && (!list || before->end() == before->next->index)) {
+ before->next->index = before->index;
+ before->next->count += before->count;
+ *before = erase(*before);
+ }
+
+ m_end.incrementIndexes(count, flags);
+ m_cacheIt = before;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+ return before;
+}
+
+void QDeclarativeListCompositor::setFlags(
+ Group group, int index, int count, int flags, QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group << index << count << flags)
+ setFlags(find(group, index), count, flags, inserts);
+}
+
+void QDeclarativeListCompositor::setFlags(
+ iterator from, int count, int flags, QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< from << count << flags)
+ if (!flags || !count)
+ return;
+
+ if (from.offset > 0) {
+ *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
+ from->index += from.offset;
+ from->count -= from.offset;
+ from.offset = 0;
+ }
+
+ for (; count > 0; *from = from->next) {
+ if (from != from.group) {
+ from.incrementIndexes(from->count);
+ continue;
+ }
+ const int difference = qMin(count, from->count);
+ count -= difference;
+
+ const int insertFlags = ~from->flags & flags;
+ const int setFlags = (from->flags | flags) & ~AppendFlag;
+ if (insertFlags && inserts)
+ inserts->append(Insert(from, difference, insertFlags | (from->flags & CacheFlag)));
+ m_end.incrementIndexes(difference, insertFlags);
+ from.incrementIndexes(difference, setFlags);
+
+ if (from->previous != &m_ranges
+ && from->previous->list == from->list
+ && (!from->list || from->previous->end() == from->index)
+ && from->previous->flags == setFlags) {
+ from->previous->count += difference;
+ from->index += difference;
+ from->count -= difference;
+ if (from->count == 0) {
+ if (from->append())
+ from->previous->flags |= AppendFlag;
+ *from = erase(*from)->previous;
+ continue;
+ } else {
+ break;
+ }
+ } else if (!insertFlags) {
+ from.incrementIndexes(from->count - difference);
+ continue;
+ } else if (difference < from->count) {
+ *from = insert(*from, from->list, from->index, difference, setFlags)->next;
+ from->index += difference;
+ from->count -= difference;
+ } else {
+ from->flags |= flags;
+ continue;
+ }
+ from.incrementIndexes(from->count);
+ }
+
+ if (from->previous != &m_ranges
+ && from->previous->list == from->list
+ && (!from->list || from->previous->end() == from->index)
+ && from->previous->flags == (from->flags & ~AppendFlag)) {
+ from.offset = from->previous->count;
+ from->previous->count += from->count;
+ from->previous->flags = from->flags;
+ *from = erase(*from)->previous;
+ }
+ m_cacheIt = from;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+void QDeclarativeListCompositor::clearFlags(
+ Group group, int index, int count, int flags, QVector<Remove> *removes)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< group << index << count << flags)
+ clearFlags(find(group, index), count, flags, removes);
+}
+
+void QDeclarativeListCompositor::clearFlags(
+ iterator from, int count, int flags, QVector<Remove> *removes)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< from << count << flags)
+ if (!flags || !count)
+ return;
+
+ const bool clearCache = flags & CacheFlag;
+
+ if (from.offset > 0) {
+ *from = insert(*from, from->list, from->index, from.offset, from->flags & ~AppendFlag)->next;
+ from->index += from.offset;
+ from->count -= from.offset;
+ from.offset = 0;
+ }
+
+ for (; count > 0; *from = from->next) {
+ if (from != from.group) {
+ from.incrementIndexes(from->count);
+ continue;
+ }
+ const int difference = qMin(count, from->count);
+ count -= difference;
+
+ const int removeFlags = from->flags & flags & ~(AppendFlag | PrependFlag);
+ const int clearedFlags = from->flags & ~(flags | AppendFlag);
+ if (removeFlags && removes) {
+ const int maskedFlags = clearCache
+ ? (removeFlags & ~CacheFlag)
+ : (removeFlags | (from->flags & CacheFlag));
+ if (maskedFlags)
+ removes->append(Remove(from, difference, maskedFlags));
+ }
+ m_end.decrementIndexes(difference, removeFlags);
+ from.incrementIndexes(difference, clearedFlags);
+
+ if (from->previous != &m_ranges
+ && from->previous->list == from->list
+ && (!from->list || clearedFlags == CacheFlag || from->previous->end() == from->index)
+ && from->previous->flags == clearedFlags) {
+ from->previous->count += difference;
+ from->index += difference;
+ from->count -= difference;
+ if (from->count == 0) {
+ if (from->append())
+ from->previous->flags |= AppendFlag;
+ *from = erase(*from)->previous;
+ } else {
+ from.incrementIndexes(from->count);
+ }
+ } else if (difference < from->count) {
+ if (clearedFlags)
+ *from = insert(*from, from->list, from->index, difference, clearedFlags)->next;
+ from->index += difference;
+ from->count -= difference;
+ from.incrementIndexes(from->count);
+ } else if (clearedFlags) {
+ from->flags &= ~flags;
+ } else {
+ *from = erase(*from)->previous;
+ }
+ }
+
+ if (*from != &m_ranges && from->previous != &m_ranges
+ && from->previous->list == from->list
+ && (!from->list || from->previous->end() == from->index)
+ && from->previous->flags == (from->flags & ~AppendFlag)) {
+ from.offset = from->previous->count;
+ from->previous->count += from->count;
+ from->previous->flags = from->flags;
+ *from = erase(*from)->previous;
+ }
+ m_cacheIt = from;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+void QDeclarativeListCompositor::removeList(void *list, QVector<Remove> *removes, bool destroyed)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << destroyed)
+ for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
+ if (it->list == list) {
+ const int flags = it->flags & (GroupMask | CacheFlag);
+ if (flags) {
+ removes->append(Remove(it, it->count, flags));
+ m_end.decrementIndexes(it->count, flags);
+ }
+ if (destroyed)
+ it->list = 0;
+ if (it->inCache()) {
+ it->flags = CacheFlag;
+ it.cacheIndex += it->count;
+ } else {
+ *it = erase(*it)->previous;
+ }
+ } else {
+ it.incrementIndexes(it->count);
+ }
+ }
+ m_cacheIt = m_end;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+bool QDeclarativeListCompositor::verifyMoveTo(
+ Group fromGroup, int from, Group toGroup, int to, int count) const
+{
+ if (fromGroup != toGroup) {
+ // determine how many items from the destination group intersect with the source group.
+ iterator fromIt = find(fromGroup, from);
+
+ int intersectingCount = 0;
+
+ for (; count > 0; *fromIt = fromIt->next) {
+ if (*fromIt == &m_ranges)
+ return false;
+ if (!fromIt->inGroup(fromGroup))
+ continue;
+ if (fromIt->inGroup(toGroup))
+ intersectingCount += qMin(count, fromIt->count - fromIt.offset);
+ count -= fromIt->count - fromIt.offset;
+ fromIt.offset = 0;
+ }
+ count = intersectingCount;
+ }
+
+ return to >= 0 && to + count <= m_end.index[toGroup];
+}
+
+void QDeclarativeListCompositor::move(
+ Group fromGroup,
+ int from,
+ Group toGroup,
+ int to,
+ int count,
+ QVector<Remove> *removes,
+ QVector<Insert> *inserts)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< fromGroup << from << toGroup << to << count)
+ Q_ASSERT(count != 0);
+ Q_ASSERT(from >=0 && from + count <= m_end.index[toGroup]);
+ Q_ASSERT(verifyMoveTo(fromGroup, from, toGroup, to, count));
+
+ iterator fromIt = find(fromGroup, from);
+ if (fromIt.offset > 0) {
+ *fromIt = insert(
+ *fromIt, fromIt->list, fromIt->index, fromIt.offset, fromIt->flags & ~AppendFlag)->next;
+ fromIt->index += fromIt.offset;
+ fromIt->count -= fromIt.offset;
+ fromIt.offset = 0;
+ }
+
+ Range movedFlags;
+ for (int moveId = 0; count > 0;) {
+ if (fromIt != fromIt.group) {
+ fromIt.incrementIndexes(fromIt->count);
+ *fromIt = fromIt->next;
+ continue;
+ }
+ int difference = qMin(count, fromIt->count);
+
+ new Range(
+ &movedFlags,
+ fromIt->list,
+ fromIt->index,
+ difference,
+ fromIt->flags & ~(PrependFlag | AppendFlag));
+ if (removes)
+ removes->append(Remove(fromIt, difference, fromIt->flags, moveId++));
+ count -= difference;
+ fromIt->count -= difference;
+
+ int removeIndex = fromIt->index;
+ if (fromIt->prepend()
+ && fromIt->previous != &m_ranges
+ && fromIt->previous->flags == PrependFlag
+ && fromIt->previous->list == fromIt->list
+ && fromIt->previous->end() == fromIt->index) {
+ fromIt->previous->count += difference;
+ } else if (fromIt->prepend()) {
+ *fromIt = insert(*fromIt, fromIt->list, removeIndex, difference, PrependFlag)->next;
+ }
+ fromIt->index += difference;
+
+ if (fromIt->count == 0) {
+ if (fromIt->append())
+ fromIt->previous->flags |= AppendFlag;
+ *fromIt = erase(*fromIt);
+
+ if (*fromIt != m_ranges.next && fromIt->flags == PrependFlag
+ && fromIt->previous != &m_ranges
+ && fromIt->previous->flags == PrependFlag
+ && fromIt->previous->list == fromIt->list
+ && fromIt->previous->end() == fromIt->index) {
+ fromIt.incrementIndexes(fromIt->count);
+ fromIt->previous->count += fromIt->count;
+ *fromIt = erase(*fromIt);
+ }
+ } else if (count > 0) {
+ *fromIt = fromIt->next;
+ }
+ }
+
+ if (*fromIt != m_ranges.next
+ && *fromIt != &m_ranges
+ && fromIt->previous->list == fromIt->list
+ && (!fromIt->list || fromIt->previous->end() == fromIt->index)
+ && fromIt->previous->flags == (fromIt->flags & ~AppendFlag)) {
+ if (fromIt == fromIt.group)
+ fromIt.offset = fromIt->previous->count;
+ fromIt.offset = fromIt->previous->count;
+ fromIt->previous->count += fromIt->count;
+ fromIt->previous->flags = fromIt->flags;
+ *fromIt = erase(*fromIt)->previous;
+ }
+
+ insert_iterator toIt = fromIt;
+ toIt.setGroup(toGroup);
+ const int difference = to - toIt.index[toGroup];
+ if (difference > 0)
+ toIt += difference;
+ else
+ toIt -= -difference;
+
+ if (toIt.offset > 0) {
+ *toIt = insert(*toIt, toIt->list, toIt->index, toIt.offset, toIt->flags & ~AppendFlag)->next;
+ toIt->index += toIt.offset;
+ toIt->count -= toIt.offset;
+ toIt.offset = 0;
+ }
+
+ for (Range *range = movedFlags.previous; range != &movedFlags; range = range->previous) {
+ if (*toIt != &m_ranges
+ && range->list == toIt->list
+ && (!range->list || range->end() == toIt->index)
+ && range->flags == (toIt->flags & ~AppendFlag)) {
+ toIt->index -= range->count;
+ toIt->count += range->count;
+ } else {
+ *toIt = insert(*toIt, range->list, range->index, range->count, range->flags);
+ }
+ }
+
+ if (*toIt != m_ranges.next
+ && toIt->previous->list == toIt->list
+ && (!toIt->list || (toIt->previous->end() == toIt->index && toIt->previous->flags == (toIt->flags & ~AppendFlag)))) {
+ toIt.offset = toIt->previous->count;
+ toIt->previous->count += toIt->count;
+ toIt->previous->flags = toIt->flags;
+ *toIt = erase(*toIt)->previous;
+ }
+ Insert insert(toIt, 0, 0, 0);
+ for (Range *next, *range = movedFlags.next; range != &movedFlags; range = next) {
+ insert.count = range->count;
+ insert.flags = range->flags;
+ if (inserts)
+ inserts->append(insert);
+ for (int i = 0; i < m_groupCount; ++i) {
+ if (insert.inGroup(i))
+ insert.index[i] += range->count;
+ }
+ ++insert.moveId;
+ next = range->next;
+ delete range;
+ }
+
+ m_cacheIt = toIt;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+void QDeclarativeListCompositor::clear()
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR( )
+ for (Range *range = m_ranges.next; range != &m_ranges; range = erase(range)) {}
+ m_end = iterator(m_ranges.next, 0, Default, m_groupCount);
+ m_cacheIt = m_end;
+}
+
+void QDeclarativeListCompositor::listItemsInserted(
+ QVector<Insert> *translatedInsertions,
+ void *list,
+ const QVector<QDeclarativeChangeSet::Insert> &insertions,
+ const QVector<MovedFlags> *movedFlags)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << insertions)
+ for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
+ if (it->list != list || it->flags == CacheFlag) {
+ it.incrementIndexes(it->count);
+ continue;
+ } else if (it->flags & MovedFlag) {
+ it->flags &= ~MovedFlag;
+ it.incrementIndexes(it->count);
+ continue;
+ }
+ foreach (const QDeclarativeChangeSet::Insert &insertion, insertions) {
+ int offset = insertion.index - it->index;
+ if ((offset > 0 && offset < it->count)
+ || (offset == 0 && it->prepend())
+ || (offset == it->count && it->append())) {
+ if (it->prepend()) {
+ int flags = m_defaultFlags;
+ if (insertion.isMove()) {
+ for (QVector<MovedFlags>::const_iterator move = movedFlags->begin();
+ move != movedFlags->end();
+ ++move) {
+ if (move->moveId == insertion.moveId) {
+ flags = move->flags;
+ break;
+ }
+ }
+ }
+ if (flags & ~(AppendFlag | PrependFlag)) {
+ Insert translatedInsert(it, insertion.count, flags, insertion.moveId);
+ for (int i = 0; i < m_groupCount; ++i) {
+ if (it->inGroup(i))
+ translatedInsert.index[i] += offset;
+ }
+ translatedInsertions->append(translatedInsert);
+ }
+ if ((it->flags & ~AppendFlag) == flags) {
+ it->count += insertion.count;
+ } else if (offset == 0
+ && it->previous != &m_ranges
+ && it->previous->list == list
+ && it->previous->end() == insertion.index
+ && it->previous->flags == flags) {
+ it->previous->count += insertion.count;
+ it->index += insertion.count;
+ it.incrementIndexes(insertion.count);
+ } else {
+ if (offset > 0) {
+ it.incrementIndexes(offset);
+ *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
+ }
+ *it = insert(*it, it->list, insertion.index, insertion.count, flags)->next;
+ it.incrementIndexes(insertion.count, flags);
+ it->index += offset + insertion.count;
+ it->count -= offset;
+ }
+ m_end.incrementIndexes(insertion.count, flags);
+ } else {
+ if (offset > 0) {
+ *it = insert(*it, it->list, it->index, offset, it->flags)->next;
+ it->index += offset;
+ it->count -= offset;
+ }
+ it->index += insertion.count;
+ }
+ } else if (offset <= 0) {
+ it->index += insertion.count;
+ }
+ }
+ it.incrementIndexes(it->count);
+ }
+ m_cacheIt = m_end;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+void QDeclarativeListCompositor::listItemsInserted(
+ void *list, int index, int count, QVector<Insert> *translatedInsertions)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << index << count)
+ Q_ASSERT(count > 0);
+
+ QVector<QDeclarativeChangeSet::Insert> insertions;
+ insertions.append(QDeclarativeChangeSet::Insert(index, count));
+
+ listItemsInserted(translatedInsertions, list, insertions);
+}
+
+void QDeclarativeListCompositor::listItemsRemoved(
+ QVector<Remove> *translatedRemovals,
+ void *list,
+ QVector<QDeclarativeChangeSet::Remove> *removals,
+ QVector<QDeclarativeChangeSet::Insert> *insertions,
+ QVector<MovedFlags> *movedFlags, int moveId)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << *removals)
+
+ for (iterator it(m_ranges.next, 0, Default, m_groupCount);
+ *it != &m_ranges && !removals->isEmpty();
+ *it = it->next) {
+ if (it->list != list || it->flags == CacheFlag) {
+ it.incrementIndexes(it->count);
+ continue;
+ }
+ bool removed = false;
+ for (QVector<QDeclarativeChangeSet::Remove>::iterator removal = removals->begin();
+ !removed && removal != removals->end();
+ ++removal) {
+ int relativeIndex = removal->index - it->index;
+ int itemsRemoved = removal->count;
+ if (relativeIndex + removal->count > 0 && relativeIndex < it->count) {
+ const int offset = qMax(0, relativeIndex);
+ int removeCount = qMin(it->count, relativeIndex + removal->count) - offset;
+ it->count -= removeCount;
+ int removeFlags = it->flags & m_removeFlags;
+ Remove translatedRemoval(it, removeCount, it->flags);
+ for (int i = 0; i < m_groupCount; ++i) {
+ if (it->inGroup(i))
+ translatedRemoval.index[i] += offset;
+ }
+ if (removal->isMove()) {
+ QVector<QDeclarativeChangeSet::Insert>::iterator insertion = insertions->begin();
+ for (; insertion != insertions->end() && insertion->moveId != removal->moveId;
+ ++insertion) {}
+ Q_ASSERT(insertion != insertions->end());
+ Q_ASSERT(insertion->count == removal->count);
+
+ if (relativeIndex < 0) {
+ int splitMoveId = ++moveId;
+ removal = removals->insert(removal, QDeclarativeChangeSet::Remove(
+ removal->index, -relativeIndex, splitMoveId));
+ ++removal;
+ removal->count -= -relativeIndex;
+ insertion = insertions->insert(insertion, QDeclarativeChangeSet::Insert(
+ insertion->index, -relativeIndex, splitMoveId));
+ ++insertion;
+ insertion->index += -relativeIndex;
+ insertion->count -= -relativeIndex;
+ }
+
+ if (it->prepend()) {
+ removeFlags |= it->flags & CacheFlag;
+ translatedRemoval.moveId = ++moveId;
+ movedFlags->append(MovedFlags(moveId, it->flags & ~AppendFlag));
+
+ removal = removals->insert(removal, QDeclarativeChangeSet::Remove(
+ removal->index, removeCount, translatedRemoval.moveId));
+ ++removal;
+ insertion = insertions->insert(insertion, QDeclarativeChangeSet::Insert(
+ insertion->index, removeCount, translatedRemoval.moveId));
+ ++insertion;
+
+ removal->count -= removeCount;
+ insertion->index += removeCount;
+ insertion->count -= removeCount;
+ if (removal->count == 0) {
+ removal = removals->erase(removal);
+ insertion = insertions->erase(insertion);
+ --removal;
+ --insertion;
+ }
+ } else {
+ if (offset > 0) {
+ *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
+ it->index += offset;
+ it->count -= offset;
+ it.incrementIndexes(offset);
+ }
+ if (it->previous != &m_ranges
+ && it->previous->list == it->list
+ && it->end() == insertion->index
+ && it->previous->flags == (it->flags | MovedFlag)) {
+ it->previous->count += removeCount;
+ } else {
+ *it = insert(*it, it->list, insertion->index, removeCount, it->flags | MovedFlag)->next;
+ }
+ translatedRemoval.flags = 0;
+ removeFlags = 0;
+ }
+ } else if (it->inCache()) {
+ if (offset > 0) {
+ *it = insert(*it, it->list, it->index, offset, it->flags & ~AppendFlag)->next;
+ it->index += offset;
+ it->count -= offset;
+ it.incrementIndexes(offset);
+ }
+ if (it->previous != &m_ranges
+ && it->previous->list == it->list
+ && it->previous->flags == CacheFlag) {
+ it->previous->count += removeCount;
+ } else {
+ *it = insert(*it, it->list, -1, removeCount, CacheFlag)->next;
+ }
+ it.index[Cache] += removeCount;
+ }
+ if (removeFlags & GroupMask)
+ translatedRemovals->append(translatedRemoval);
+ m_end.decrementIndexes(removeCount, removeFlags);
+ if (it->count == 0 && !it->append()) {
+ *it = erase(*it)->previous;
+ removed = true;
+ } else if (relativeIndex <= 0) {
+ it->index = removal->index;
+ }
+ } else if (relativeIndex < 0) {
+ it->index -= itemsRemoved;
+
+ if (it->previous != &m_ranges
+ && it->previous->list == it->list
+ && it->previous->end() == it->index
+ && it->previous->flags == (it->flags & ~AppendFlag)) {
+ it->previous->count += it->count;
+ it->previous->flags = it->flags;
+ it.incrementIndexes(it->count);
+ *it = erase(*it);
+ removed = true;
+ }
+ }
+ }
+ if (it->flags == CacheFlag && it->next->flags == CacheFlag && it->next->list == it->list) {
+ it.index[Cache] += it->next->count;
+ it->count += it->next->count;
+ erase(it->next);
+ } else if (!removed) {
+ it.incrementIndexes(it->count);
+ }
+ }
+ m_cacheIt = m_end;
+ QT_DECLARATIVE_VERIFY_LISTCOMPOSITOR
+}
+
+void QDeclarativeListCompositor::listItemsRemoved(
+ void *list, int index, int count, QVector<Remove> *translatedRemovals)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << index << count)
+ Q_ASSERT(count >= 0);
+
+ QVector<QDeclarativeChangeSet::Remove> removals;
+ removals.append(QDeclarativeChangeSet::Remove(index, count));
+ listItemsRemoved(translatedRemovals, list, &removals, 0, 0, 0);
+}
+
+void QDeclarativeListCompositor::listItemsMoved(
+ void *list,
+ int from,
+ int to,
+ int count,
+ QVector<Remove> *translatedRemovals,
+ QVector<Insert> *translatedInsertions)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << from << to << count)
+ Q_ASSERT(count >= 0);
+
+ QVector<QDeclarativeChangeSet::Remove> removals;
+ QVector<QDeclarativeChangeSet::Insert> insertions;
+ QVector<MovedFlags> movedFlags;
+ removals.append(QDeclarativeChangeSet::Remove(from, count, 0));
+ insertions.append(QDeclarativeChangeSet::Insert(to, count, 0));
+
+ listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags, 0);
+ listItemsInserted(translatedInsertions, list, insertions, &movedFlags);
+}
+
+void QDeclarativeListCompositor::listItemsChanged(
+ QVector<Change> *translatedChanges,
+ void *list,
+ const QVector<QDeclarativeChangeSet::Change> &changes)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << changes)
+ for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
+ if (it->list != list || it->flags == CacheFlag) {
+ it.incrementIndexes(it->count);
+ continue;
+ } else if (!it->inGroup()) {
+ continue;
+ }
+ foreach (const QDeclarativeChangeSet::Change &change, changes) {
+ const int offset = change.index - it->index;
+ if (offset + change.count > 0 && offset < it->count) {
+ const int changeOffset = qMax(0, offset);
+ const int changeCount = qMin(it->count, offset + change.count) - changeOffset;
+
+ Change translatedChange(it, changeCount, it->flags);
+ for (int i = 0; i < m_groupCount; ++i) {
+ if (it->inGroup(i))
+ translatedChange.index[i] += changeOffset;
+ }
+ translatedChanges->append(translatedChange);
+ }
+ }
+ it.incrementIndexes(it->count);
+ }
+}
+
+void QDeclarativeListCompositor::listItemsChanged(
+ void *list, int index, int count, QVector<Change> *translatedChanges)
+{
+ QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << index << count)
+ Q_ASSERT(count >= 0);
+ QVector<QDeclarativeChangeSet::Change> changes;
+ changes.append(QDeclarativeChangeSet::Change(index, count));
+ listItemsChanged(translatedChanges, list, changes);
+}
+
+void QDeclarativeListCompositor::listChanged(
+ void *list,
+ const QDeclarativeChangeSet &changeSet,
+ QVector<Remove> *translatedRemovals,
+ QVector<Insert> *translatedInsertions,
+ QVector<Change> *translatedChanges)
+{
+ QVector<QDeclarativeChangeSet::Remove> removals = changeSet.removes();
+ QVector<QDeclarativeChangeSet::Insert> insertions = changeSet.inserts();
+ QVector<MovedFlags> movedFlags;
+ listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags, changeSet.moveCounter());
+ listItemsInserted(translatedInsertions, list, insertions, &movedFlags);
+ listItemsChanged(translatedChanges, list, changeSet.changes());
+}
+
+void QDeclarativeListCompositor::transition(
+ Group from,
+ Group to,
+ QVector<QDeclarativeChangeSet::Remove> *removes,
+ QVector<QDeclarativeChangeSet::Insert> *inserts)
+{
+ int removeCount = 0;
+ for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) {
+ if (it == from && it != to) {
+ removes->append(QDeclarativeChangeSet::Remove(it.index[from]- removeCount, it->count));
+ removeCount += it->count;
+ } else if (it != from && it == to) {
+ inserts->append(QDeclarativeChangeSet::Insert(it.index[to], it->count));
+ }
+ it.incrementIndexes(it->count);
+ }
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Group &group)
+{
+ switch (group) {
+ case QDeclarativeListCompositor::Cache: return debug << "Cache";
+ case QDeclarativeListCompositor::Default: return debug << "Default";
+ default: return (debug.nospace() << "Group" << int(group)).space();
+ }
+
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Range &range)
+{
+ (debug.nospace()
+ << "Range("
+ << range.list) << " "
+ << range.index << " "
+ << range.count << " "
+ << (range.append() ? "A" : "0")
+ << (range.prepend() ? "P" : "0");
+ for (int i = QDeclarativeListCompositor::MaximumGroupCount - 1; i >= 2; --i)
+ debug << (range.inGroup(i) ? "1" : "0");
+ return (debug
+ << (range.inGroup(QDeclarativeListCompositor::Default) ? "D" : "0")
+ << (range.inGroup(QDeclarativeListCompositor::Cache) ? "C" : "0"));
+}
+
+static void qt_print_indexes(QDebug &debug, int count, const int *indexes)
+{
+ for (int i = count - 1; i >= 0; --i)
+ debug << indexes[i];
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::iterator &it)
+{
+ (debug.nospace() << "iterator(" << it.group).space() << "offset:" << it.offset;
+ qt_print_indexes(debug, it.groupCount, it.index);
+ return ((debug << **it).nospace() << ")").space();
+}
+
+static QDebug qt_print_change(QDebug debug, const char *name, const QDeclarativeListCompositor::Change &change)
+{
+ debug.nospace() << name << "(" << change.moveId << " " << change.count << " ";
+ for (int i = QDeclarativeListCompositor::MaximumGroupCount - 1; i >= 2; --i)
+ debug << (change.inGroup(i) ? "1" : "0");
+ debug << (change.inGroup(QDeclarativeListCompositor::Default) ? "D" : "0")
+ << (change.inGroup(QDeclarativeListCompositor::Cache) ? "C" : "0");
+ int i = QDeclarativeListCompositor::MaximumGroupCount - 1;
+ for (; i >= 0 && !change.inGroup(i); --i) {}
+ for (; i >= 0; --i)
+ debug << " " << change.index[i];
+ return (debug << ")").maybeSpace();
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Change &change)
+{
+ return qt_print_change(debug, "Change", change);
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Remove &remove)
+{
+ return qt_print_change(debug, "Remove", remove);
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Insert &insert)
+{
+ return qt_print_change(debug, "Insert", insert);
+}
+
+QDebug operator <<(QDebug debug, const QDeclarativeListCompositor &list)
+{
+ int indexes[QDeclarativeListCompositor::MaximumGroupCount];
+ for (int i = 0; i < QDeclarativeListCompositor::MaximumGroupCount; ++i)
+ indexes[i] = 0;
+ debug.nospace() << "QDeclarativeListCompositor(";
+ qt_print_indexes(debug, list.m_groupCount, list.m_end.index);
+ for (QDeclarativeListCompositor::Range *range = list.m_ranges.next; range != &list.m_ranges; range = range->next) {
+ (debug << "\n").space();
+ qt_print_indexes(debug, list.m_groupCount, indexes);
+ debug << " " << *range;
+
+ for (int i = 0; i < list.m_groupCount; ++i) {
+ if (range->inGroup(i))
+ indexes[i] += range->count;
+ }
+ }
+ return (debug << ")").maybeSpace();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativelistcompositor_p.h b/src/quick/util/qdeclarativelistcompositor_p.h
new file mode 100644
index 0000000000..c808f6fe80
--- /dev/null
+++ b/src/quick/util/qdeclarativelistcompositor_p.h
@@ -0,0 +1,371 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVELISTCOMPOSITOR_P_H
+#define QDECLARATIVELISTCOMPOSITOR_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 <QtCore/qglobal.h>
+#include <QtCore/qvector.h>
+
+#include <private/qdeclarativechangeset_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QDeclarativeListCompositor
+{
+public:
+ enum { MaximumGroupCount = 11 };
+
+ enum Group
+ {
+ Cache = 0,
+ Default = 1,
+ Persisted = 2
+ };
+
+ enum Flag
+ {
+ CacheFlag = 0x000001,
+ DefaultFlag = 0x000002,
+ PersistedFlag = 0x000004,
+ GroupMask = 0x00FFFE,
+ PrependFlag = 0x100000,
+ AppendFlag = 0x200000,
+ MovedFlag = 0x400000
+ };
+
+ class Range
+ {
+ public:
+ Range() : next(this), previous(this), list(0), index(0), count(0), flags(0) {}
+ Range(Range *next, void *list, int index, int count, uint flags)
+ : next(next), previous(next->previous), list(list), index(index), count(count), flags(flags) {
+ next->previous = this; previous->next = this; }
+
+ Range *next;
+ Range *previous;
+ void *list;
+ int index;
+ int count;
+ int flags;
+
+ inline int start() const { return index; }
+ inline int end() const { return index + count; }
+
+ inline int groups() const { return flags & GroupMask; }
+
+ inline bool inGroup() const { return flags & GroupMask; }
+ inline bool inCache() const { return flags & CacheFlag; }
+ inline bool inGroup(int group) const { return flags & (1 << group); }
+
+ inline bool prepend() const { return flags & PrependFlag; }
+ inline bool append() const { return flags & AppendFlag; }
+ };
+
+ class Q_AUTOTEST_EXPORT iterator
+ {
+ public:
+ inline iterator();
+ inline iterator(const iterator &it);
+ inline iterator(Range *range, int offset, Group group, int groupCount);
+ inline ~iterator() {}
+
+ bool operator ==(const iterator &it) const { return range == it.range && offset == it.offset; }
+ bool operator !=(const iterator &it) const { return range != it.range || offset != it.offset; }
+
+ bool operator ==(Group group) const { return range->flags & (1 << group); }
+ bool operator !=(Group group) const { return !(range->flags & (1 << group)); }
+
+ Range *&operator *() { return range; }
+ Range * const &operator *() const { return range; }
+ Range *operator ->() { return range; }
+ const Range *operator ->() const { return range; }
+
+ iterator &operator +=(int difference);
+ iterator &operator -=(int difference);
+
+ template<typename T> T *list() const { return static_cast<T *>(range->list); }
+ int modelIndex() const { return range->index + offset; }
+
+ void incrementIndexes(int difference) { incrementIndexes(difference, range->flags); }
+ void decrementIndexes(int difference) { decrementIndexes(difference, range->flags); }
+
+ inline void incrementIndexes(int difference, int flags);
+ inline void decrementIndexes(int difference, int flags);
+
+ void setGroup(Group g) { group = g; groupFlag = 1 << g; }
+
+ Range *range;
+ int offset;
+ Group group;
+ int groupFlag;
+ int groupCount;
+ union {
+ struct {
+ int cacheIndex;
+ };
+ int index[MaximumGroupCount];
+ };
+ };
+
+ class Q_AUTOTEST_EXPORT insert_iterator : public iterator
+ {
+ public:
+ inline insert_iterator() {}
+ inline insert_iterator(const iterator &it) : iterator(it) {}
+ inline insert_iterator(Range *, int, Group, int);
+ inline ~insert_iterator() {}
+
+ insert_iterator &operator +=(int difference);
+ insert_iterator &operator -=(int difference);
+ };
+
+ struct Change
+ {
+ inline Change() {}
+ inline Change(iterator it, int count, int flags, int moveId = -1);
+ int count;
+ int flags;
+ int moveId;
+ union {
+ struct {
+ int cacheIndex;
+ };
+ int index[MaximumGroupCount];
+ };
+
+ inline bool isMove() const { return moveId >= 0; }
+ inline bool inCache() const { return flags & CacheFlag; }
+ inline bool inGroup() const { return flags & GroupMask; }
+ inline bool inGroup(int group) const { return flags & (CacheFlag << group); }
+
+ inline int groups() const { return flags & GroupMask; }
+ };
+
+ struct Insert : public Change
+ {
+ Insert() {}
+ Insert(iterator it, int count, int flags, int moveId = -1)
+ : Change(it, count, flags, moveId) {}
+ };
+
+ struct Remove : public Change
+ {
+ Remove() {}
+ Remove(iterator it, int count, int flags, int moveId = -1)
+ : Change(it, count, flags, moveId) {}
+ };
+
+ QDeclarativeListCompositor();
+ ~QDeclarativeListCompositor();
+
+ int defaultGroups() const { return m_defaultFlags & ~PrependFlag; }
+ void setDefaultGroups(int groups) { m_defaultFlags = groups | PrependFlag; }
+ void setDefaultGroup(Group group) { m_defaultFlags |= (1 << group); }
+ void clearDefaultGroup(Group group) { m_defaultFlags &= ~(1 << group); }
+ void setRemoveGroups(int groups) { m_removeFlags = PrependFlag | AppendFlag | groups; }
+ void setGroupCount(int count);
+
+ int count(Group group) const;
+ iterator find(Group group, int index);
+ iterator find(Group group, int index) const;
+ insert_iterator findInsertPosition(Group group, int index);
+
+ iterator begin(Group group);
+ const iterator &end() { return m_end; }
+
+ void append(void *list, int index, int count, int flags, QVector<Insert> *inserts = 0);
+ void insert(Group group, int before, void *list, int index, int count, int flags, QVector<Insert> *inserts = 0);
+ iterator insert(iterator before, void *list, int index, int count, int flags, QVector<Insert> *inserts = 0);
+
+ void setFlags(Group group, int index, int count, int flags, QVector<Insert> *inserts = 0);
+ void setFlags(iterator from, int count, int flags, QVector<Insert> *inserts = 0);
+
+ void clearFlags(Group group, int index, int count, int flags, QVector<Remove> *removals = 0);
+ void clearFlags(iterator from, int count, int flags, QVector<Remove> *removals = 0);
+
+ void removeList(void *list, QVector<Remove> *removals, bool destroyed);
+
+ bool verifyMoveTo(Group fromGroup, int from, Group toGroup, int to, int count) const;
+
+ void move(
+ Group fromGroup,
+ int from,
+ Group toGroup,
+ int to,
+ int count,
+ QVector<Remove> *removals = 0,
+ QVector<Insert> *inserts = 0);
+ void clear();
+
+ void listItemsInserted(void *list, int index, int count, QVector<Insert> *inserts);
+ void listItemsRemoved(void *list, int index, int count, QVector<Remove> *removals);
+ void listItemsMoved(void *list, int from, int to, int count, QVector<Remove> *removals, QVector<Insert> *inserts);
+ void listItemsChanged(void *list, int index, int count, QVector<Change> *changes);
+ void listChanged(
+ void *list,
+ const QDeclarativeChangeSet &changeSet,
+ QVector<Remove> *removals,
+ QVector<Insert> *inserts,
+ QVector<Change> *changes);
+
+ void transition(
+ Group from,
+ Group to,
+ QVector<QDeclarativeChangeSet::Remove> *removes,
+ QVector<QDeclarativeChangeSet::Insert> *inserts);
+
+private:
+ Range m_ranges;
+ iterator m_end;
+ iterator m_cacheIt;
+ int m_groupCount;
+ int m_defaultFlags;
+ int m_removeFlags;
+
+ inline Range *insert(Range *before, void *list, int index, int count, int flags);
+ inline Range *erase(Range *range);
+
+ struct MovedFlags
+ {
+ MovedFlags() {}
+ MovedFlags(int moveId, int flags) : moveId(moveId), flags(flags) {}
+
+ int moveId;
+ int flags;
+ };
+
+ void listItemsRemoved(
+ QVector<Remove> *translatedRemovals,
+ void *list,
+ QVector<QDeclarativeChangeSet::Remove> *removals,
+ QVector<QDeclarativeChangeSet::Insert> *insertions = 0,
+ QVector<MovedFlags> *movedFlags = 0,
+ int moveId = 0);
+ void listItemsInserted(
+ QVector<Insert> *translatedInsertions,
+ void *list,
+ const QVector<QDeclarativeChangeSet::Insert> &insertions,
+ const QVector<MovedFlags> *movedFlags = 0);
+ void listItemsChanged(
+ QVector<Change> *translatedChanges,
+ void *list,
+ const QVector<QDeclarativeChangeSet::Change> &changes);
+
+ friend Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor &list);
+};
+
+inline QDeclarativeListCompositor::iterator::iterator()
+ : range(0), offset(0), group(Default), groupCount(0) {}
+inline QDeclarativeListCompositor::iterator::iterator(const iterator &it)
+ : range(it.range)
+ , offset(it.offset)
+ , group(it.group)
+ , groupFlag(it.groupFlag)
+ , groupCount(it.groupCount)
+{
+ for (int i = 0; i < groupCount; ++i)
+ index[i] = it.index[i];
+}
+
+inline QDeclarativeListCompositor::iterator::iterator(
+ Range *range, int offset, Group group, int groupCount)
+ : range(range)
+ , offset(offset)
+ , group(group)
+ , groupFlag(1 << group)
+ , groupCount(groupCount)
+{
+ for (int i = 0; i < groupCount; ++i)
+ index[i] = 0;
+}
+
+inline void QDeclarativeListCompositor::iterator::incrementIndexes(int difference, int flags)
+{
+ for (int i = 0; i < groupCount; ++i) {
+ if (flags & (1 << i))
+ index[i] += difference;
+ }
+}
+
+inline void QDeclarativeListCompositor::iterator::decrementIndexes(int difference, int flags)
+{
+ for (int i = 0; i < groupCount; ++i) {
+ if (flags & (1 << i))
+ index[i] -= difference;
+ }
+}
+
+inline QDeclarativeListCompositor::insert_iterator::insert_iterator(
+ Range *range, int offset, Group group, int groupCount)
+ : iterator(range, offset, group, groupCount) {}
+
+inline QDeclarativeListCompositor::Change::Change(iterator it, int count, int flags, int moveId)
+ : count(count), flags(flags), moveId(moveId)
+{
+ for (int i = 0; i < MaximumGroupCount; ++i)
+ index[i] = it.index[i];
+}
+
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Group &group);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Range &range);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::iterator &it);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Change &change);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Remove &remove);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor::Insert &insert);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QDeclarativeListCompositor &list);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/util/qdeclarativepackage.cpp b/src/quick/util/qdeclarativepackage.cpp
new file mode 100644
index 0000000000..1d46574f02
--- /dev/null
+++ b/src/quick/util/qdeclarativepackage.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepackage_p.h"
+
+#include <private/qobject_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Package QDeclarativePackage
+ \inqmlmodule QtQuick 2
+ \ingroup qml-working-with-data
+ \brief Package provides a collection of named items.
+
+ The Package class is used in conjunction with
+ VisualDataModel to enable delegates with a shared context
+ to be provided to multiple views.
+
+ Any item within a Package may be assigned a name via the
+ \l{Package::name}{Package.name} attached property.
+
+ The example below creates a Package containing two named items;
+ \e list and \e grid. The third element in the package (the \l Rectangle) is parented to whichever
+ delegate it should appear in. This allows an item to move
+ between views.
+
+ \snippet examples/declarative/modelviews/package/Delegate.qml 0
+
+ These named items are used as the delegates by the two views who
+ reference the special \l{VisualDataModel::parts} property to select
+ a model which provides the chosen delegate.
+
+ \snippet examples/declarative/modelviews/package/view.qml 0
+
+ \sa {declarative/modelviews/package}{Package example}, {declarative/photoviewer}{Photo Viewer example}, QtDeclarative
+*/
+
+/*!
+ \qmlattachedproperty string QtQuick2::Package::name
+ This attached property holds the name of an item within a Package.
+*/
+
+
+class QDeclarativePackagePrivate : public QObjectPrivate
+{
+public:
+ QDeclarativePackagePrivate() {}
+
+ struct DataGuard : public QDeclarativeGuard<QObject>
+ {
+ DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QDeclarativeGuard<QObject>&)*this = obj; }
+ QList<DataGuard> *list;
+ void objectDestroyed(QObject *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+
+ QList<DataGuard> dataList;
+ static void data_append(QDeclarativeListProperty<QObject> *prop, QObject *o) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->append(DataGuard(o, list));
+ }
+ static void data_clear(QDeclarativeListProperty<QObject> *prop) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->clear();
+ }
+ static QObject *data_at(QDeclarativeListProperty<QObject> *prop, int index) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ return list->at(index);
+ }
+ static int data_count(QDeclarativeListProperty<QObject> *prop) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ return list->count();
+ }
+};
+
+QHash<QObject *, QDeclarativePackageAttached *> QDeclarativePackageAttached::attached;
+
+QDeclarativePackageAttached::QDeclarativePackageAttached(QObject *parent)
+: QObject(parent)
+{
+ attached.insert(parent, this);
+}
+
+QDeclarativePackageAttached::~QDeclarativePackageAttached()
+{
+ attached.remove(parent());
+}
+
+QString QDeclarativePackageAttached::name() const
+{
+ return _name;
+}
+
+void QDeclarativePackageAttached::setName(const QString &n)
+{
+ _name = n;
+}
+
+QDeclarativePackage::QDeclarativePackage(QObject *parent)
+ : QObject(*(new QDeclarativePackagePrivate), parent)
+{
+}
+
+QDeclarativePackage::~QDeclarativePackage()
+{
+ Q_D(QDeclarativePackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ obj->setParent(this);
+ }
+}
+
+QDeclarativeListProperty<QObject> QDeclarativePackage::data()
+{
+ Q_D(QDeclarativePackage);
+ return QDeclarativeListProperty<QObject>(this, &d->dataList, QDeclarativePackagePrivate::data_append,
+ QDeclarativePackagePrivate::data_count,
+ QDeclarativePackagePrivate::data_at,
+ QDeclarativePackagePrivate::data_clear);
+}
+
+bool QDeclarativePackage::hasPart(const QString &name)
+{
+ Q_D(QDeclarativePackage);
+ for (int ii = 0; ii < d->dataList.count(); ++ii) {
+ QObject *obj = d->dataList.at(ii);
+ QDeclarativePackageAttached *a = QDeclarativePackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return true;
+ }
+ return false;
+}
+
+QObject *QDeclarativePackage::part(const QString &name)
+{
+ Q_D(QDeclarativePackage);
+ 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);
+ QDeclarativePackageAttached *a = QDeclarativePackageAttached::attached.value(obj);
+ if (a && a->name() == name)
+ return obj;
+ }
+
+ if (name == QLatin1String("default") && !d->dataList.isEmpty())
+ return d->dataList.at(0);
+
+ return 0;
+}
+
+QDeclarativePackageAttached *QDeclarativePackage::qmlAttachedProperties(QObject *o)
+{
+ return new QDeclarativePackageAttached(o);
+}
+
+
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativepackage_p.h b/src/quick/util/qdeclarativepackage_p.h
new file mode 100644
index 0000000000..76797430ce
--- /dev/null
+++ b/src/quick/util/qdeclarativepackage_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPACKAGE_H
+#define QDECLARATIVEPACKAGE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePackagePrivate;
+class QDeclarativePackageAttached;
+class Q_AUTOTEST_EXPORT QDeclarativePackage : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePackage)
+
+ Q_CLASSINFO("DefaultProperty", "data")
+ Q_PROPERTY(QDeclarativeListProperty<QObject> data READ data)
+
+public:
+ QDeclarativePackage(QObject *parent=0);
+ virtual ~QDeclarativePackage();
+
+ QDeclarativeListProperty<QObject> data();
+
+ QObject *part(const QString & = QString());
+ bool hasPart(const QString &);
+
+ static QDeclarativePackageAttached *qmlAttachedProperties(QObject *);
+};
+
+class QDeclarativePackageAttached : public QObject
+{
+Q_OBJECT
+Q_PROPERTY(QString name READ name WRITE setName)
+public:
+ QDeclarativePackageAttached(QObject *parent);
+ virtual ~QDeclarativePackageAttached();
+
+ QString name() const;
+ void setName(const QString &n);
+
+ static QHash<QObject *, QDeclarativePackageAttached *> attached;
+private:
+ QString _name;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePackage)
+QML_DECLARE_TYPEINFO(QDeclarativePackage, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPACKAGE_H
diff --git a/src/quick/util/qdeclarativepath.cpp b/src/quick/util/qdeclarativepath.cpp
new file mode 100644
index 0000000000..2ba7c372e2
--- /dev/null
+++ b/src/quick/util/qdeclarativepath.cpp
@@ -0,0 +1,1484 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepath_p.h"
+#include "qdeclarativepath_p_p.h"
+#include "qdeclarativesvgparser_p.h"
+
+#include <QSet>
+#include <QTime>
+
+#include <private/qbezier_p.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass PathElement QDeclarativePathElement
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief PathElement is the base path type.
+
+ This type is the base for all path types. It cannot
+ be instantiated.
+
+ \sa Path, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+
+/*!
+ \qmlclass Path QDeclarativePath
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief A Path object defines a path for use by \l PathView.
+
+ A Path is composed of one or more path segments - PathLine, PathQuad,
+ PathCubic.
+
+ The spacing of the items along the Path can be adjusted via a
+ PathPercent object.
+
+ PathAttribute allows named attributes with values to be defined
+ along the path.
+
+ \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+QDeclarativePath::QDeclarativePath(QObject *parent)
+ : QObject(*(new QDeclarativePathPrivate), parent)
+{
+}
+
+QDeclarativePath::~QDeclarativePath()
+{
+}
+
+/*!
+ \qmlproperty real QtQuick2::Path::startX
+ \qmlproperty real QtQuick2::Path::startY
+ These properties hold the starting position of the path.
+*/
+qreal QDeclarativePath::startX() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startX.isNull ? 0 : d->startX.value;
+}
+
+void QDeclarativePath::setStartX(qreal x)
+{
+ Q_D(QDeclarativePath);
+ if (d->startX.isValid() && qFuzzyCompare(x, d->startX))
+ return;
+ d->startX = x;
+ emit startXChanged();
+ processPath();
+}
+
+bool QDeclarativePath::hasStartX() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startX.isValid();
+}
+
+qreal QDeclarativePath::startY() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startY.isNull ? 0 : d->startY.value;
+}
+
+void QDeclarativePath::setStartY(qreal y)
+{
+ Q_D(QDeclarativePath);
+ if (d->startY.isValid() && qFuzzyCompare(y, d->startY))
+ return;
+ d->startY = y;
+ emit startYChanged();
+ processPath();
+}
+
+bool QDeclarativePath::hasStartY() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startY.isValid();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::Path::closed
+ This property holds whether the start and end of the path are identical.
+*/
+bool QDeclarativePath::isClosed() const
+{
+ Q_D(const QDeclarativePath);
+ return d->closed;
+}
+
+bool QDeclarativePath::hasEnd() const
+{
+ Q_D(const QDeclarativePath);
+ for (int i = d->_pathElements.count() - 1; i > -1; --i) {
+ if (QDeclarativeCurve *curve = qobject_cast<QDeclarativeCurve *>(d->_pathElements.at(i))) {
+ if ((!curve->hasX() && !curve->hasRelativeX()) || (!curve->hasY() && !curve->hasRelativeY()))
+ return false;
+ else
+ return true;
+ }
+ }
+ return hasStartX() && hasStartY();
+}
+
+/*!
+ \qmlproperty list<PathElement> QtQuick2::Path::pathElements
+ This property holds the objects composing the path.
+
+ \default
+
+ A path can contain the following path objects:
+ \list
+ \i \l PathLine - a straight line to a given position.
+ \i \l PathQuad - a quadratic Bezier curve to a given position with a control point.
+ \i \l PathCubic - a cubic Bezier curve to a given position with two control points.
+ \i \l PathAttribute - an attribute at a given position in the path.
+ \i \l PathPercent - a way to spread out items along various segments of the path.
+ \endlist
+
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 2
+*/
+
+QDeclarativeListProperty<QDeclarativePathElement> QDeclarativePath::pathElements()
+{
+ Q_D(QDeclarativePath);
+ return QDeclarativeListProperty<QDeclarativePathElement>(this, d->_pathElements);
+}
+
+void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
+{
+ Q_D(QDeclarativePath);
+ interpolate(d->_attributePoints, idx, name, value);
+}
+
+void QDeclarativePath::interpolate(QList<AttributePoint> &attributePoints, int idx, const QString &name, qreal value)
+{
+ if (!idx)
+ return;
+
+ qreal lastValue = 0;
+ qreal lastPercent = 0;
+ int search = idx - 1;
+ while(search >= 0) {
+ const AttributePoint &point = attributePoints.at(search);
+ if (point.values.contains(name)) {
+ lastValue = point.values.value(name);
+ lastPercent = point.origpercent;
+ break;
+ }
+ --search;
+ }
+
+ ++search;
+
+ const AttributePoint &curPoint = attributePoints.at(idx);
+
+ for (int ii = search; ii < idx; ++ii) {
+ AttributePoint &point = attributePoints[ii];
+
+ qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
+ point.values.insert(name, val);
+ }
+}
+
+void QDeclarativePath::endpoint(const QString &name)
+{
+ Q_D(QDeclarativePath);
+ const AttributePoint &first = d->_attributePoints.first();
+ qreal val = first.values.value(name);
+ for (int ii = d->_attributePoints.count() - 1; ii >= 0; ii--) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if (point.values.contains(name)) {
+ for (int jj = ii + 1; jj < d->_attributePoints.count(); ++jj) {
+ AttributePoint &setPoint = d->_attributePoints[jj];
+ setPoint.values.insert(name, val);
+ }
+ return;
+ }
+ }
+}
+
+void QDeclarativePath::endpoint(QList<AttributePoint> &attributePoints, const QString &name)
+{
+ const AttributePoint &first = attributePoints.first();
+ qreal val = first.values.value(name);
+ for (int ii = attributePoints.count() - 1; ii >= 0; ii--) {
+ const AttributePoint &point = attributePoints.at(ii);
+ if (point.values.contains(name)) {
+ for (int jj = ii + 1; jj < attributePoints.count(); ++jj) {
+ AttributePoint &setPoint = attributePoints[jj];
+ setPoint.values.insert(name, val);
+ }
+ return;
+ }
+ }
+}
+
+static QString percentString(QLatin1String("_qfx_percent"));
+
+void QDeclarativePath::processPath()
+{
+ Q_D(QDeclarativePath);
+
+ if (!d->componentComplete)
+ return;
+
+ d->_pointCache.clear();
+ d->prevBez.isValid = false;
+
+ d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
+
+ emit changed();
+}
+
+QPainterPath QDeclarativePath::createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed)
+{
+ Q_D(QDeclarativePath);
+
+ pathLength = 0;
+ attributePoints.clear();
+
+ if (!d->componentComplete)
+ return QPainterPath();
+
+ QPainterPath path;
+
+ AttributePoint first;
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ first.values[attributes.at(ii)] = 0;
+ attributePoints << first;
+
+ qreal startX = d->startX.isValid() ? d->startX.value : startPoint.x();
+ qreal startY = d->startY.isValid() ? d->startY.value : startPoint.y();
+ path.moveTo(startX, startY);
+
+ bool usesPercent = false;
+ int index = 0;
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativeCurve *curve = qobject_cast<QDeclarativeCurve *>(pathElement)) {
+ QDeclarativePathData data;
+ data.index = index;
+ data.endPoint = endPoint;
+ data.curves = d->_pathCurves;
+ curve->addToPath(path, data);
+ AttributePoint p;
+ p.origpercent = path.length();
+ attributePoints << p;
+ ++index;
+ } else if (QDeclarativePathAttribute *attribute = qobject_cast<QDeclarativePathAttribute *>(pathElement)) {
+ AttributePoint &point = attributePoints.last();
+ point.values[attribute->name()] = attribute->value();
+ interpolate(attributePoints, attributePoints.count() - 1, attribute->name(), attribute->value());
+ } else if (QDeclarativePathPercent *percent = qobject_cast<QDeclarativePathPercent *>(pathElement)) {
+ AttributePoint &point = attributePoints.last();
+ point.values[percentString] = percent->value();
+ interpolate(attributePoints, attributePoints.count() - 1, percentString, percent->value());
+ usesPercent = true;
+ }
+ }
+
+ // Fixup end points
+ const AttributePoint &last = attributePoints.last();
+ for (int ii = 0; ii < attributes.count(); ++ii) {
+ if (!last.values.contains(attributes.at(ii)))
+ endpoint(attributePoints, attributes.at(ii));
+ }
+ if (usesPercent && !last.values.contains(percentString)) {
+ d->_attributePoints.last().values[percentString] = 1;
+ interpolate(d->_attributePoints.count() - 1, percentString, 1);
+ }
+
+
+ // Adjust percent
+ qreal length = path.length();
+ qreal prevpercent = 0;
+ qreal prevorigpercent = 0;
+ for (int ii = 0; ii < attributePoints.count(); ++ii) {
+ const AttributePoint &point = attributePoints.at(ii);
+ if (point.values.contains(percentString)) { //special string for QDeclarativePathPercent
+ if ( ii > 0) {
+ qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
+ (point.values.value(percentString)-prevpercent);
+ attributePoints[ii].scale = scale;
+ }
+ attributePoints[ii].origpercent /= length;
+ attributePoints[ii].percent = point.values.value(percentString);
+ prevorigpercent = attributePoints[ii].origpercent;
+ prevpercent = attributePoints[ii].percent;
+ } else {
+ attributePoints[ii].origpercent /= length;
+ attributePoints[ii].percent = attributePoints[ii].origpercent;
+ }
+ }
+
+ if (closed) {
+ QPointF end = path.currentPosition();
+ *closed = length > 0 && startX == end.x() && startY == end.y();
+ }
+ pathLength = length;
+
+ return path;
+}
+
+void QDeclarativePath::classBegin()
+{
+ Q_D(QDeclarativePath);
+ d->componentComplete = false;
+}
+
+void QDeclarativePath::componentComplete()
+{
+ Q_D(QDeclarativePath);
+ QSet<QString> attrs;
+ d->componentComplete = true;
+
+ // First gather up all the attributes
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativeCurve *curve =
+ qobject_cast<QDeclarativeCurve *>(pathElement))
+ d->_pathCurves.append(curve);
+ else if (QDeclarativePathAttribute *attribute =
+ qobject_cast<QDeclarativePathAttribute *>(pathElement))
+ attrs.insert(attribute->name());
+ }
+ d->_attributes = attrs.toList();
+
+ processPath();
+
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements)
+ connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
+}
+
+QPainterPath QDeclarativePath::path() const
+{
+ Q_D(const QDeclarativePath);
+ return d->_path;
+}
+
+QStringList QDeclarativePath::attributes() const
+{
+ Q_D(const QDeclarativePath);
+ if (!d->componentComplete) {
+ QSet<QString> attrs;
+
+ // First gather up all the attributes
+ foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
+ if (QDeclarativePathAttribute *attribute =
+ qobject_cast<QDeclarativePathAttribute *>(pathElement))
+ attrs.insert(attribute->name());
+ }
+ return attrs.toList();
+ }
+ return d->_attributes;
+}
+
+static inline QBezier nextBezier(const QPainterPath &path, int *current, qreal *bezLength, bool reverse = false)
+{
+ const int lastElement = reverse ? 0 : path.elementCount() - 1;
+ const int start = reverse ? *current - 1 : *current + 1;
+ for (int i=start; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+
+ switch (e.type) {
+ case QPainterPath::MoveToElement:
+ break;
+ case QPainterPath::LineToElement:
+ {
+ QLineF line(path.elementAt(i-1), e);
+ *bezLength = line.length();
+ QPointF a = path.elementAt(i-1);
+ QPointF delta = e - a;
+ *current = i;
+ return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
+ }
+ case QPainterPath::CurveToElement:
+ {
+ QBezier b = QBezier::fromPoints(path.elementAt(i-1),
+ e,
+ path.elementAt(i+1),
+ path.elementAt(i+2));
+ *bezLength = b.length();
+ *current = i;
+ return b;
+ }
+ default:
+ break;
+ }
+ }
+ *current = lastElement;
+ *bezLength = 0;
+ return QBezier();
+}
+
+//derivative of the equation
+static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
+{
+ return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
+}
+
+void QDeclarativePath::createPointCache() const
+{
+ Q_D(const QDeclarativePath);
+ qreal pathLength = d->pathLength;
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return;
+ // more points means less jitter between items as they move along the
+ // path, but takes longer to generate
+ const int points = qCeil(pathLength*5);
+ const int lastElement = d->_path.elementCount() - 1;
+ d->_pointCache.resize(points+1);
+
+ int currElement = -1;
+ qreal bezLength = 0;
+ QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
+ qreal currLength = bezLength;
+ qreal epc = currLength / pathLength;
+
+ for (int i = 0; i < d->_pointCache.size(); i++) {
+ //find which set we are in
+ qreal prevPercent = 0;
+ qreal prevOrigPercent = 0;
+ for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ qreal percent = qreal(i)/points;
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if (percent < point.percent || ii == d->_attributePoints.count() - 1) { //### || is special case for very last item
+ qreal elementPercent = (percent - prevPercent);
+
+ qreal spc = prevOrigPercent + elementPercent * point.scale;
+
+ while (spc > epc) {
+ if (currElement > lastElement)
+ break;
+ currBez = nextBezier(d->_path, &currElement, &bezLength);
+ if (bezLength == 0.0) {
+ currLength = pathLength;
+ epc = 1.0;
+ break;
+ }
+ currLength += bezLength;
+ epc = currLength / pathLength;
+ }
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+ d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ break;
+ }
+ prevOrigPercent = point.origpercent;
+ prevPercent = point.percent;
+ }
+ }
+}
+
+QPointF QDeclarativePath::sequentialPointAt(qreal p, qreal *angle) const
+{
+ Q_D(const QDeclarativePath);
+ return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
+}
+
+QPointF QDeclarativePath::sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (!prevBez.isValid)
+ return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
+ forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
+
+ return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
+ forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
+}
+
+QPointF QDeclarativePath::forwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return path.pointAtPercent(0); //expensive?
+
+ const int lastElement = path.elementCount() - 1;
+ bool haveCachedBez = prevBez.isValid;
+ int currElement = haveCachedBez ? prevBez.element : -1;
+ qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
+ QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
+ qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
+ qreal epc = currLength / pathLength;
+
+ //find which set we are in
+ qreal prevPercent = 0;
+ qreal prevOrigPercent = 0;
+ for (int ii = 0; ii < attributePoints.count(); ++ii) {
+ qreal percent = p;
+ const AttributePoint &point = attributePoints.at(ii);
+ if (percent < point.percent || ii == attributePoints.count() - 1) {
+ qreal elementPercent = (percent - prevPercent);
+
+ qreal spc = prevOrigPercent + elementPercent * point.scale;
+
+ while (spc > epc) {
+ Q_ASSERT(!(currElement > lastElement));
+ Q_UNUSED(lastElement);
+ currBez = nextBezier(path, &currElement, &bezLength);
+ currLength += bezLength;
+ epc = currLength / pathLength;
+ }
+ prevBez.element = currElement;
+ prevBez.bezLength = bezLength;
+ prevBez.currLength = currLength;
+ prevBez.bezier = currBez;
+ prevBez.p = p;
+ prevBez.isValid = true;
+
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+
+ if (angle) {
+ qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
+ qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
+ *angle = QLineF(0, 0, m1, m2).angle();
+ }
+
+ return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ }
+ prevOrigPercent = point.origpercent;
+ prevPercent = point.percent;
+ }
+
+ return QPointF(0,0);
+}
+
+//ideally this should be merged with forwardsPointAt
+QPointF QDeclarativePath::backwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return path.pointAtPercent(0);
+
+ const int firstElement = 0;
+ bool haveCachedBez = prevBez.isValid;
+ int currElement = haveCachedBez ? prevBez.element : path.elementCount();
+ qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
+ QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength, true /*reverse*/);
+ qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
+ qreal prevLength = currLength - bezLength;
+ qreal epc = prevLength / pathLength;
+
+ for (int ii = attributePoints.count() - 1; ii > 0; --ii) {
+ qreal percent = p;
+ const AttributePoint &point = attributePoints.at(ii);
+ const AttributePoint &prevPoint = attributePoints.at(ii-1);
+ if (percent > prevPoint.percent || ii == 1) {
+ qreal elementPercent = (percent - prevPoint.percent);
+
+ qreal spc = prevPoint.origpercent + elementPercent * point.scale;
+
+ while (spc < epc) {
+ Q_ASSERT(!(currElement < firstElement));
+ Q_UNUSED(firstElement);
+ currBez = nextBezier(path, &currElement, &bezLength, true /*reverse*/);
+ currLength = prevLength;
+ prevLength = currLength - bezLength;
+ epc = prevLength / pathLength;
+ }
+ prevBez.element = currElement;
+ prevBez.bezLength = bezLength;
+ prevBez.currLength = currLength;
+ prevBez.bezier = currBez;
+ prevBez.p = p;
+ prevBez.isValid = true;
+
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+
+ if (angle) {
+ qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
+ qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
+ *angle = QLineF(0, 0, m1, m2).angle();
+ }
+
+ return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ }
+ }
+
+ return QPointF(0,0);
+}
+
+QPointF QDeclarativePath::pointAt(qreal p) const
+{
+ Q_D(const QDeclarativePath);
+ if (d->_pointCache.isEmpty()) {
+ createPointCache();
+ if (d->_pointCache.isEmpty())
+ return QPointF();
+ }
+ int idx = qRound(p*d->_pointCache.size());
+ if (idx >= d->_pointCache.size())
+ idx = d->_pointCache.size() - 1;
+ else if (idx < 0)
+ idx = 0;
+ return d->_pointCache.at(idx);
+}
+
+qreal QDeclarativePath::attributeAt(const QString &name, qreal percent) const
+{
+ Q_D(const QDeclarativePath);
+ if (percent < 0 || percent > 1)
+ return 0;
+
+ for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+
+ if (point.percent == percent) {
+ return point.values.value(name);
+ } else if (point.percent > percent) {
+ qreal lastValue =
+ ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
+ qreal lastPercent =
+ ii?(d->_attributePoints.at(ii - 1).percent):0;
+ qreal curValue = point.values.value(name);
+ qreal curPercent = point.percent;
+
+ return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+qreal QDeclarativeCurve::x() const
+{
+ return _x.isNull ? 0 : _x.value;
+}
+
+void QDeclarativeCurve::setX(qreal x)
+{
+ if (_x.isNull || _x != x) {
+ _x = x;
+ emit xChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasX()
+{
+ return _x.isValid();
+}
+
+qreal QDeclarativeCurve::y() const
+{
+ return _y.isNull ? 0 : _y.value;
+}
+
+void QDeclarativeCurve::setY(qreal y)
+{
+ if (_y.isNull || _y != y) {
+ _y = y;
+ emit yChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasY()
+{
+ return _y.isValid();
+}
+
+qreal QDeclarativeCurve::relativeX() const
+{
+ return _relativeX;
+}
+
+void QDeclarativeCurve::setRelativeX(qreal x)
+{
+ if (_relativeX.isNull || _relativeX != x) {
+ _relativeX = x;
+ emit relativeXChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasRelativeX()
+{
+ return _relativeX.isValid();
+}
+
+qreal QDeclarativeCurve::relativeY() const
+{
+ return _relativeY;
+}
+
+void QDeclarativeCurve::setRelativeY(qreal y)
+{
+ if (_relativeY.isNull || _relativeY != y) {
+ _relativeY = y;
+ emit relativeYChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasRelativeY()
+{
+ return _relativeY.isValid();
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathAttribute QDeclarativePathAttribute
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief The PathAttribute allows setting an attribute at a given position in a Path.
+
+ The PathAttribute object allows attributes consisting of a name and
+ a value to be specified for various points along a path. The
+ attributes are exposed to the delegate as
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Properties}.
+ The value of an attribute at any particular point along the path is interpolated
+ from the PathAttributes bounding that point.
+
+ The example below shows a path with the items scaled to 30% with
+ opacity 50% at the top of the path and scaled 100% with opacity
+ 100% at the bottom. Note the use of the PathView.iconScale and
+ PathView.iconOpacity attached properties to set the scale and opacity
+ of the delegate.
+
+ \table
+ \row
+ \o \image declarative-pathattribute.png
+ \o
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 0
+ (see the PathView documentation for the specification of ContactModel.qml
+ used for ContactModel above.)
+ \endtable
+
+
+ \sa Path
+*/
+
+/*!
+ \qmlproperty string QtQuick2::PathAttribute::name
+ This property holds the name of the attribute to change.
+
+ This attribute will be available to the delegate as PathView.<name>
+
+ Note that using an existing Item property name such as "opacity" as an
+ attribute is allowed. This is because path attributes add a new
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
+ which in no way clashes with existing properties.
+*/
+
+/*!
+ the name of the attribute to change.
+*/
+
+QString QDeclarativePathAttribute::name() const
+{
+ return _name;
+}
+
+void QDeclarativePathAttribute::setName(const QString &name)
+{
+ if (_name == name)
+ return;
+ _name = name;
+ emit nameChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick2::PathAttribute::value
+ This property holds the value for the attribute.
+
+ The value specified can be used to influence the visual appearance
+ of an item along the path. For example, the following Path specifies
+ an attribute named \e itemRotation, which has the value \e 0 at the
+ beginning of the path, and the value 90 at the end of the path.
+
+ \qml
+ Path {
+ startX: 0
+ startY: 0
+ PathAttribute { name: "itemRotation"; value: 0 }
+ PathLine { x: 100; y: 100 }
+ PathAttribute { name: "itemRotation"; value: 90 }
+ }
+ \endqml
+
+ In our delegate, we can then bind the \e rotation property to the
+ \l{qdeclarativeintroduction.html#attached-properties} {Attached Property}
+ \e PathView.itemRotation created for this attribute.
+
+ \qml
+ Rectangle {
+ width: 10; height: 10
+ rotation: PathView.itemRotation
+ }
+ \endqml
+
+ As each item is positioned along the path, it will be rotated accordingly:
+ an item at the beginning of the path with be not be rotated, an item at
+ the end of the path will be rotated 90 degrees, and an item mid-way along
+ the path will be rotated 45 degrees.
+*/
+
+/*!
+ the new value of the attribute.
+*/
+qreal QDeclarativePathAttribute::value() const
+{
+ return _value;
+}
+
+void QDeclarativePathAttribute::setValue(qreal value)
+{
+ if (_value != value) {
+ _value = value;
+ emit valueChanged();
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathLine QDeclarativePathLine
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief The PathLine defines a straight line.
+
+ The example below creates a path consisting of a straight line from
+ 0,100 to 200,100:
+
+ \qml
+ Path {
+ startX: 0; startY: 100
+ PathLine { x: 200; y: 100 }
+ }
+ \endqml
+
+ \sa Path, PathQuad, PathCubic
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathLine::x
+ \qmlproperty real QtQuick2::PathLine::y
+
+ Defines the end point of the line.
+*/
+
+inline QPointF positionForCurve(const QDeclarativePathData &data, const QPointF &prevPoint)
+{
+ QDeclarativeCurve *curve = data.curves.at(data.index);
+ bool isEnd = data.index == data.curves.size() - 1;
+ return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
+ curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
+}
+
+void QDeclarativePathLine::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ path.lineTo(positionForCurve(data, path.currentPosition()));
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathQuad QDeclarativePathQuad
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief The PathQuad defines a quadratic Bezier curve with a control point.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathquad.png
+ \o
+ \qml
+ Path {
+ startX: 0; startY: 0
+ PathQuad { x: 200; y: 0; controlX: 100; controlY: 150 }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathCubic, PathLine
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathQuad::x
+ \qmlproperty real QtQuick2::PathQuad::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathQuad::controlX
+ \qmlproperty real QtQuick2::PathQuad::controlY
+
+ Defines the position of the control point.
+*/
+
+/*!
+ the x position of the control point.
+*/
+qreal QDeclarativePathQuad::controlX() const
+{
+ return _controlX;
+}
+
+void QDeclarativePathQuad::setControlX(qreal x)
+{
+ if (_controlX != x) {
+ _controlX = x;
+ emit controlXChanged();
+ emit changed();
+ }
+}
+
+
+/*!
+ the y position of the control point.
+*/
+qreal QDeclarativePathQuad::controlY() const
+{
+ return _controlY;
+}
+
+void QDeclarativePathQuad::setControlY(qreal y)
+{
+ if (_controlY != y) {
+ _controlY = y;
+ emit controlYChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathQuad::relativeControlX() const
+{
+ return _relativeControlX;
+}
+
+void QDeclarativePathQuad::setRelativeControlX(qreal x)
+{
+ if (_relativeControlX.isNull || _relativeControlX != x) {
+ _relativeControlX = x;
+ emit relativeControlXChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathQuad::hasRelativeControlX()
+{
+ return _relativeControlX.isValid();
+}
+
+qreal QDeclarativePathQuad::relativeControlY() const
+{
+ return _relativeControlY;
+}
+
+void QDeclarativePathQuad::setRelativeControlY(qreal y)
+{
+ if (_relativeControlY.isNull || _relativeControlY != y) {
+ _relativeControlY = y;
+ emit relativeControlYChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathQuad::hasRelativeControlY()
+{
+ return _relativeControlY.isValid();
+}
+
+void QDeclarativePathQuad::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &prevPoint = path.currentPosition();
+ QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
+ hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
+ path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathCubic QDeclarativePathCubic
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief The PathCubic defines a cubic Bezier curve with two control points.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathcubic.png
+ \o
+ \qml
+ Path {
+ startX: 20; startY: 0
+ PathCubic {
+ x: 180; y: 0
+ control1X: -10; control1Y: 90
+ control2X: 210; control2Y: 90
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathQuad, PathLine
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathCubic::x
+ \qmlproperty real QtQuick2::PathCubic::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathCubic::control1X
+ \qmlproperty real QtQuick2::PathCubic::control1Y
+
+ Defines the position of the first control point.
+*/
+qreal QDeclarativePathCubic::control1X() const
+{
+ return _control1X;
+}
+
+void QDeclarativePathCubic::setControl1X(qreal x)
+{
+ if (_control1X != x) {
+ _control1X = x;
+ emit control1XChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathCubic::control1Y() const
+{
+ return _control1Y;
+}
+
+void QDeclarativePathCubic::setControl1Y(qreal y)
+{
+ if (_control1Y != y) {
+ _control1Y = y;
+ emit control1YChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick2::PathCubic::control2X
+ \qmlproperty real QtQuick2::PathCubic::control2Y
+
+ Defines the position of the second control point.
+*/
+qreal QDeclarativePathCubic::control2X() const
+{
+ return _control2X;
+}
+
+void QDeclarativePathCubic::setControl2X(qreal x)
+{
+ if (_control2X != x) {
+ _control2X = x;
+ emit control2XChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathCubic::control2Y() const
+{
+ return _control2Y;
+}
+
+void QDeclarativePathCubic::setControl2Y(qreal y)
+{
+ if (_control2Y != y) {
+ _control2Y = y;
+ emit control2YChanged();
+ emit changed();
+ }
+}
+
+qreal QDeclarativePathCubic::relativeControl1X() const
+{
+ return _relativeControl1X;
+}
+
+void QDeclarativePathCubic::setRelativeControl1X(qreal x)
+{
+ if (_relativeControl1X.isNull || _relativeControl1X != x) {
+ _relativeControl1X = x;
+ emit relativeControl1XChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl1X()
+{
+ return _relativeControl1X.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl1Y() const
+{
+ return _relativeControl1Y;
+}
+
+void QDeclarativePathCubic::setRelativeControl1Y(qreal y)
+{
+ if (_relativeControl1Y.isNull || _relativeControl1Y != y) {
+ _relativeControl1Y = y;
+ emit relativeControl1YChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl1Y()
+{
+ return _relativeControl1Y.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl2X() const
+{
+ return _relativeControl2X;
+}
+
+void QDeclarativePathCubic::setRelativeControl2X(qreal x)
+{
+ if (_relativeControl2X.isNull || _relativeControl2X != x) {
+ _relativeControl2X = x;
+ emit relativeControl2XChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl2X()
+{
+ return _relativeControl2X.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl2Y() const
+{
+ return _relativeControl2Y;
+}
+
+void QDeclarativePathCubic::setRelativeControl2Y(qreal y)
+{
+ if (_relativeControl2Y.isNull || _relativeControl2Y != y) {
+ _relativeControl2Y = y;
+ emit relativeControl2YChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl2Y()
+{
+ return _relativeControl2Y.isValid();
+}
+
+void QDeclarativePathCubic::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &prevPoint = path.currentPosition();
+ QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
+ hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
+ QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
+ hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
+ path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
+}
+
+/****************************************************************************/
+
+inline QPointF previousPathPosition(const QPainterPath &path)
+{
+ int count = path.elementCount();
+ if (count < 1)
+ return QPointF();
+
+ int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
+ return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
+}
+
+void QDeclarativePathCatmullRomCurve::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ //here we convert catmull-rom spline to bezier for use in QPainterPath.
+ //basic conversion algorithm:
+ // catmull-rom points * inverse bezier matrix * catmull-rom matrix = bezier points
+ //each point in the catmull-rom spline produces a bezier endpoint + 2 control points
+ //calculations for each point use a moving window of 4 points
+ // (previous 2 points + current point + next point)
+ QPointF prevFar, prev, point, next;
+
+ //get previous points
+ int index = data.index - 1;
+ QDeclarativeCurve *curve = index == -1 ? 0 : data.curves.at(index);
+ if (qobject_cast<QDeclarativePathCatmullRomCurve*>(curve)) {
+ prev = path.currentPosition();
+ prevFar = previousPathPosition(path);
+ } else
+ prevFar = prev = path.currentPosition();
+
+ //get current point
+ point = positionForCurve(data, path.currentPosition());
+
+ //get next point
+ index = data.index + 1;
+ if (index < data.curves.count() && qobject_cast<QDeclarativePathCatmullRomCurve*>(data.curves.at(index))) {
+ QDeclarativePathData nextData;
+ nextData.index = index;
+ nextData.endPoint = data.endPoint;
+ nextData.curves = data.curves;
+ next = positionForCurve(nextData, point);
+ } else
+ next = point;
+
+ /*
+ full conversion matrix (inverse bezier * catmull-rom):
+ 0.000, 1.000, 0.000, 0.000,
+ -0.167, 1.000, 0.167, 0.000,
+ 0.000, 0.167, 1.000, -0.167,
+ 0.000, 0.000, 1.000, 0.000
+
+ conversion doesn't require full matrix multiplication,
+ so below we simplify
+ */
+ QPointF control1(prevFar.x() * qreal(-0.167) +
+ prev.x() +
+ point.x() * qreal(0.167),
+ prevFar.y() * qreal(-0.167) +
+ prev.y() +
+ point.y() * qreal(0.167));
+
+ QPointF control2(prev.x() * qreal(0.167) +
+ point.x() +
+ next.x() * qreal(-0.167),
+ prev.y() * qreal(0.167) +
+ point.y() +
+ next.y() * qreal(-0.167));
+
+ path.cubicTo(control1, control2, point);
+}
+
+/****************************************************************************/
+
+qreal QDeclarativePathArc::radiusX() const
+{
+ return _radiusX;
+}
+
+void QDeclarativePathArc::setRadiusX(qreal radius)
+{
+ if (_radiusX == radius)
+ return;
+
+ _radiusX = radius;
+ emit radiusXChanged();
+}
+
+qreal QDeclarativePathArc::radiusY() const
+{
+ return _radiusY;
+}
+
+void QDeclarativePathArc::setRadiusY(qreal radius)
+{
+ if (_radiusY == radius)
+ return;
+
+ _radiusY = radius;
+ emit radiusYChanged();
+}
+
+bool QDeclarativePathArc::useLargeArc() const
+{
+ return _useLargeArc;
+}
+
+void QDeclarativePathArc::setUseLargeArc(bool largeArc)
+{
+ if (_useLargeArc == largeArc)
+ return;
+
+ _useLargeArc = largeArc;
+ emit useLargeArcChanged();
+}
+
+QDeclarativePathArc::ArcDirection QDeclarativePathArc::direction() const
+{
+ return _direction;
+}
+
+void QDeclarativePathArc::setDirection(ArcDirection direction)
+{
+ if (_direction == direction)
+ return;
+
+ _direction = direction;
+ emit directionChanged();
+}
+
+void QDeclarativePathArc::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &startPoint = path.currentPosition();
+ const QPointF &endPoint = positionForCurve(data, startPoint);
+ QDeclarativeSvgParser::pathArc(path,
+ _radiusX,
+ _radiusY,
+ 0, //xAxisRotation
+ _useLargeArc,
+ _direction == Clockwise ? 1 : 0,
+ endPoint.x(),
+ endPoint.y(),
+ startPoint.x(), startPoint.y());
+}
+
+/****************************************************************************/
+
+QString QDeclarativePathSvg::path() const
+{
+ return _path;
+}
+
+void QDeclarativePathSvg::setPath(const QString &path)
+{
+ if (_path == path)
+ return;
+
+ _path = path;
+ emit pathChanged();
+}
+
+void QDeclarativePathSvg::addToPath(QPainterPath &path, const QDeclarativePathData &)
+{
+ QDeclarativeSvgParser::parsePathDataFast(_path, path);
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathPercent QDeclarativePathPercent
+ \inqmlmodule QtQuick 2
+ \ingroup qml-view-elements
+ \brief The PathPercent manipulates the way a path is interpreted.
+
+ PathPercent allows you to manipulate the spacing between items on a
+ PathView's path. You can use it to bunch together items on part of
+ the path, and spread them out on other parts of the path.
+
+ The examples below show the normal distribution of items along a path
+ compared to a distribution which places 50% of the items along the
+ PathLine section of the path.
+ \table
+ \row
+ \o \image declarative-nopercent.png
+ \o
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathLine { x: 150; y: 80 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ }
+ }
+ \endqml
+ \row
+ \o \image declarative-percent.png
+ \o
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathPercent { value: 0.25 }
+ PathLine { x: 150; y: 80 }
+ PathPercent { value: 0.75 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ PathPercent { value: 1 }
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa Path
+*/
+
+/*!
+ \qmlproperty real QtQuick2::PathPercent::value
+ The proportion of items that should be laid out up to this point.
+
+ This value should always be higher than the last value specified
+ by a PathPercent at a previous position in the Path.
+
+ In the following example we have a Path made up of three PathLines.
+ Normally, the items of the PathView would be laid out equally along
+ this path, with an equal number of items per line segment. PathPercent
+ allows us to specify that the first and third lines should each hold
+ 10% of the laid out items, while the second line should hold the remaining
+ 80%.
+
+ \qml
+ PathView {
+ // ...
+ Path {
+ startX: 0; startY: 0
+ PathLine { x:100; y: 0; }
+ PathPercent { value: 0.1 }
+ PathLine { x: 100; y: 100 }
+ PathPercent { value: 0.9 }
+ PathLine { x: 100; y: 0 }
+ PathPercent { value: 1 }
+ }
+ }
+ \endqml
+*/
+
+qreal QDeclarativePathPercent::value() const
+{
+ return _value;
+}
+
+void QDeclarativePathPercent::setValue(qreal value)
+{
+ if (_value != value) {
+ _value = value;
+ emit valueChanged();
+ emit changed();
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativepath_p.h b/src/quick/util/qdeclarativepath_p.h
new file mode 100644
index 0000000000..afa5b0240e
--- /dev/null
+++ b/src/quick/util/qdeclarativepath_p.h
@@ -0,0 +1,450 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATH_H
+#define QDECLARATIVEPATH_H
+
+#include <qdeclarative.h>
+
+#include <private/qdeclarativenullablevalue_p_p.h>
+#include <private/qbezier_p.h>
+
+#include <QtCore/QObject>
+#include <QtGui/QPainterPath>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeCurve;
+struct QDeclarativePathData
+{
+ int index;
+ QPointF endPoint;
+ QList<QDeclarativeCurve*> curves;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathElement : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativePathElement(QObject *parent=0) : QObject(parent) {}
+Q_SIGNALS:
+ void changed();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathAttribute : public QDeclarativePathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+public:
+ QDeclarativePathAttribute(QObject *parent=0) : QDeclarativePathElement(parent), _value(0) {}
+
+
+ QString name() const;
+ void setName(const QString &name);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+Q_SIGNALS:
+ void nameChanged();
+ void valueChanged();
+
+private:
+ QString _name;
+ qreal _value;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeCurve : public QDeclarativePathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal relativeX READ relativeX WRITE setRelativeX NOTIFY relativeXChanged)
+ Q_PROPERTY(qreal relativeY READ relativeY WRITE setRelativeY NOTIFY relativeYChanged)
+public:
+ QDeclarativeCurve(QObject *parent=0) : QDeclarativePathElement(parent) {}
+
+ qreal x() const;
+ void setX(qreal x);
+ bool hasX();
+
+ qreal y() const;
+ void setY(qreal y);
+ bool hasY();
+
+ qreal relativeX() const;
+ void setRelativeX(qreal x);
+ bool hasRelativeX();
+
+ qreal relativeY() const;
+ void setRelativeY(qreal y);
+ bool hasRelativeY();
+
+ virtual void addToPath(QPainterPath &, const QDeclarativePathData &) {}
+
+Q_SIGNALS:
+ void xChanged();
+ void yChanged();
+ void relativeXChanged();
+ void relativeYChanged();
+
+private:
+ QDeclarativeNullableValue<qreal> _x;
+ QDeclarativeNullableValue<qreal> _y;
+ QDeclarativeNullableValue<qreal> _relativeX;
+ QDeclarativeNullableValue<qreal> _relativeY;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathLine : public QDeclarativeCurve
+{
+ Q_OBJECT
+public:
+ QDeclarativePathLine(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathQuad : public QDeclarativeCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal controlX READ controlX WRITE setControlX NOTIFY controlXChanged)
+ Q_PROPERTY(qreal controlY READ controlY WRITE setControlY NOTIFY controlYChanged)
+ Q_PROPERTY(qreal relativeControlX READ relativeControlX WRITE setRelativeControlX NOTIFY relativeControlXChanged)
+ Q_PROPERTY(qreal relativeControlY READ relativeControlY WRITE setRelativeControlY NOTIFY relativeControlYChanged)
+public:
+ QDeclarativePathQuad(QObject *parent=0) : QDeclarativeCurve(parent), _controlX(0), _controlY(0) {}
+
+ qreal controlX() const;
+ void setControlX(qreal x);
+
+ qreal controlY() const;
+ void setControlY(qreal y);
+
+ qreal relativeControlX() const;
+ void setRelativeControlX(qreal x);
+ bool hasRelativeControlX();
+
+ qreal relativeControlY() const;
+ void setRelativeControlY(qreal y);
+ bool hasRelativeControlY();
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void controlXChanged();
+ void controlYChanged();
+ void relativeControlXChanged();
+ void relativeControlYChanged();
+
+private:
+ qreal _controlX;
+ qreal _controlY;
+ QDeclarativeNullableValue<qreal> _relativeControlX;
+ QDeclarativeNullableValue<qreal> _relativeControlY;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathCubic : public QDeclarativeCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal control1X READ control1X WRITE setControl1X NOTIFY control1XChanged)
+ Q_PROPERTY(qreal control1Y READ control1Y WRITE setControl1Y NOTIFY control1YChanged)
+ Q_PROPERTY(qreal control2X READ control2X WRITE setControl2X NOTIFY control2XChanged)
+ Q_PROPERTY(qreal control2Y READ control2Y WRITE setControl2Y NOTIFY control2YChanged)
+ Q_PROPERTY(qreal relativeControl1X READ relativeControl1X WRITE setRelativeControl1X NOTIFY relativeControl1XChanged)
+ Q_PROPERTY(qreal relativeControl1Y READ relativeControl1Y WRITE setRelativeControl1Y NOTIFY relativeControl1YChanged)
+ Q_PROPERTY(qreal relativeControl2X READ relativeControl2X WRITE setRelativeControl2X NOTIFY relativeControl2XChanged)
+ Q_PROPERTY(qreal relativeControl2Y READ relativeControl2Y WRITE setRelativeControl2Y NOTIFY relativeControl2YChanged)
+public:
+ QDeclarativePathCubic(QObject *parent=0) : QDeclarativeCurve(parent), _control1X(0), _control1Y(0), _control2X(0), _control2Y(0) {}
+
+ qreal control1X() const;
+ void setControl1X(qreal x);
+
+ qreal control1Y() const;
+ void setControl1Y(qreal y);
+
+ qreal control2X() const;
+ void setControl2X(qreal x);
+
+ qreal control2Y() const;
+ void setControl2Y(qreal y);
+
+ qreal relativeControl1X() const;
+ void setRelativeControl1X(qreal x);
+ bool hasRelativeControl1X();
+
+ qreal relativeControl1Y() const;
+ void setRelativeControl1Y(qreal y);
+ bool hasRelativeControl1Y();
+
+ qreal relativeControl2X() const;
+ void setRelativeControl2X(qreal x);
+ bool hasRelativeControl2X();
+
+ qreal relativeControl2Y() const;
+ void setRelativeControl2Y(qreal y);
+ bool hasRelativeControl2Y();
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void control1XChanged();
+ void control1YChanged();
+ void control2XChanged();
+ void control2YChanged();
+ void relativeControl1XChanged();
+ void relativeControl1YChanged();
+ void relativeControl2XChanged();
+ void relativeControl2YChanged();
+
+private:
+ qreal _control1X;
+ qreal _control1Y;
+ qreal _control2X;
+ qreal _control2Y;
+ QDeclarativeNullableValue<qreal> _relativeControl1X;
+ QDeclarativeNullableValue<qreal> _relativeControl1Y;
+ QDeclarativeNullableValue<qreal> _relativeControl2X;
+ QDeclarativeNullableValue<qreal> _relativeControl2Y;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathCatmullRomCurve : public QDeclarativeCurve
+{
+ Q_OBJECT
+public:
+ QDeclarativePathCatmullRomCurve(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathArc : public QDeclarativeCurve
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal radiusX READ radiusX WRITE setRadiusX NOTIFY radiusXChanged)
+ Q_PROPERTY(qreal radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged)
+ Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged)
+ Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+
+public:
+ QDeclarativePathArc(QObject *parent=0)
+ : QDeclarativeCurve(parent), _radiusX(0), _radiusY(0), _useLargeArc(false), _direction(Clockwise) {}
+
+ enum ArcDirection { Clockwise, Counterclockwise };
+ Q_ENUMS(ArcDirection)
+
+ qreal radiusX() const;
+ void setRadiusX(qreal);
+
+ qreal radiusY() const;
+ void setRadiusY(qreal);
+
+ bool useLargeArc() const;
+ void setUseLargeArc(bool);
+
+ ArcDirection direction() const;
+ void setDirection(ArcDirection direction);
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void radiusXChanged();
+ void radiusYChanged();
+ void useLargeArcChanged();
+ void directionChanged();
+
+private:
+ qreal _radiusX;
+ qreal _radiusY;
+ bool _useLargeArc;
+ ArcDirection _direction;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathSvg : public QDeclarativeCurve
+{
+ Q_OBJECT
+ Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
+public:
+ QDeclarativePathSvg(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ QString path() const;
+ void setPath(const QString &path);
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void pathChanged();
+
+private:
+ QString _path;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathPercent : public QDeclarativePathElement
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+public:
+ QDeclarativePathPercent(QObject *parent=0) : QDeclarativePathElement(parent) {}
+
+ qreal value() const;
+ void setValue(qreal value);
+
+signals:
+ void valueChanged();
+
+private:
+ qreal _value;
+};
+
+struct QDeclarativeCachedBezier
+{
+ QDeclarativeCachedBezier() : isValid(false) {}
+ QBezier bezier;
+ int element;
+ qreal bezLength;
+ qreal currLength;
+ qreal p;
+ bool isValid;
+};
+
+class QDeclarativePathPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativePath : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativePathElement> pathElements READ pathElements)
+ Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged)
+ Q_PROPERTY(qreal startY READ startY WRITE setStartY NOTIFY startYChanged)
+ Q_PROPERTY(bool closed READ isClosed NOTIFY changed)
+ Q_CLASSINFO("DefaultProperty", "pathElements")
+ Q_INTERFACES(QDeclarativeParserStatus)
+public:
+ QDeclarativePath(QObject *parent=0);
+ ~QDeclarativePath();
+
+ QDeclarativeListProperty<QDeclarativePathElement> pathElements();
+
+ qreal startX() const;
+ void setStartX(qreal x);
+ bool hasStartX() const;
+
+ qreal startY() const;
+ void setStartY(qreal y);
+ bool hasStartY() const;
+
+ bool isClosed() const;
+ bool hasEnd() const;
+
+ QPainterPath path() const;
+ QStringList attributes() const;
+ qreal attributeAt(const QString &, qreal) const;
+ QPointF pointAt(qreal) const;
+ QPointF sequentialPointAt(qreal p, qreal *angle = 0) const;
+
+Q_SIGNALS:
+ void changed();
+ void startXChanged();
+ void startYChanged();
+
+protected:
+ virtual void componentComplete();
+ virtual void classBegin();
+
+private Q_SLOTS:
+ void processPath();
+
+private:
+ struct AttributePoint {
+ AttributePoint() : percent(0), scale(1), origpercent(0) {}
+ AttributePoint(const AttributePoint &other)
+ : percent(other.percent), scale(other.scale), origpercent(other.origpercent), values(other.values) {}
+ AttributePoint &operator=(const AttributePoint &other) {
+ percent = other.percent; scale = other.scale; origpercent = other.origpercent; values = other.values; return *this;
+ }
+ qreal percent; //massaged percent along the painter path
+ qreal scale;
+ qreal origpercent; //'real' percent along the painter path
+ QHash<QString, qreal> values;
+ };
+
+ void interpolate(int idx, const QString &name, qreal value);
+ void endpoint(const QString &name);
+ void createPointCache() const;
+
+ static void interpolate(QList<AttributePoint> &points, int idx, const QString &name, qreal value);
+ static void endpoint(QList<AttributePoint> &attributePoints, const QString &name);
+ static QPointF forwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
+ static QPointF backwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
+
+private:
+ Q_DISABLE_COPY(QDeclarativePath)
+ Q_DECLARE_PRIVATE(QDeclarativePath)
+ friend class QQuickPathAnimationUpdater;
+
+public:
+ QPainterPath createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed = 0);
+ static QPointF sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePathElement)
+QML_DECLARE_TYPE(QDeclarativePathAttribute)
+QML_DECLARE_TYPE(QDeclarativeCurve)
+QML_DECLARE_TYPE(QDeclarativePathLine)
+QML_DECLARE_TYPE(QDeclarativePathQuad)
+QML_DECLARE_TYPE(QDeclarativePathCubic)
+QML_DECLARE_TYPE(QDeclarativePathCatmullRomCurve)
+QML_DECLARE_TYPE(QDeclarativePathArc)
+QML_DECLARE_TYPE(QDeclarativePathSvg)
+QML_DECLARE_TYPE(QDeclarativePathPercent)
+QML_DECLARE_TYPE(QDeclarativePath)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPATH_H
diff --git a/src/quick/util/qdeclarativepath_p_p.h b/src/quick/util/qdeclarativepath_p_p.h
new file mode 100644
index 0000000000..910b7627d3
--- /dev/null
+++ b/src/quick/util/qdeclarativepath_p_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATH_P_H
+#define QDECLARATIVEPATH_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 "qdeclarativepath_p.h"
+
+#include <qdeclarative.h>
+#include <QtCore/QStringList>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePathPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePath)
+
+public:
+ QDeclarativePathPrivate() : pathLength(0), closed(false), componentComplete(true) { }
+
+ QPainterPath _path;
+ QList<QDeclarativePathElement*> _pathElements;
+ mutable QVector<QPointF> _pointCache;
+ QList<QDeclarativePath::AttributePoint> _attributePoints;
+ QStringList _attributes;
+ QList<QDeclarativeCurve*> _pathCurves;
+ mutable QDeclarativeCachedBezier prevBez;
+ QDeclarativeNullableValue<qreal> startX;
+ QDeclarativeNullableValue<qreal> startY;
+ qreal pathLength;
+ bool closed;
+ bool componentComplete;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/util/qdeclarativepathinterpolator.cpp b/src/quick/util/qdeclarativepathinterpolator.cpp
new file mode 100644
index 0000000000..569884d33a
--- /dev/null
+++ b/src/quick/util/qdeclarativepathinterpolator.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepathinterpolator_p.h"
+
+#include "qdeclarativepath_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativePathInterpolator::QDeclarativePathInterpolator(QObject *parent) :
+ QObject(parent), _path(0), _x(0), _y(0), _angle(0), _progress(0)
+{
+}
+
+QDeclarativePath *QDeclarativePathInterpolator::path() const
+{
+ return _path;
+}
+
+void QDeclarativePathInterpolator::setPath(QDeclarativePath *path)
+{
+ if (_path == path)
+ return;
+ if (_path)
+ disconnect(_path, SIGNAL(changed()), this, SLOT(_q_pathUpdated()));
+ _path = path;
+ connect(_path, SIGNAL(changed()), this, SLOT(_q_pathUpdated()));
+ emit pathChanged();
+}
+
+qreal QDeclarativePathInterpolator::progress() const
+{
+ return _progress;
+}
+
+void QDeclarativePathInterpolator::setProgress(qreal progress)
+{
+ if (progress == _progress)
+ return;
+ _progress = progress;
+ emit progressChanged();
+ _q_pathUpdated();
+}
+
+qreal QDeclarativePathInterpolator::x() const
+{
+ return _x;
+}
+
+qreal QDeclarativePathInterpolator::y() const
+{
+ return _y;
+}
+
+qreal QDeclarativePathInterpolator::angle() const
+{
+ return _angle;
+}
+
+void QDeclarativePathInterpolator::_q_pathUpdated()
+{
+ if (! _path)
+ return;
+
+ qreal angle = 0;
+ const QPointF pt = _path->sequentialPointAt(_progress, &angle);
+
+ if (_x != pt.x()) {
+ _x = pt.x();
+ emit xChanged();
+ }
+
+ if (_y != pt.y()) {
+ _y = pt.y();
+ emit yChanged();
+ }
+
+ if (angle != _angle) {
+ _angle = angle;
+ emit angleChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativepathinterpolator_p.h b/src/quick/util/qdeclarativepathinterpolator_p.h
new file mode 100644
index 0000000000..11370a53fe
--- /dev/null
+++ b/src/quick/util/qdeclarativepathinterpolator_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATHINTERPOLATOR_P_H
+#define QDECLARATIVEPATHINTERPOLATOR_P_H
+
+#include <qdeclarative.h>
+#include <QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePath;
+class Q_AUTOTEST_EXPORT QDeclarativePathInterpolator : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativePath *path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
+ Q_PROPERTY(qreal x READ x NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y NOTIFY yChanged)
+ Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged)
+public:
+ explicit QDeclarativePathInterpolator(QObject *parent = 0);
+
+ QDeclarativePath *path() const;
+ void setPath(QDeclarativePath *path);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ qreal x() const;
+ qreal y() const;
+ qreal angle() const;
+
+Q_SIGNALS:
+ void pathChanged();
+ void progressChanged();
+ void xChanged();
+ void yChanged();
+ void angleChanged();
+
+private Q_SLOTS:
+ void _q_pathUpdated();
+
+private:
+ QDeclarativePath *_path;
+ qreal _x;
+ qreal _y;
+ qreal _angle;
+ qreal _progress;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePathInterpolator)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPATHINTERPOLATOR_P_H
diff --git a/src/quick/util/qdeclarativepixmapcache.cpp b/src/quick/util/qdeclarativepixmapcache.cpp
new file mode 100644
index 0000000000..ba155abe98
--- /dev/null
+++ b/src/quick/util/qdeclarativepixmapcache.cpp
@@ -0,0 +1,1241 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepixmapcache_p.h"
+#include <qdeclarativenetworkaccessmanagerfactory.h>
+#include <qdeclarativeimageprovider.h>
+
+#include <qdeclarativeengine.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <QtQuick/private/qsgtexture_p.h>
+
+#include <QCoreApplication>
+#include <QImageReader>
+#include <QHash>
+#include <QNetworkReply>
+#include <QPixmapCache>
+#include <QFile>
+#include <QThread>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QWaitCondition>
+#include <QBuffer>
+#include <QWaitCondition>
+#include <QtCore/qdebug.h>
+#include <private/qobject_p.h>
+#include <QSslError>
+#include <QOpenGLContext>
+
+#define IMAGEREQUEST_MAX_REQUEST_COUNT 8
+#define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16
+#define CACHE_EXPIRE_TIME 30
+#define CACHE_REMOVAL_FRACTION 4
+
+QT_BEGIN_NAMESPACE
+
+// The cache limit describes the maximum "junk" in the cache.
+static int cache_limit = 2048 * 1024; // 2048 KB cache limit for embedded in qpixmapcache.cpp
+
+QSGTexture *QDeclarativeDefaultTextureFactory::createTexture() const
+{
+ QSGPlainTexture *t = new QSGPlainTexture();
+ t->setImage(im);
+ return t;
+}
+
+class QDeclarativePixmapReader;
+class QDeclarativePixmapData;
+class QDeclarativePixmapReply : public QObject
+{
+ Q_OBJECT
+public:
+ enum ReadError { NoError, Loading, Decoding };
+
+ QDeclarativePixmapReply(QDeclarativePixmapData *);
+ ~QDeclarativePixmapReply();
+
+ QDeclarativePixmapData *data;
+ QDeclarativeEngine *engineForReader; // always access reader inside readerMutex
+ QSize requestSize;
+ QUrl url;
+
+ bool loading;
+ int redirectCount;
+
+ class Event : public QEvent {
+ public:
+ Event(ReadError, const QString &, const QSize &, QDeclarativeTextureFactory *factory, const QImage &image);
+
+ ReadError error;
+ QString errorString;
+ QSize implicitSize;
+ QImage image;
+ QDeclarativeTextureFactory *textureFactory;
+ };
+ void postReply(ReadError, const QString &, const QSize &, const QImage &image);
+ void postReply(ReadError, const QString &, const QSize &, QDeclarativeTextureFactory *factory, const QImage &image);
+
+
+Q_SIGNALS:
+ void finished();
+ void downloadProgress(qint64, qint64);
+
+protected:
+ bool event(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QDeclarativePixmapReply)
+
+public:
+ static int finishedIndex;
+ static int downloadProgressIndex;
+};
+
+class QDeclarativePixmapReaderThreadObject : public QObject {
+ Q_OBJECT
+public:
+ QDeclarativePixmapReaderThreadObject(QDeclarativePixmapReader *);
+ void processJobs();
+ virtual bool event(QEvent *e);
+private slots:
+ void networkRequestDone();
+private:
+ QDeclarativePixmapReader *reader;
+};
+
+class QDeclarativePixmapData;
+class QDeclarativePixmapReader : public QThread
+{
+ Q_OBJECT
+public:
+ QDeclarativePixmapReader(QDeclarativeEngine *eng);
+ ~QDeclarativePixmapReader();
+
+ QDeclarativePixmapReply *getImage(QDeclarativePixmapData *);
+ void cancel(QDeclarativePixmapReply *rep);
+
+ static QDeclarativePixmapReader *instance(QDeclarativeEngine *engine);
+ static QDeclarativePixmapReader *existingInstance(QDeclarativeEngine *engine);
+
+protected:
+ void run();
+
+private:
+ friend class QDeclarativePixmapReaderThreadObject;
+ void processJobs();
+ void processJob(QDeclarativePixmapReply *, const QUrl &, const QSize &);
+ void networkRequestDone(QNetworkReply *);
+
+ QList<QDeclarativePixmapReply*> jobs;
+ QList<QDeclarativePixmapReply*> cancelled;
+ QDeclarativeEngine *engine;
+ QObject *eventLoopQuitHack;
+
+ QMutex mutex;
+ QDeclarativePixmapReaderThreadObject *threadObject;
+ QWaitCondition waitCondition;
+
+ QNetworkAccessManager *networkAccessManager();
+ QNetworkAccessManager *accessManager;
+
+ QHash<QNetworkReply*,QDeclarativePixmapReply*> replies;
+
+ static int replyDownloadProgress;
+ static int replyFinished;
+ static int downloadProgress;
+ static int threadNetworkRequestDone;
+ static QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> readers;
+public:
+ static QMutex readerMutex;
+};
+
+class QDeclarativePixmapData
+{
+public:
+ QDeclarativePixmapData(QDeclarativePixmap *pixmap, const QUrl &u, const QSize &s, const QString &e)
+ : refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Error),
+ url(u), errorString(e), requestSize(s), textureFactory(0), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ declarativePixmaps.insert(pixmap);
+ }
+
+ QDeclarativePixmapData(QDeclarativePixmap *pixmap, const QUrl &u, const QSize &r)
+ : refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Loading),
+ url(u), requestSize(r), textureFactory(0), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0),
+ nextUnreferenced(0)
+ {
+ declarativePixmaps.insert(pixmap);
+ }
+
+ QDeclarativePixmapData(QDeclarativePixmap *pixmap, const QUrl &u, const QImage &p, const QSize &s, const QSize &r)
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), image(p), implicitSize(s), requestSize(r), textureFactory(new QDeclarativeDefaultTextureFactory(p)), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ declarativePixmaps.insert(pixmap);
+ }
+
+ QDeclarativePixmapData(QDeclarativePixmap *pixmap, const QUrl &u, QDeclarativeTextureFactory *factory, const QImage &p, const QSize &s, const QSize &r)
+ : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
+ url(u), image(p), implicitSize(s), requestSize(r), textureFactory(factory), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ declarativePixmaps.insert(pixmap);
+ }
+
+ QDeclarativePixmapData(QDeclarativePixmap *pixmap, const QImage &p)
+ : refCount(1), inCache(false), privatePixmap(true), pixmapStatus(QDeclarativePixmap::Ready),
+ image(p), implicitSize(p.size()), requestSize(p.size()), textureFactory(new QDeclarativeDefaultTextureFactory(p)), reply(0), prevUnreferenced(0),
+ prevUnreferencedPtr(0), nextUnreferenced(0)
+ {
+ declarativePixmaps.insert(pixmap);
+ }
+
+ ~QDeclarativePixmapData()
+ {
+ while (!declarativePixmaps.isEmpty()) {
+ QDeclarativePixmap *referencer = declarativePixmaps.first();
+ declarativePixmaps.remove(referencer);
+ referencer->d = 0;
+ }
+ delete textureFactory;
+ }
+
+ int cost() const;
+ void addref();
+ void release();
+ void addToCache();
+ void removeFromCache();
+
+ uint refCount;
+
+ bool inCache:1;
+ bool privatePixmap:1;
+
+ QDeclarativePixmap::Status pixmapStatus;
+ QUrl url;
+ QString errorString;
+ QImage image;
+ QSize implicitSize;
+ QSize requestSize;
+
+ QDeclarativeTextureFactory *textureFactory;
+
+ QIntrusiveList<QDeclarativePixmap, &QDeclarativePixmap::dataListNode> declarativePixmaps;
+ QDeclarativePixmapReply *reply;
+
+ QDeclarativePixmapData *prevUnreferenced;
+ QDeclarativePixmapData**prevUnreferencedPtr;
+ QDeclarativePixmapData *nextUnreferenced;
+};
+
+int QDeclarativePixmapReply::finishedIndex = -1;
+int QDeclarativePixmapReply::downloadProgressIndex = -1;
+
+// XXX
+QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> QDeclarativePixmapReader::readers;
+QMutex QDeclarativePixmapReader::readerMutex;
+
+int QDeclarativePixmapReader::replyDownloadProgress = -1;
+int QDeclarativePixmapReader::replyFinished = -1;
+int QDeclarativePixmapReader::downloadProgress = -1;
+int QDeclarativePixmapReader::threadNetworkRequestDone = -1;
+
+
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+ const QSize &implicitSize, const QImage &image)
+{
+ loading = false;
+ QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, new QDeclarativeDefaultTextureFactory(image), image));
+}
+
+void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
+ const QSize &implicitSize, QDeclarativeTextureFactory *factory,
+ const QImage &image)
+{
+ loading = false;
+ QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, factory, image));
+}
+
+QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, QDeclarativeTextureFactory *factory, const QImage &i)
+ : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i), textureFactory(factory)
+{
+}
+
+QNetworkAccessManager *QDeclarativePixmapReader::networkAccessManager()
+{
+ if (!accessManager) {
+ Q_ASSERT(threadObject);
+ accessManager = QDeclarativeEnginePrivate::get(engine)->createNetworkAccessManager(threadObject);
+ }
+ return accessManager;
+}
+
+static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
+ const QSize &requestSize)
+{
+ QImageReader imgio(dev);
+
+ bool force_scale = false;
+ if (url.path().endsWith(QLatin1String(".svg"),Qt::CaseInsensitive)) {
+ imgio.setFormat("svg"); // QSvgPlugin::capabilities bug QTBUG-9053
+ force_scale = true;
+ }
+
+ bool scaled = false;
+ if (requestSize.width() > 0 || requestSize.height() > 0) {
+ QSize s = imgio.size();
+ if (requestSize.width() && (force_scale || requestSize.width() < s.width())) {
+ if (requestSize.height() <= 0)
+ s.setHeight(s.height()*requestSize.width()/s.width());
+ s.setWidth(requestSize.width()); scaled = true;
+ }
+ if (requestSize.height() && (force_scale || requestSize.height() < s.height())) {
+ if (requestSize.width() <= 0)
+ s.setWidth(s.width()*requestSize.height()/s.height());
+ s.setHeight(requestSize.height()); scaled = true;
+ }
+ if (scaled) { imgio.setScaledSize(s); }
+ }
+
+ if (impsize)
+ *impsize = imgio.size();
+
+ if (imgio.read(image)) {
+ if (impsize && impsize->width() < 0)
+ *impsize = image->size();
+ return true;
+ } else {
+ if (errorString)
+ *errorString = QDeclarativePixmap::tr("Error decoding: %1: %2").arg(url.toString())
+ .arg(imgio.errorString());
+ return false;
+ }
+}
+
+QDeclarativePixmapReader::QDeclarativePixmapReader(QDeclarativeEngine *eng)
+: QThread(eng), engine(eng), threadObject(0), accessManager(0)
+{
+ eventLoopQuitHack = new QObject;
+ eventLoopQuitHack->moveToThread(this);
+ connect(eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection);
+ start(QThread::LowestPriority);
+}
+
+QDeclarativePixmapReader::~QDeclarativePixmapReader()
+{
+ readerMutex.lock();
+ readers.remove(engine);
+ readerMutex.unlock();
+
+ mutex.lock();
+ // manually cancel all outstanding jobs.
+ foreach (QDeclarativePixmapReply *reply, jobs) {
+ delete reply;
+ }
+ jobs.clear();
+ QList<QDeclarativePixmapReply*> activeJobs = replies.values();
+ foreach (QDeclarativePixmapReply *reply, activeJobs) {
+ if (reply->loading) {
+ cancelled.append(reply);
+ reply->data = 0;
+ }
+ }
+ if (threadObject) threadObject->processJobs();
+ mutex.unlock();
+
+ eventLoopQuitHack->deleteLater();
+ wait();
+}
+
+void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
+{
+ QDeclarativePixmapReply *job = replies.take(reply);
+
+ if (job) {
+ job->redirectCount++;
+ if (job->redirectCount < IMAGEREQUEST_MAX_REDIRECT_RECURSION) {
+ QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = reply->url().resolved(redirect.toUrl());
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+
+ reply->deleteLater();
+ reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, job, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone);
+
+ replies.insert(reply, job);
+ return;
+ }
+ }
+
+ QImage image;
+ QDeclarativePixmapReply::ReadError error = QDeclarativePixmapReply::NoError;
+ QString errorString;
+ QSize readSize;
+ if (reply->error()) {
+ error = QDeclarativePixmapReply::Loading;
+ errorString = reply->errorString();
+ } else {
+ QByteArray all = reply->readAll();
+ QBuffer buff(&all);
+ buff.open(QIODevice::ReadOnly);
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize))
+ error = QDeclarativePixmapReply::Decoding;
+ }
+ // send completion event to the QDeclarativePixmapReply
+ mutex.lock();
+ if (!cancelled.contains(job)) {
+ job->postReply(error, errorString, readSize, image);
+ }
+ mutex.unlock();
+ }
+ reply->deleteLater();
+
+ // kick off event loop again incase we have dropped below max request count
+ threadObject->processJobs();
+}
+
+QDeclarativePixmapReaderThreadObject::QDeclarativePixmapReaderThreadObject(QDeclarativePixmapReader *i)
+: reader(i)
+{
+}
+
+void QDeclarativePixmapReaderThreadObject::processJobs()
+{
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+bool QDeclarativePixmapReaderThreadObject::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ reader->processJobs();
+ return true;
+ } else {
+ return QObject::event(e);
+ }
+}
+
+void QDeclarativePixmapReaderThreadObject::networkRequestDone()
+{
+ QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
+ reader->networkRequestDone(reply);
+}
+
+void QDeclarativePixmapReader::processJobs()
+{
+ QMutexLocker locker(&mutex);
+
+ while (true) {
+ if (cancelled.isEmpty() && (jobs.isEmpty() || replies.count() >= IMAGEREQUEST_MAX_REQUEST_COUNT))
+ return; // Nothing else to do
+
+ // Clean cancelled jobs
+ if (cancelled.count()) {
+ for (int i = 0; i < cancelled.count(); ++i) {
+ QDeclarativePixmapReply *job = cancelled.at(i);
+ QNetworkReply *reply = replies.key(job, 0);
+ if (reply && reply->isRunning()) {
+ // cancel any jobs already started
+ replies.remove(reply);
+ reply->close();
+ }
+ // deleteLater, since not owned by this thread
+ job->deleteLater();
+ }
+ cancelled.clear();
+ }
+
+ if (!jobs.isEmpty() && replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT) {
+ QDeclarativePixmapReply *runningJob = jobs.takeLast();
+ runningJob->loading = true;
+
+ QUrl url = runningJob->url;
+ QSize requestSize = runningJob->requestSize;
+ locker.unlock();
+ processJob(runningJob, url, requestSize);
+ locker.relock();
+ }
+ }
+}
+
+void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, const QUrl &url,
+ const QSize &requestSize)
+{
+ // fetch
+ if (url.scheme() == QLatin1String("image")) {
+ // Use QmlImageProvider
+ QSize readSize;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+ if (imageType == QDeclarativeImageProvider::Invalid) {
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::Loading;
+ QString errorStr = QDeclarativePixmap::tr("Invalid image provider: %1").arg(url.toString());
+ QImage image;
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ mutex.unlock();
+ } else if (imageType == QDeclarativeImageProvider::Image) {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (image.isNull()) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ mutex.unlock();
+ } else {
+ QDeclarativeTextureFactory *t = ep->getTextureFromProvider(url, &readSize, requestSize);
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ if (!t) {
+ errorCode = QDeclarativePixmapReply::Loading;
+ errorStr = QDeclarativePixmap::tr("Failed to get texture from provider: %1").arg(url.toString());
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, t, QImage());
+ mutex.unlock();
+
+ }
+
+ } else {
+ QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+ if (!lf.isEmpty()) {
+ // Image is local - load/decode immediately
+ QImage image;
+ QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError;
+ QString errorStr;
+ QFile f(lf);
+ QSize readSize;
+ if (f.open(QIODevice::ReadOnly)) {
+ if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize))
+ errorCode = QDeclarativePixmapReply::Loading;
+ } else {
+ errorStr = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
+ errorCode = QDeclarativePixmapReply::Loading;
+ }
+ mutex.lock();
+ if (!cancelled.contains(runningJob))
+ runningJob->postReply(errorCode, errorStr, readSize, image);
+ mutex.unlock();
+ } else {
+ // Network resource
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ QNetworkReply *reply = networkAccessManager()->get(req);
+
+ QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress);
+ QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone);
+
+ replies.insert(reply, runningJob);
+ }
+ }
+}
+
+QDeclarativePixmapReader *QDeclarativePixmapReader::instance(QDeclarativeEngine *engine)
+{
+ // XXX NOTE: must be called within readerMutex locking.
+ QDeclarativePixmapReader *reader = readers.value(engine);
+ if (!reader) {
+ reader = new QDeclarativePixmapReader(engine);
+ readers.insert(engine, reader);
+ }
+
+ return reader;
+}
+
+QDeclarativePixmapReader *QDeclarativePixmapReader::existingInstance(QDeclarativeEngine *engine)
+{
+ // XXX NOTE: must be called within readerMutex locking.
+ return readers.value(engine, 0);
+}
+
+QDeclarativePixmapReply *QDeclarativePixmapReader::getImage(QDeclarativePixmapData *data)
+{
+ mutex.lock();
+ QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(data);
+ reply->engineForReader = engine;
+ jobs.append(reply);
+ // XXX
+ if (threadObject) threadObject->processJobs();
+ mutex.unlock();
+ return reply;
+}
+
+void QDeclarativePixmapReader::cancel(QDeclarativePixmapReply *reply)
+{
+ mutex.lock();
+ if (reply->loading) {
+ cancelled.append(reply);
+ reply->data = 0;
+ // XXX
+ if (threadObject) threadObject->processJobs();
+ } else {
+ jobs.removeAll(reply);
+ delete reply;
+ }
+ mutex.unlock();
+}
+
+void QDeclarativePixmapReader::run()
+{
+ if (replyDownloadProgress == -1) {
+ const QMetaObject *nr = &QNetworkReply::staticMetaObject;
+ const QMetaObject *pr = &QDeclarativePixmapReply::staticMetaObject;
+ const QMetaObject *ir = &QDeclarativePixmapReaderThreadObject::staticMetaObject;
+ replyDownloadProgress = nr->indexOfSignal("downloadProgress(qint64,qint64)");
+ replyFinished = nr->indexOfSignal("finished()");
+ downloadProgress = pr->indexOfSignal("downloadProgress(qint64,qint64)");
+ threadNetworkRequestDone = ir->indexOfSlot("networkRequestDone()");
+ }
+
+ mutex.lock();
+ threadObject = new QDeclarativePixmapReaderThreadObject(this);
+ mutex.unlock();
+
+ processJobs();
+ exec();
+
+ delete threadObject;
+ threadObject = 0;
+}
+
+class QDeclarativePixmapKey
+{
+public:
+ const QUrl *url;
+ const QSize *size;
+};
+
+inline bool operator==(const QDeclarativePixmapKey &lhs, const QDeclarativePixmapKey &rhs)
+{
+ return *lhs.size == *rhs.size && *lhs.url == *rhs.url;
+}
+
+inline uint qHash(const QDeclarativePixmapKey &key)
+{
+ return qHash(*key.url) ^ key.size->width() ^ key.size->height();
+}
+
+class QSGContext;
+
+class QDeclarativePixmapStore : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativePixmapStore();
+ ~QDeclarativePixmapStore();
+
+ void unreferencePixmap(QDeclarativePixmapData *);
+ void referencePixmap(QDeclarativePixmapData *);
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+public:
+ QHash<QDeclarativePixmapKey, QDeclarativePixmapData *> m_cache;
+
+private:
+ void shrinkCache(int remove);
+
+ QDeclarativePixmapData *m_unreferencedPixmaps;
+ QDeclarativePixmapData *m_lastUnreferencedPixmap;
+
+ int m_unreferencedCost;
+ int m_timerId;
+};
+Q_GLOBAL_STATIC(QDeclarativePixmapStore, pixmapStore);
+
+
+QDeclarativePixmapStore::QDeclarativePixmapStore()
+: m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1)
+{
+}
+
+QDeclarativePixmapStore::~QDeclarativePixmapStore()
+{
+ int leakedPixmaps = 0;
+ QList<QDeclarativePixmapData*> cachedData = m_cache.values();
+
+ // unreference all (leaked) pixmaps
+ foreach (QDeclarativePixmapData* pixmap, cachedData) {
+ int currRefCount = pixmap->refCount;
+ if (currRefCount) {
+ leakedPixmaps++;
+ while (currRefCount > 0) {
+ pixmap->release();
+ currRefCount--;
+ }
+ }
+ }
+
+ // free all unreferenced pixmaps
+ while (m_lastUnreferencedPixmap) {
+ shrinkCache(20);
+ }
+
+ if (leakedPixmaps)
+ qDebug("Number of leaked pixmaps: %i", leakedPixmaps);
+}
+
+void QDeclarativePixmapStore::unreferencePixmap(QDeclarativePixmapData *data)
+{
+ Q_ASSERT(data->prevUnreferenced == 0);
+ Q_ASSERT(data->prevUnreferencedPtr == 0);
+ Q_ASSERT(data->nextUnreferenced == 0);
+
+ data->nextUnreferenced = m_unreferencedPixmaps;
+ data->prevUnreferencedPtr = &m_unreferencedPixmaps;
+
+ m_unreferencedPixmaps = data;
+ if (m_unreferencedPixmaps->nextUnreferenced) {
+ m_unreferencedPixmaps->nextUnreferenced->prevUnreferenced = m_unreferencedPixmaps;
+ m_unreferencedPixmaps->nextUnreferenced->prevUnreferencedPtr = &m_unreferencedPixmaps->nextUnreferenced;
+ }
+
+ if (!m_lastUnreferencedPixmap)
+ m_lastUnreferencedPixmap = data;
+
+ m_unreferencedCost += data->cost();
+
+ shrinkCache(-1); // Shrink the cache incase it has become larger than cache_limit
+
+ if (m_timerId == -1 && m_unreferencedPixmaps)
+ m_timerId = startTimer(CACHE_EXPIRE_TIME * 1000);
+}
+
+void QDeclarativePixmapStore::referencePixmap(QDeclarativePixmapData *data)
+{
+ Q_ASSERT(data->prevUnreferencedPtr);
+
+ *data->prevUnreferencedPtr = data->nextUnreferenced;
+ if (data->nextUnreferenced) {
+ data->nextUnreferenced->prevUnreferencedPtr = data->prevUnreferencedPtr;
+ data->nextUnreferenced->prevUnreferenced = data->prevUnreferenced;
+ }
+ if (m_lastUnreferencedPixmap == data)
+ m_lastUnreferencedPixmap = data->prevUnreferenced;
+
+ data->nextUnreferenced = 0;
+ data->prevUnreferencedPtr = 0;
+ data->prevUnreferenced = 0;
+
+ m_unreferencedCost -= data->cost();
+}
+
+void QDeclarativePixmapStore::shrinkCache(int remove)
+{
+ while ((remove > 0 || m_unreferencedCost > cache_limit) && m_lastUnreferencedPixmap) {
+ QDeclarativePixmapData *data = m_lastUnreferencedPixmap;
+ Q_ASSERT(data->nextUnreferenced == 0);
+
+ *data->prevUnreferencedPtr = 0;
+ m_lastUnreferencedPixmap = data->prevUnreferenced;
+ data->prevUnreferencedPtr = 0;
+ data->prevUnreferenced = 0;
+
+ remove -= data->cost();
+ m_unreferencedCost -= data->cost();
+ data->removeFromCache();
+ delete data;
+ }
+}
+
+void QDeclarativePixmapStore::timerEvent(QTimerEvent *)
+{
+ int removalCost = m_unreferencedCost / CACHE_REMOVAL_FRACTION;
+
+ shrinkCache(removalCost);
+
+ if (m_unreferencedPixmaps == 0) {
+ killTimer(m_timerId);
+ m_timerId = -1;
+ }
+}
+
+QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativePixmapData *d)
+: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0)
+{
+ if (finishedIndex == -1) {
+ finishedIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()");
+ downloadProgressIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)");
+ }
+}
+
+QDeclarativePixmapReply::~QDeclarativePixmapReply()
+{
+}
+
+bool QDeclarativePixmapReply::event(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+
+ if (data) {
+ Event *de = static_cast<Event *>(event);
+ data->pixmapStatus = (de->error == NoError) ? QDeclarativePixmap::Ready : QDeclarativePixmap::Error;
+
+ if (data->pixmapStatus == QDeclarativePixmap::Ready) {
+ if (de->textureFactory) {
+ data->textureFactory = de->textureFactory;
+ }
+ data->image = de->image;
+ data->implicitSize = de->implicitSize;
+ } else {
+ data->errorString = de->errorString;
+ data->removeFromCache(); // We don't continue to cache error'd pixmaps
+ }
+
+ data->reply = 0;
+ emit finished();
+ }
+
+ delete this;
+ return true;
+ } else {
+ return QObject::event(event);
+ }
+}
+
+int QDeclarativePixmapData::cost() const
+{
+ if (textureFactory)
+ return textureFactory->textureByteCount();
+ return image.byteCount();
+}
+
+void QDeclarativePixmapData::addref()
+{
+ ++refCount;
+ if (prevUnreferencedPtr)
+ pixmapStore()->referencePixmap(this);
+}
+
+void QDeclarativePixmapData::release()
+{
+ Q_ASSERT(refCount > 0);
+ --refCount;
+ if (refCount == 0) {
+ if (reply) {
+ QDeclarativePixmapReply *cancelReply = reply;
+ reply->data = 0;
+ reply = 0;
+ QDeclarativePixmapReader::readerMutex.lock();
+ QDeclarativePixmapReader *reader = QDeclarativePixmapReader::existingInstance(cancelReply->engineForReader);
+ if (reader)
+ reader->cancel(cancelReply);
+ QDeclarativePixmapReader::readerMutex.unlock();
+ }
+
+ if (pixmapStatus == QDeclarativePixmap::Ready) {
+ pixmapStore()->unreferencePixmap(this);
+ } else {
+ removeFromCache();
+ delete this;
+ }
+ }
+}
+
+void QDeclarativePixmapData::addToCache()
+{
+ if (!inCache) {
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ pixmapStore()->m_cache.insert(key, this);
+ inCache = true;
+ }
+}
+
+void QDeclarativePixmapData::removeFromCache()
+{
+ if (inCache) {
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ pixmapStore()->m_cache.remove(key);
+ inCache = false;
+ }
+}
+
+static QDeclarativePixmapData* createPixmapDataSync(QDeclarativePixmap *declarativePixmap, QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool *ok)
+{
+ if (url.scheme() == QLatin1String("image")) {
+ QSize readSize;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+
+ switch (imageType) {
+ case QDeclarativeImageProvider::Invalid:
+ return new QDeclarativePixmapData(declarativePixmap, url, requestSize,
+ QDeclarativePixmap::tr("Invalid image provider: %1").arg(url.toString()));
+ case QDeclarativeImageProvider::Texture:
+ {
+ QDeclarativeTextureFactory *texture = ep->getTextureFromProvider(url, &readSize, requestSize);
+ if (texture) {
+ *ok = true;
+ return new QDeclarativePixmapData(declarativePixmap, url, texture, QImage(), readSize, requestSize);
+ }
+ }
+
+ case QDeclarativeImageProvider::Image:
+ {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ if (!image.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(declarativePixmap, url, image, readSize, requestSize);
+ }
+ }
+ case QDeclarativeImageProvider::Pixmap:
+ {
+ QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
+ if (!pixmap.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(declarativePixmap, url, pixmap.toImage(), readSize, requestSize);
+ }
+ }
+ }
+
+ // provider has bad image type, or provider returned null image
+ return new QDeclarativePixmapData(declarativePixmap, url, requestSize,
+ QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()));
+ }
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+ if (localFile.isEmpty())
+ return 0;
+
+ QFile f(localFile);
+ QSize readSize;
+ QString errorString;
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QImage image;
+
+ if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+ *ok = true;
+ return new QDeclarativePixmapData(declarativePixmap, url, image, readSize, requestSize);
+ }
+ errorString = QDeclarativePixmap::tr("Invalid image data: %1").arg(url.toString());
+
+ } else {
+ errorString = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
+ }
+ return new QDeclarativePixmapData(declarativePixmap, url, requestSize, errorString);
+}
+
+
+struct QDeclarativePixmapNull {
+ QUrl url;
+ QImage image;
+ QSize size;
+};
+Q_GLOBAL_STATIC(QDeclarativePixmapNull, nullPixmap);
+
+QDeclarativePixmap::QDeclarativePixmap()
+: d(0)
+{
+}
+
+QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url)
+: d(0)
+{
+ load(engine, url);
+}
+
+QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url, const QSize &size)
+: d(0)
+{
+ load(engine, url, size);
+}
+
+QDeclarativePixmap::~QDeclarativePixmap()
+{
+ if (d) {
+ d->declarativePixmaps.remove(this);
+ d->release();
+ d = 0;
+ }
+}
+
+bool QDeclarativePixmap::isNull() const
+{
+ return d == 0;
+}
+
+bool QDeclarativePixmap::isReady() const
+{
+ return status() == Ready;
+}
+
+bool QDeclarativePixmap::isError() const
+{
+ return status() == Error;
+}
+
+bool QDeclarativePixmap::isLoading() const
+{
+ return status() == Loading;
+}
+
+QString QDeclarativePixmap::error() const
+{
+ if (d)
+ return d->errorString;
+ else
+ return QString();
+}
+
+QDeclarativePixmap::Status QDeclarativePixmap::status() const
+{
+ if (d)
+ return d->pixmapStatus;
+ else
+ return Null;
+}
+
+const QUrl &QDeclarativePixmap::url() const
+{
+ if (d)
+ return d->url;
+ else
+ return nullPixmap()->url;
+}
+
+const QSize &QDeclarativePixmap::implicitSize() const
+{
+ if (d)
+ return d->implicitSize;
+ else
+ return nullPixmap()->size;
+}
+
+const QSize &QDeclarativePixmap::requestSize() const
+{
+ if (d)
+ return d->requestSize;
+ else
+ return nullPixmap()->size;
+}
+
+QDeclarativeTextureFactory *QDeclarativePixmap::textureFactory() const
+{
+ if (d)
+ return d->textureFactory;
+
+ return 0;
+}
+
+const QImage &QDeclarativePixmap::image() const
+{
+ if (d)
+ return d->image;
+ else
+ return nullPixmap()->image;
+}
+
+void QDeclarativePixmap::setImage(const QImage &p)
+{
+ clear();
+
+ if (!p.isNull())
+ d = new QDeclarativePixmapData(this, p);
+}
+
+int QDeclarativePixmap::width() const
+{
+ if (d)
+ return d->textureFactory ? d->textureFactory->textureSize().width() : d->image.width();
+ else
+ return 0;
+}
+
+int QDeclarativePixmap::height() const
+{
+ if (d)
+ return d->textureFactory ? d->textureFactory->textureSize().height() : d->image.height();
+ else
+ return 0;
+}
+
+QRect QDeclarativePixmap::rect() const
+{
+ if (d)
+ return d->textureFactory ? QRect(QPoint(), d->textureFactory->textureSize()) : d->image.rect();
+ else
+ return QRect();
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url)
+{
+ load(engine, url, QSize(), QDeclarativePixmap::Cache);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, QDeclarativePixmap::Options options)
+{
+ load(engine, url, QSize(), options);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &size)
+{
+ load(engine, url, size, QDeclarativePixmap::Cache);
+}
+
+void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, QDeclarativePixmap::Options options)
+{
+ if (d) {
+ d->declarativePixmaps.remove(this);
+ d->release();
+ d = 0;
+ }
+
+ QDeclarativePixmapKey key = { &url, &requestSize };
+ QDeclarativePixmapStore *store = pixmapStore();
+
+ QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::Iterator iter = store->m_cache.find(key);
+
+ if (iter == store->m_cache.end()) {
+ if (options & QDeclarativePixmap::Asynchronous) {
+ // pixmaps can only be loaded synchronously
+ if (url.scheme() == QLatin1String("image")
+ && QDeclarativeEnginePrivate::get(engine)->getImageProviderType(url) == QDeclarativeImageProvider::Pixmap) {
+ options &= ~QDeclarativePixmap::Asynchronous;
+ }
+ }
+
+ if (!(options & QDeclarativePixmap::Asynchronous)) {
+ bool ok = false;
+ d = createPixmapDataSync(this, engine, url, requestSize, &ok);
+ if (ok) {
+ if (options & QDeclarativePixmap::Cache)
+ d->addToCache();
+ return;
+ }
+ if (d) // loadable, but encountered error while loading
+ return;
+ }
+
+ if (!engine)
+ return;
+
+ d = new QDeclarativePixmapData(this, url, requestSize);
+ if (options & QDeclarativePixmap::Cache)
+ d->addToCache();
+
+ QDeclarativePixmapReader::readerMutex.lock();
+ d->reply = QDeclarativePixmapReader::instance(engine)->getImage(d);
+ QDeclarativePixmapReader::readerMutex.unlock();
+ } else {
+ d = *iter;
+ d->addref();
+ d->declarativePixmaps.insert(this);
+ }
+}
+
+void QDeclarativePixmap::clear()
+{
+ if (d) {
+ d->declarativePixmaps.remove(this);
+ d->release();
+ d = 0;
+ }
+}
+
+void QDeclarativePixmap::clear(QObject *obj)
+{
+ if (d) {
+ if (d->reply)
+ QObject::disconnect(d->reply, 0, obj, 0);
+ d->declarativePixmaps.remove(this);
+ d->release();
+ d = 0;
+ }
+}
+
+bool QDeclarativePixmap::connectFinished(QObject *object, const char *method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectFinished() called when not loading.");
+ return false;
+ }
+
+ return QObject::connect(d->reply, SIGNAL(finished()), object, method);
+}
+
+bool QDeclarativePixmap::connectFinished(QObject *object, int method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectFinished() called when not loading.");
+ return false;
+ }
+
+ return QMetaObject::connect(d->reply, QDeclarativePixmapReply::finishedIndex, object, method);
+}
+
+bool QDeclarativePixmap::connectDownloadProgress(QObject *object, const char *method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading.");
+ return false;
+ }
+
+ return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), object, method);
+}
+
+bool QDeclarativePixmap::connectDownloadProgress(QObject *object, int method)
+{
+ if (!d || !d->reply) {
+ qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading.");
+ return false;
+ }
+
+ return QMetaObject::connect(d->reply, QDeclarativePixmapReply::downloadProgressIndex, object, method);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativepixmapcache.moc>
diff --git a/src/quick/util/qdeclarativepixmapcache_p.h b/src/quick/util/qdeclarativepixmapcache_p.h
new file mode 100644
index 0000000000..ee55519f93
--- /dev/null
+++ b/src/quick/util/qdeclarativepixmapcache_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPIXMAPCACHE_H
+#define QDECLARATIVEPIXMAPCACHE_H
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qpixmap.h>
+#include <QtCore/qurl.h>
+#include <QtQuick/qtquickglobal.h>
+
+#include <private/qintrusivelist_p.h>
+#include <qdeclarativeimageprovider.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeEngine;
+class QDeclarativePixmapData;
+class QDeclarativeTextureFactory;
+
+class QDeclarativeDefaultTextureFactory : public QDeclarativeTextureFactory
+{
+ Q_OBJECT
+public:
+ QDeclarativeDefaultTextureFactory(const QImage &i)
+ : im(i)
+ {
+ }
+
+ QSGTexture *createTexture() const;
+ QSize textureSize() const { return im.size(); }
+ int textureByteCount() const { return im.byteCount(); }
+ QImage image() const { return im; }
+
+private:
+ QImage im;
+};
+
+class Q_QUICK_EXPORT QDeclarativePixmap
+{
+ Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmap)
+public:
+ QDeclarativePixmap();
+ QDeclarativePixmap(QDeclarativeEngine *, const QUrl &);
+ QDeclarativePixmap(QDeclarativeEngine *, const QUrl &, const QSize &);
+ ~QDeclarativePixmap();
+
+ enum Status { Null, Ready, Error, Loading };
+
+ enum Option {
+ Asynchronous = 0x00000001,
+ Cache = 0x00000002
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ bool isNull() const;
+ bool isReady() const;
+ bool isError() const;
+ bool isLoading() const;
+
+ Status status() const;
+ QString error() const;
+ const QUrl &url() const;
+ const QSize &implicitSize() const;
+ const QSize &requestSize() const;
+ const QImage &image() const;
+ void setImage(const QImage &);
+
+ QDeclarativeTextureFactory *textureFactory() const;
+
+ QRect rect() const;
+ int width() const;
+ int height() const;
+
+ void load(QDeclarativeEngine *, const QUrl &);
+ void load(QDeclarativeEngine *, const QUrl &, QDeclarativePixmap::Options options);
+ void load(QDeclarativeEngine *, const QUrl &, const QSize &);
+ void load(QDeclarativeEngine *, const QUrl &, const QSize &, QDeclarativePixmap::Options options);
+
+ void clear();
+ void clear(QObject *);
+
+ bool connectFinished(QObject *, const char *);
+ bool connectFinished(QObject *, int);
+ bool connectDownloadProgress(QObject *, const char *);
+ bool connectDownloadProgress(QObject *, int);
+
+private:
+ Q_DISABLE_COPY(QDeclarativePixmap)
+ QDeclarativePixmapData *d;
+ QIntrusiveListNode dataListNode;
+ friend class QDeclarativePixmapData;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePixmap::Options)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPIXMAPCACHE_H
diff --git a/src/quick/util/qdeclarativepropertychanges.cpp b/src/quick/util/qdeclarativepropertychanges.cpp
new file mode 100644
index 0000000000..d6035fa9d2
--- /dev/null
+++ b/src/quick/util/qdeclarativepropertychanges.cpp
@@ -0,0 +1,796 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepropertychanges_p.h"
+
+#include <private/qdeclarativeopenmetaobject_p.h>
+#include <private/qdeclarativerewrite_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativecustomparser_p.h>
+#include <private/qdeclarativescript_p.h>
+#include <qdeclarativeexpression.h>
+#include <private/qdeclarativebinding_p.h>
+#include <qdeclarativecontext.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativestate_p_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass PropertyChanges QDeclarativePropertyChanges
+ \inqmlmodule QtQuick 2
+ \ingroup qml-state-elements
+ \brief The PropertyChanges element describes new property bindings or values for a state.
+
+ PropertyChanges is used to define the property values or bindings in a
+ \l State. This enables an item's property values to be changed when it
+ \l {QML States}{changes between states}.
+
+ To create a PropertyChanges object, specify the \l target item whose
+ properties are to be modified, and define the new property values or
+ bindings. For example:
+
+ \snippet doc/src/snippets/declarative/propertychanges.qml import
+ \codeline
+ \snippet doc/src/snippets/declarative/propertychanges.qml 0
+
+ When the mouse is pressed, the \l Rectangle changes to the \e resized
+ state. In this state, the PropertyChanges object sets the rectangle's
+ color to blue and the \c height value to that of \c container.height.
+
+ Note this automatically binds \c rect.height to \c container.height
+ in the \e resized state. If a property binding should not be
+ established, and the height should just be set to the value of
+ \c container.height at the time of the state change, set the \l explicit
+ property to \c true.
+
+ A PropertyChanges object can also override the default signal handler
+ for an object to implement a signal handler specific to the new state:
+
+ \qml
+ PropertyChanges {
+ target: myMouseArea
+ onClicked: doSomethingDifferent()
+ }
+ \endqml
+
+ \note PropertyChanges can be used to change anchor margins, but not other anchor
+ values; use AnchorChanges for this instead. Similarly, to change an \l Item's
+ \l {Item::}{parent} value, use ParentChanges instead.
+
+
+ \section2 Resetting property values
+
+ The \c undefined value can be used to reset the property value for a state.
+ In the following example, when \c myText changes to the \e widerText
+ state, its \c width property is reset, giving the text its natural width
+ and displaying the whole string on a single line.
+
+ \snippet doc/src/snippets/declarative/propertychanges.qml reset
+
+
+ \section2 Immediate property changes in transitions
+
+ When \l{QML Animation and Transitions}{Transitions} are used to animate
+ state changes, they animate properties from their values in the current
+ state to those defined in the new state (as defined by PropertyChanges
+ objects). However, it is sometimes desirable to set a property value
+ \e immediately during a \l Transition, without animation; in these cases,
+ the PropertyAction element can be used to force an immediate property
+ change.
+
+ See the PropertyAction documentation for more details.
+
+ \sa {declarative/animation/states}{states example}, {qmlstate}{States}, QtDeclarative
+*/
+
+/*!
+ \qmlproperty Object QtQuick2::PropertyChanges::target
+ This property holds the object which contains the properties to be changed.
+*/
+
+class QDeclarativeReplaceSignalHandler : public QDeclarativeActionEvent
+{
+public:
+ QDeclarativeReplaceSignalHandler() : expression(0), reverseExpression(0),
+ rewindExpression(0), ownedExpression(0) {}
+ ~QDeclarativeReplaceSignalHandler() {
+ delete ownedExpression;
+ }
+
+ virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
+
+ QDeclarativeProperty property;
+ QDeclarativeExpression *expression;
+ QDeclarativeExpression *reverseExpression;
+ QDeclarativeExpression *rewindExpression;
+ QDeclarativeGuard<QDeclarativeExpression> ownedExpression;
+
+ virtual void execute(Reason) {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
+ if (ownedExpression == expression)
+ ownedExpression = 0;
+ }
+
+ virtual bool isReversable() { return true; }
+ virtual void reverse(Reason) {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
+ if (ownedExpression == reverseExpression)
+ ownedExpression = 0;
+ }
+
+ virtual void saveOriginals() {
+ saveCurrentValues();
+ reverseExpression = rewindExpression;
+ }
+
+ virtual bool needsCopy() { return true; }
+ virtual void copyOriginals(QDeclarativeActionEvent *other)
+ {
+ QDeclarativeReplaceSignalHandler *rsh = static_cast<QDeclarativeReplaceSignalHandler*>(other);
+ saveCurrentValues();
+ if (rsh == this)
+ return;
+ reverseExpression = rsh->reverseExpression;
+ if (rsh->ownedExpression == reverseExpression) {
+ ownedExpression = rsh->ownedExpression;
+ rsh->ownedExpression = 0;
+ }
+ }
+
+ virtual void rewind() {
+ ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression);
+ if (ownedExpression == rewindExpression)
+ ownedExpression = 0;
+ }
+ virtual void saveCurrentValues() {
+ rewindExpression = QDeclarativePropertyPrivate::signalExpression(property);
+ }
+
+ virtual bool override(QDeclarativeActionEvent*other) {
+ if (other == this)
+ return true;
+ if (other->typeName() != typeName())
+ return false;
+ if (static_cast<QDeclarativeReplaceSignalHandler*>(other)->property == property)
+ return true;
+ return false;
+ }
+};
+
+
+class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativePropertyChanges)
+public:
+ QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
+ isExplicit(false) {}
+
+ QDeclarativeGuard<QObject> object;
+ QByteArray data;
+
+ bool decoded : 1;
+ bool restore : 1;
+ bool isExplicit : 1;
+
+ void decode();
+
+ class ExpressionChange {
+ public:
+ ExpressionChange(const QString &_name,
+ QDeclarativeBinding::Identifier _id,
+ QDeclarativeExpression *_expr)
+ : name(_name), id(_id), expression(_expr) {}
+ QString name;
+ QDeclarativeBinding::Identifier id;
+ QDeclarativeExpression *expression;
+ };
+
+ QList<QPair<QString, QVariant> > properties;
+ QList<ExpressionChange> expressions;
+ QList<QDeclarativeReplaceSignalHandler*> signalReplacements;
+
+ QDeclarativeProperty property(const QString &);
+};
+
+void
+QDeclarativePropertyChangesParser::compileList(QList<QPair<QString, QVariant> > &list,
+ const QString &pre,
+ const QDeclarativeCustomParserProperty &prop)
+{
+ QString 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<QDeclarativeCustomParserNode>()) {
+ error(qvariant_cast<QDeclarativeCustomParserNode>(value),
+ QDeclarativePropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
+ continue;
+ } else if(value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
+
+ QDeclarativeCustomParserProperty prop =
+ qvariant_cast<QDeclarativeCustomParserProperty>(value);
+ QString pre = propName + QLatin1Char('.');
+ compileList(list, pre, prop);
+
+ } else {
+ list << qMakePair(propName, value);
+ }
+ }
+}
+
+QByteArray
+QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
+{
+ QList<QPair<QString, QVariant> > data;
+ for(int ii = 0; ii < props.count(); ++ii)
+ compileList(data, QString(), props.at(ii));
+
+ QByteArray rv;
+ QDataStream ds(&rv, QIODevice::WriteOnly);
+
+ ds << data.count();
+ for(int ii = 0; ii < data.count(); ++ii) {
+ QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(data.at(ii).second);
+ QVariant var;
+ bool isScript = v.isScript();
+ QDeclarativeBinding::Identifier id = 0;
+ switch(v.type()) {
+ case QDeclarativeScript::Variant::Boolean:
+ var = QVariant(v.asBoolean());
+ break;
+ case QDeclarativeScript::Variant::Number:
+ var = QVariant(v.asNumber());
+ break;
+ case QDeclarativeScript::Variant::String:
+ var = QVariant(v.asString());
+ break;
+ case QDeclarativeScript::Variant::Invalid:
+ case QDeclarativeScript::Variant::Script:
+ var = QVariant(v.asScript());
+ {
+ // Pre-rewrite the expression
+ id = rewriteBinding(v, data.at(ii).first);
+ }
+ break;
+ }
+
+ ds << data.at(ii).first << isScript << var;
+ if (isScript)
+ ds << id;
+ }
+
+ return rv;
+}
+
+void QDeclarativePropertyChangesPrivate::decode()
+{
+ Q_Q(QDeclarativePropertyChanges);
+ if (decoded)
+ return;
+
+ QDataStream ds(&data, QIODevice::ReadOnly);
+
+ int count;
+ ds >> count;
+ for (int ii = 0; ii < count; ++ii) {
+ QString name;
+ bool isScript;
+ QVariant data;
+ QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid;
+ ds >> name;
+ ds >> isScript;
+ ds >> data;
+ if (isScript)
+ ds >> id;
+
+ QDeclarativeProperty prop = property(name); //### better way to check for signal property?
+ if (prop.type() & QDeclarativeProperty::SignalProperty) {
+ QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
+ QDeclarativeData *ddata = QDeclarativeData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ QDeclarativeReplaceSignalHandler *handler = new QDeclarativeReplaceSignalHandler;
+ handler->property = prop;
+ handler->expression = expression;
+ signalReplacements << handler;
+ } else if (isScript) {
+ QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
+ QDeclarativeData *ddata = QDeclarativeData::get(q);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
+ expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
+ expressions << ExpressionChange(name, id, expression);
+ } else {
+ properties << qMakePair(name, data);
+ }
+ }
+
+ decoded = true;
+ data.clear();
+}
+
+void QDeclarativePropertyChangesParser::setCustomData(QObject *object,
+ const QByteArray &data)
+{
+ QDeclarativePropertyChangesPrivate *p =
+ static_cast<QDeclarativePropertyChangesPrivate *>(QObjectPrivate::get(object));
+ p->data = data;
+ p->decoded = false;
+}
+
+QDeclarativePropertyChanges::QDeclarativePropertyChanges()
+: QDeclarativeStateOperation(*(new QDeclarativePropertyChangesPrivate))
+{
+}
+
+QDeclarativePropertyChanges::~QDeclarativePropertyChanges()
+{
+ Q_D(QDeclarativePropertyChanges);
+ for(int ii = 0; ii < d->expressions.count(); ++ii)
+ delete d->expressions.at(ii).expression;
+ for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
+ delete d->signalReplacements.at(ii);
+}
+
+QObject *QDeclarativePropertyChanges::object() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->object;
+}
+
+void QDeclarativePropertyChanges::setObject(QObject *o)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->object = o;
+}
+
+/*!
+ \qmlproperty bool QtQuick2::PropertyChanges::restoreEntryValues
+
+ This property holds whether the previous values should be restored when
+ leaving the state.
+
+ The default value is \c true. Setting this value to \c false creates a
+ temporary state that has permanent effects on property values.
+*/
+bool QDeclarativePropertyChanges::restoreEntryValues() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->restore;
+}
+
+void QDeclarativePropertyChanges::setRestoreEntryValues(bool v)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->restore = v;
+}
+
+QDeclarativeProperty
+QDeclarativePropertyChangesPrivate::property(const QString &property)
+{
+ Q_Q(QDeclarativePropertyChanges);
+ QDeclarativeProperty prop(object, property, qmlContext(q));
+ if (!prop.isValid()) {
+ qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
+ return QDeclarativeProperty();
+ } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) {
+ qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
+ return QDeclarativeProperty();
+ }
+ return prop;
+}
+
+QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
+{
+ Q_D(QDeclarativePropertyChanges);
+
+ d->decode();
+
+ ActionList list;
+
+ for (int ii = 0; ii < d->properties.count(); ++ii) {
+
+ QDeclarativeAction a(d->object, d->properties.at(ii).first,
+ qmlContext(this), d->properties.at(ii).second);
+
+ if (a.property.isValid()) {
+ a.restore = restoreEntryValues();
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
+
+ QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
+
+ if (handler->property.isValid()) {
+ QDeclarativeAction a;
+ a.event = handler;
+ list << a;
+ }
+ }
+
+ for (int ii = 0; ii < d->expressions.count(); ++ii) {
+
+ const QString &property = d->expressions.at(ii).name;
+ QDeclarativeProperty prop = d->property(property);
+
+ if (prop.isValid()) {
+ QDeclarativeAction a;
+ a.restore = restoreEntryValues();
+ a.property = prop;
+ a.fromValue = a.property.read();
+ a.specifiedObject = d->object;
+ a.specifiedProperty = property;
+
+ if (d->isExplicit) {
+ a.toValue = d->expressions.at(ii).expression->evaluate();
+ } else {
+ QDeclarativeExpression *e = d->expressions.at(ii).expression;
+
+ QDeclarativeBinding::Identifier id = d->expressions.at(ii).id;
+ QDeclarativeBinding *newBinding = id != QDeclarativeBinding::Invalid ? QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0;
+ if (!newBinding) {
+ newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
+ newBinding->setSourceLocation(e->sourceFile(), e->lineNumber());
+ }
+ newBinding->setTarget(prop);
+ a.toBinding = newBinding;
+ a.deletableToBinding = true;
+ }
+
+ list << a;
+ }
+ }
+
+ return list;
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 \c myItem.width from
+ being bound to \c parent.width. Instead, it is assigned the value of \c 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 QDeclarativePropertyChanges::isExplicit() const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ return d->isExplicit;
+}
+
+void QDeclarativePropertyChanges::setIsExplicit(bool e)
+{
+ Q_D(QDeclarativePropertyChanges);
+ d->isExplicit = e;
+}
+
+bool QDeclarativePropertyChanges::containsValue(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsExpression(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativePropertyChanges::containsProperty(const QString &name) const
+{
+ return containsValue(name) || containsExpression(name);
+}
+
+void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ expressionIterator.remove();
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+ d->property(name).write(value);
+ }
+
+ d->properties.append(PropertyEntry(name, value));
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ entry.second = value;
+ if (state() && state()->isStateActive())
+ d->property(name).write(value);
+ return;
+ }
+ }
+
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = name;
+ action.toValue = value;
+
+ propertyIterator.insert(PropertyEntry(name, value));
+ if (state() && state()->isStateActive()) {
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ d->property(name).write(value);
+ }
+}
+
+void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ bool hadValue = false;
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ hadValue = true;
+ break;
+ }
+ }
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ entry.expression->setExpression(expression);
+ if (state() && state()->isStateActive()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ return;
+ }
+ }
+
+ QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
+ expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
+
+ if (state() && state()->isStateActive()) {
+ if (hadValue) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
+ if (oldBinding) {
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ state()->changeBindingInRevertList(object(), name, oldBinding);
+ }
+
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ } else {
+ QDeclarativeAction action;
+ action.restore = restoreEntryValues();
+ action.property = d->property(name);
+ action.fromValue = action.property.read();
+ action.specifiedObject = object();
+ action.specifiedProperty = name;
+
+
+ if (d->isExplicit) {
+ action.toValue = newExpression->evaluate();
+ } else {
+ QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
+ newBinding->setTarget(d->property(name));
+ action.toBinding = newBinding;
+ action.deletableToBinding = true;
+
+ state()->addEntryToRevertList(action);
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
+ if (oldBinding)
+ oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+
+ QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
+ }
+ }
+ }
+ // what about the signal handler?
+}
+
+QVariant QDeclarativePropertyChanges::property(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return QVariant(entry.expression->expression());
+ }
+ }
+
+ return QVariant();
+}
+
+void QDeclarativePropertyChanges::removeProperty(const QString &name)
+{
+ Q_D(QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ expressionIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+
+ QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ propertyIterator.remove();
+ state()->removeEntryFromRevertList(object(), name);
+ return;
+ }
+ }
+}
+
+QVariant QDeclarativePropertyChanges::value(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QPair<QString, QVariant> PropertyEntry;
+
+ QListIterator<PropertyEntry> propertyIterator(d->properties);
+ while (propertyIterator.hasNext()) {
+ const PropertyEntry &entry = propertyIterator.next();
+ if (entry.first == name) {
+ return entry.second;
+ }
+ }
+
+ return QVariant();
+}
+
+QString QDeclarativePropertyChanges::expression(const QString &name) const
+{
+ Q_D(const QDeclarativePropertyChanges);
+ typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
+
+ QListIterator<ExpressionEntry> expressionIterator(d->expressions);
+ while (expressionIterator.hasNext()) {
+ const ExpressionEntry &entry = expressionIterator.next();
+ if (entry.name == name) {
+ return entry.expression->expression();
+ }
+ }
+
+ return QString();
+}
+
+void QDeclarativePropertyChanges::detachFromState()
+{
+ if (state())
+ state()->removeAllEntriesFromRevertList(object());
+}
+
+void QDeclarativePropertyChanges::attachToState()
+{
+ if (state())
+ state()->addEntriesToRevertList(actions());
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativepropertychanges_p.h b/src/quick/util/qdeclarativepropertychanges_p.h
new file mode 100644
index 0000000000..73f308874d
--- /dev/null
+++ b/src/quick/util/qdeclarativepropertychanges_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPROPERTYCHANGES_H
+#define QDECLARATIVEPROPERTYCHANGES_H
+
+#include "qdeclarativestateoperations_p.h"
+#include <private/qdeclarativecustomparser_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativePropertyChangesPrivate;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativePropertyChanges : public QDeclarativeStateOperation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativePropertyChanges)
+
+ 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:
+ QDeclarativePropertyChanges();
+ ~QDeclarativePropertyChanges();
+
+ QObject *object() const;
+ void setObject(QObject *);
+
+ bool restoreEntryValues() const;
+ void setRestoreEntryValues(bool);
+
+ bool isExplicit() const;
+ void setIsExplicit(bool);
+
+ virtual ActionList actions();
+
+ bool containsProperty(const QString &name) const;
+ bool containsValue(const QString &name) const;
+ bool containsExpression(const QString &name) const;
+ void changeValue(const QString &name, const QVariant &value);
+ void changeExpression(const QString &name, const QString &expression);
+ void removeProperty(const QString &name);
+ QVariant value(const QString &name) const;
+ QString expression(const QString &name) const;
+
+ void detachFromState();
+ void attachToState();
+
+ QVariant property(const QString &name) const;
+};
+
+class QDeclarativePropertyChangesParser : public QDeclarativeCustomParser
+{
+public:
+ QDeclarativePropertyChangesParser()
+ : QDeclarativeCustomParser(AcceptsAttachedProperties) {}
+
+ void compileList(QList<QPair<QString, QVariant> > &list, const QString &pre, const QDeclarativeCustomParserProperty &prop);
+
+ virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &);
+ virtual void setCustomData(QObject *, const QByteArray &);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePropertyChanges)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPROPERTYCHANGES_H
diff --git a/src/quick/util/qdeclarativesmoothedanimation.cpp b/src/quick/util/qdeclarativesmoothedanimation.cpp
new file mode 100644
index 0000000000..45c6885fbb
--- /dev/null
+++ b/src/quick/util/qdeclarativesmoothedanimation.cpp
@@ -0,0 +1,503 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativesmoothedanimation_p.h"
+#include "qdeclarativesmoothedanimation_p_p.h"
+
+#include "qdeclarativeanimation_p_p.h"
+
+#include <qdeclarativeproperty.h>
+#include <private/qdeclarativeproperty_p.h>
+
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <math.h>
+
+#define DELAY_STOP_TIMER_INTERVAL 32
+
+QT_BEGIN_NAMESPACE
+
+QSmoothedAnimation::QSmoothedAnimation(QObject *parent)
+ : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1),
+ reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0),
+ trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0)
+{
+}
+
+void QSmoothedAnimation::restart()
+{
+ initialVelocity = trackVelocity;
+ if (state() != QAbstractAnimation::Running)
+ start();
+ else
+ init();
+}
+
+void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
+{
+ if (newState == QAbstractAnimation::Running)
+ init();
+}
+
+void QSmoothedAnimation::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == delayedStopTimer.timerId()) {
+ delayedStopTimer.stop();
+ stop();
+ } else {
+ QAbstractAnimation::timerEvent(event);
+ }
+}
+
+void QSmoothedAnimation::delayedStop()
+{
+ if (!delayedStopTimer.isActive())
+ delayedStopTimer.start(DELAY_STOP_TIMER_INTERVAL, this);
+}
+
+int QSmoothedAnimation::duration() const
+{
+ return -1;
+}
+
+bool QSmoothedAnimation::recalc()
+{
+ s = to - initialValue;
+ vi = initialVelocity;
+
+ s = (invert? -1.0: 1.0) * s;
+
+ if (userDuration > 0 && velocity > 0) {
+ tf = s / velocity;
+ if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.);
+ } else if (userDuration > 0) {
+ tf = userDuration / 1000.;
+ } else if (velocity > 0) {
+ tf = s / velocity;
+ } else {
+ return false;
+ }
+
+ finalDuration = ceil(tf * 1000.0);
+
+ 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.;
+ /* tp| |td
+ * vp_ _______
+ * / \
+ * vi_ / \
+ * \
+ * \ _ 0
+ * |ta| |ta|
+ */
+ qreal ta = met / 2.;
+ a = (s - (vi * tf - 0.5 * vi * ta)) / (tf * ta - ta * ta);
+
+ vp = vi + a * ta;
+ d = vp / ta;
+ tp = ta;
+ sp = vi * ta + 0.5 * a * tp * tp;
+ sd = sp + vp * (tf - 2 * ta);
+ td = tf - ta;
+ } 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 tp1 = 0.5 * tf - 0.5 * vi / a1;
+ qreal vp1 = a1 * tp1 + vi;
+
+ qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
+
+ a = a1;
+ d = a1;
+ tp = tp1;
+ td = tp1;
+ vp = vp1;
+ sp = sp1;
+ sd = sp1;
+ }
+ return true;
+}
+
+qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
+{
+ qreal value;
+ if (time_seconds < tp) {
+ trackVelocity = vi + time_seconds * a;
+ value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
+ } else if (time_seconds < td) {
+ time_seconds -= tp;
+ trackVelocity = vp;
+ value = sp + time_seconds * vp;
+ } else if (time_seconds < tf) {
+ time_seconds -= td;
+ trackVelocity = vp - time_seconds * a;
+ value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
+ } else {
+ trackVelocity = 0;
+ value = s;
+ delayedStop();
+ }
+
+ // to normalize 's' between [0..1], divide 'value' by 's'
+ return value;
+}
+
+void QSmoothedAnimation::updateCurrentTime(int t)
+{
+ qreal time_seconds = qreal(t - lastTime) / 1000.;
+
+ qreal value = easeFollow(time_seconds);
+ value *= (invert? -1.0: 1.0);
+ QDeclarativePropertyPrivate::write(target, initialValue + value,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+}
+
+void QSmoothedAnimation::init()
+{
+ if (velocity == 0) {
+ stop();
+ return;
+ }
+
+ if (delayedStopTimer.isActive())
+ delayedStopTimer.stop();
+
+ initialValue = target.read().toReal();
+ lastTime = this->currentTime();
+
+ if (to == initialValue) {
+ stop();
+ return;
+ }
+
+ bool hasReversed = trackVelocity != 0. &&
+ ((!invert) == ((initialValue - to) > 0));
+
+ if (hasReversed) {
+ switch (reversingMode) {
+ default:
+ case QDeclarativeSmoothedAnimation::Eased:
+ initialVelocity = -trackVelocity;
+ break;
+ case QDeclarativeSmoothedAnimation::Sync:
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ trackVelocity = 0;
+ stop();
+ return;
+ case QDeclarativeSmoothedAnimation::Immediate:
+ initialVelocity = 0;
+ break;
+ }
+ }
+
+ trackVelocity = initialVelocity;
+
+ invert = (to < initialValue);
+
+ if (!recalc()) {
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ stop();
+ return;
+ }
+}
+
+/*!
+ \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits NumberAnimation
+ \brief The SmoothedAnimation element allows a property to smoothly track a value.
+
+ A SmoothedAnimation animates a property's value to a set target value
+ using an ease in/out quad easing curve. When the target value changes,
+ the easing curves used to animate between the old and new target values
+ are smoothly spliced together to create a smooth movement to the new
+ target value that maintains the current velocity.
+
+ The follow example shows one \l Rectangle tracking the position of another
+ using SmoothedAnimation. The green rectangle's \c x and \c y values are
+ bound to those of the red rectangle. Whenever these values change, the
+ green rectangle smoothly animates to its new position:
+
+ \snippet doc/src/snippets/declarative/smoothedanimation.qml 0
+
+ A SmoothedAnimation can be configured by setting the \l velocity at which the
+ animation should occur, or the \l duration that the animation should take.
+ If both the \l velocity and \l 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 default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the
+ value being animated is small, then the velocity will need to be adjusted
+ appropriately. For example, the opacity of an item ranges from 0 - 1.0.
+ To enable a smooth animation in this range the velocity will need to be
+ set to a value such as 0.5 units/second. Animating from 0 to 1.0 with a velocity
+ of 0.5 will take 2000 ms to complete.
+
+ Like any other animation element, a SmoothedAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa SpringAnimation, NumberAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+*/
+
+QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent)
+: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent)
+{
+}
+
+QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation()
+{
+}
+
+QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate()
+ : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation)
+{
+ Q_Q(QDeclarativeSmoothedAnimation);
+ QDeclarative_setParent_noEvent(wrapperGroup, q);
+ QDeclarative_setParent_noEvent(anim, q);
+}
+
+void QDeclarativeSmoothedAnimationPrivate::updateRunningAnimations()
+{
+ foreach(QSmoothedAnimation* ease, activeAnimations.values()){
+ ease->maximumEasingTime = anim->maximumEasingTime;
+ ease->reversingMode = anim->reversingMode;
+ ease->velocity = anim->velocity;
+ ease->userDuration = anim->userDuration;
+ ease->init();
+ }
+}
+
+QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ return d->wrapperGroup;
+}
+
+void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ QDeclarativeNumberAnimation::transition(actions, modified, direction);
+
+ if (!d->actions)
+ return;
+
+ QSet<QAbstractAnimation*> anims;
+ for (int i = 0; i < d->actions->size(); i++) {
+ QSmoothedAnimation *ease;
+ bool needsRestart;
+ if (!d->activeAnimations.contains((*d->actions)[i].property)) {
+ ease = new QSmoothedAnimation();
+ d->wrapperGroup->addAnimation(ease);
+ d->activeAnimations.insert((*d->actions)[i].property, ease);
+ needsRestart = false;
+ } else {
+ ease = d->activeAnimations.value((*d->actions)[i].property);
+ needsRestart = true;
+ }
+ ease->target = (*d->actions)[i].property;
+ ease->to = (*d->actions)[i].toValue.toReal();
+
+ // copying public members from main value holder animation
+ ease->maximumEasingTime = d->anim->maximumEasingTime;
+ ease->reversingMode = d->anim->reversingMode;
+ ease->velocity = d->anim->velocity;
+ ease->userDuration = d->anim->userDuration;
+
+ ease->initialVelocity = ease->trackVelocity;
+
+ if (needsRestart)
+ ease->init();
+ anims.insert(ease);
+ }
+
+ for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) {
+ if (!anims.contains(d->wrapperGroup->animationAt(i))) {
+ QSmoothedAnimation *ease = static_cast<QSmoothedAnimation*>(d->wrapperGroup->animationAt(i));
+ d->activeAnimations.remove(ease->target);
+ d->wrapperGroup->takeAnimation(i);
+ delete ease;
+ }
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::SmoothedAnimation::reversingMode
+
+ Sets how the SmoothedAnimation behaves if an animation direction is reversed.
+
+ Possible values are:
+
+ \list
+ \o SmoothedAnimation.Eased (default) - the animation will smoothly decelerate, and then reverse direction
+ \o SmoothedAnimation.Immediate - the animation will immediately begin accelerating in the reverse direction, beginning with a velocity of 0
+ \o SmoothedAnimation.Sync - the property is immediately set to the target value
+ \endlist
+*/
+QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode;
+}
+
+void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->reversingMode == m)
+ return;
+
+ d->anim->reversingMode = m;
+ emit reversingModeChanged();
+ d->updateRunningAnimations();
+}
+
+/*!
+ \qmlproperty int QtQuick2::SmoothedAnimation::duration
+
+ This property holds the animation duration, in msecs, used when tracking the source.
+
+ Setting this to -1 (the default) disables the duration value.
+
+ If the velocity value and the duration value are both enabled, then the animation will
+ use whichever gives the shorter duration.
+*/
+int QDeclarativeSmoothedAnimation::duration() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->userDuration;
+}
+
+void QDeclarativeSmoothedAnimation::setDuration(int duration)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (duration != -1)
+ QDeclarativeNumberAnimation::setDuration(duration);
+ if(duration == d->anim->userDuration)
+ return;
+ d->anim->userDuration = duration;
+ d->updateRunningAnimations();
+}
+
+qreal QDeclarativeSmoothedAnimation::velocity() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->velocity;
+}
+
+/*!
+ \qmlproperty real QtQuick2::SmoothedAnimation::velocity
+
+ This property holds the average velocity allowed when tracking the 'to' value.
+
+ The default velocity of SmoothedAnimation is 200 units/second.
+
+ Setting this to -1 disables the velocity value.
+
+ If the velocity value and the duration value are both enabled, then the animation will
+ use whichever gives the shorter duration.
+*/
+void QDeclarativeSmoothedAnimation::setVelocity(qreal v)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->velocity == v)
+ return;
+
+ d->anim->velocity = v;
+ emit velocityChanged();
+ d->updateRunningAnimations();
+}
+
+/*!
+ \qmlproperty int QtQuick2::SmoothedAnimation::maximumEasingTime
+
+ This property specifies the maximum time, in msecs, any "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.
+*/
+int QDeclarativeSmoothedAnimation::maximumEasingTime() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->maximumEasingTime;
+}
+
+void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v)
+{
+ Q_D(QDeclarativeSmoothedAnimation);
+ if(v == d->anim->maximumEasingTime)
+ return;
+ d->anim->maximumEasingTime = v;
+ emit maximumEasingTimeChanged();
+ d->updateRunningAnimations();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativesmoothedanimation_p.h b/src/quick/util/qdeclarativesmoothedanimation_p.h
new file mode 100644
index 0000000000..d4c7716540
--- /dev/null
+++ b/src/quick/util/qdeclarativesmoothedanimation_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESMOOTHEDANIMATION_H
+#define QDECLARATIVESMOOTHEDANIMATION_H
+
+#include <qdeclarative.h>
+#include "qdeclarativeanimation_p.h"
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeProperty;
+class QDeclarativeSmoothedAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSmoothedAnimation : public QDeclarativeNumberAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeSmoothedAnimation)
+ Q_ENUMS(ReversingMode)
+
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(ReversingMode reversingMode READ reversingMode WRITE setReversingMode NOTIFY reversingModeChanged)
+ Q_PROPERTY(qreal maximumEasingTime READ maximumEasingTime WRITE setMaximumEasingTime NOTIFY maximumEasingTimeChanged)
+
+public:
+ enum ReversingMode { Eased, Immediate, Sync };
+
+ QDeclarativeSmoothedAnimation(QObject *parent = 0);
+ ~QDeclarativeSmoothedAnimation();
+
+ ReversingMode reversingMode() const;
+ void setReversingMode(ReversingMode);
+
+ virtual int duration() const;
+ virtual void setDuration(int);
+
+ qreal velocity() const;
+ void setVelocity(qreal);
+
+ int maximumEasingTime() const;
+ void setMaximumEasingTime(int);
+
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+ QAbstractAnimation* qtAnimation();
+
+Q_SIGNALS:
+ void velocityChanged();
+ void reversingModeChanged();
+ void maximumEasingTimeChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSmoothedAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESMOOTHEDANIMATION_H
diff --git a/src/quick/util/qdeclarativesmoothedanimation_p_p.h b/src/quick/util/qdeclarativesmoothedanimation_p_p.h
new file mode 100644
index 0000000000..08b1450342
--- /dev/null
+++ b/src/quick/util/qdeclarativesmoothedanimation_p_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESMOOTHEDANIMATION_P_H
+#define QDECLARATIVESMOOTHEDANIMATION_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 "qdeclarativesmoothedanimation_p.h"
+#include "qdeclarativeanimation_p.h"
+
+#include "qdeclarativeanimation_p_p.h"
+
+#include <qparallelanimationgroup.h>
+
+#include <private/qobject_p.h>
+#include <QBasicTimer>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QSmoothedAnimation : public QAbstractAnimation
+{
+public:
+ QSmoothedAnimation(QObject *parent=0);
+
+ qreal to;
+ qreal velocity;
+ int userDuration;
+
+ int maximumEasingTime;
+ QDeclarativeSmoothedAnimation::ReversingMode reversingMode;
+
+ qreal initialVelocity;
+ qreal trackVelocity;
+
+ QDeclarativeProperty target;
+
+ int duration() const;
+ void restart();
+ void init();
+
+protected:
+ virtual void updateCurrentTime(int);
+ virtual void updateState(QAbstractAnimation::State, QAbstractAnimation::State);
+ virtual void timerEvent(QTimerEvent *);
+
+private:
+ qreal easeFollow(qreal);
+ qreal initialValue;
+
+ bool invert;
+
+ int finalDuration;
+
+ // Parameters for use in updateCurrentTime()
+ qreal a; // Acceleration
+ qreal d; // Deceleration
+ qreal tf; // Total time
+ qreal tp; // Time at which peak velocity occurs
+ qreal td; // Time at which deceleration begins
+ qreal vp; // Velocity at tp
+ qreal sp; // Displacement at tp
+ qreal sd; // Displacement at td
+ qreal vi; // "Normalized" initialvelocity
+ qreal s; // Total s
+
+ int lastTime;
+
+ bool recalc();
+ void delayedStop();
+
+ QBasicTimer delayedStopTimer;
+};
+
+class QDeclarativeSmoothedAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeSmoothedAnimation)
+public:
+ QDeclarativeSmoothedAnimationPrivate();
+ void updateRunningAnimations();
+
+ QParallelAnimationGroup *wrapperGroup;
+ QSmoothedAnimation *anim;
+ QHash<QDeclarativeProperty, QSmoothedAnimation*> activeAnimations;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESMOOTHEDANIMATION_P_H
diff --git a/src/quick/util/qdeclarativespringanimation.cpp b/src/quick/util/qdeclarativespringanimation.cpp
new file mode 100644
index 0000000000..b0b12c7ba4
--- /dev/null
+++ b/src/quick/util/qdeclarativespringanimation.cpp
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativespringanimation_p.h"
+
+#include "qdeclarativeanimation_p_p.h"
+#include <private/qdeclarativeproperty_p.h>
+
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+
+#include <limits.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QDeclarativeSpringAnimationPrivate : public QDeclarativePropertyAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeSpringAnimation)
+public:
+
+
+ struct SpringAnimation {
+ SpringAnimation()
+ : currentValue(0), to(0), velocity(0), start(0), duration(0) {}
+ qreal currentValue;
+ qreal to;
+ qreal velocity;
+ int start;
+ int duration;
+ };
+ QHash<QDeclarativeProperty, SpringAnimation> activeAnimations;
+
+ qreal maxVelocity;
+ qreal velocityms;
+ int lastTime;
+ qreal mass;
+ qreal spring;
+ qreal damping;
+ qreal epsilon;
+ qreal modulus;
+
+ bool useMass : 1;
+ bool haveModulus : 1;
+
+ enum Mode {
+ Track,
+ Velocity,
+ Spring
+ };
+ Mode mode;
+
+ QDeclarativeSpringAnimationPrivate()
+ : maxVelocity(0), velocityms(0), lastTime(0)
+ , mass(1.0), spring(0.), damping(0.), epsilon(0.01)
+ , modulus(0.0), useMass(false), haveModulus(false)
+ , mode(Track), clock(0)
+ { }
+
+ void tick(int time);
+ bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed);
+ void updateMode();
+
+ typedef QTickAnimationProxy<QDeclarativeSpringAnimationPrivate, &QDeclarativeSpringAnimationPrivate::tick> Clock;
+ Clock *clock;
+};
+
+void QDeclarativeSpringAnimationPrivate::tick(int time)
+{
+ if (mode == Track) {
+ clock->stop();
+ return;
+ }
+ int elapsed = time - lastTime;
+ if (!elapsed)
+ return;
+
+ if (mode == Spring) {
+ if (elapsed < 16) // capped at 62fps.
+ return;
+ int count = elapsed / 16;
+ lastTime = time - (elapsed - count * 16);
+ } else {
+ lastTime = time;
+ }
+
+ QMutableHashIterator<QDeclarativeProperty, SpringAnimation> it(activeAnimations);
+ while (it.hasNext()) {
+ it.next();
+ if (animate(it.key(), it.value(), elapsed))
+ it.remove();
+ }
+
+ if (activeAnimations.isEmpty())
+ clock->stop();
+}
+
+bool QDeclarativeSpringAnimationPrivate::animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed)
+{
+ qreal srcVal = animation.to;
+
+ bool stop = false;
+
+ if (haveModulus) {
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ srcVal = fmod(srcVal, modulus);
+ }
+ if (mode == Spring) {
+ // 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 - animation.currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (useMass)
+ animation.velocity = animation.velocity + (spring * diff - damping * animation.velocity) / mass;
+ else
+ animation.velocity = animation.velocity + spring * diff - damping * animation.velocity;
+ if (maxVelocity > 0.) {
+ // limit velocity
+ if (animation.velocity > maxVelocity)
+ animation.velocity = maxVelocity;
+ else if (animation.velocity < -maxVelocity)
+ animation.velocity = -maxVelocity;
+ }
+ animation.currentValue += animation.velocity * 16.0 / 1000.0;
+ if (haveModulus) {
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ if (animation.currentValue < 0.0)
+ animation.currentValue += modulus;
+ }
+ }
+ if (qAbs(animation.velocity) < epsilon && qAbs(srcVal - animation.currentValue) < epsilon) {
+ animation.velocity = 0.0;
+ animation.currentValue = srcVal;
+ stop = true;
+ }
+ } else {
+ qreal moveBy = elapsed * velocityms;
+ qreal diff = srcVal - animation.currentValue;
+ if (haveModulus && qAbs(diff) > modulus / 2) {
+ if (diff < 0)
+ diff += modulus;
+ else
+ diff -= modulus;
+ }
+ if (diff > 0) {
+ animation.currentValue += moveBy;
+ if (haveModulus)
+ animation.currentValue = fmod(animation.currentValue, modulus);
+ } else {
+ animation.currentValue -= moveBy;
+ if (haveModulus && animation.currentValue < 0.0)
+ animation.currentValue = fmod(animation.currentValue, modulus) + modulus;
+ }
+ if (lastTime - animation.start >= animation.duration) {
+ animation.currentValue = animation.to;
+ stop = true;
+ }
+ }
+
+ qreal old_to = animation.to;
+
+ QDeclarativePropertyPrivate::write(property, animation.currentValue,
+ QDeclarativePropertyPrivate::BypassInterceptor |
+ QDeclarativePropertyPrivate::DontRemoveBinding);
+
+ return (stop && old_to == animation.to); // do not stop if we got restarted
+}
+
+void QDeclarativeSpringAnimationPrivate::updateMode()
+{
+ if (spring == 0. && maxVelocity == 0.)
+ mode = Track;
+ else if (spring > 0.)
+ mode = Spring;
+ else {
+ mode = Velocity;
+ QHash<QDeclarativeProperty, SpringAnimation>::iterator it;
+ for (it = activeAnimations.begin(); it != activeAnimations.end(); ++it) {
+ SpringAnimation &animation = *it;
+ animation.start = lastTime;
+ qreal dist = qAbs(animation.currentValue - animation.to);
+ if (haveModulus && dist > modulus / 2)
+ dist = modulus - fmod(dist, modulus);
+ animation.duration = dist / velocityms;
+ }
+ }
+}
+
+/*!
+ \qmlclass SpringAnimation QDeclarativeSpringAnimation
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \inherits NumberAnimation
+
+ \brief The SpringAnimation element allows a property to track a value in a spring-like motion.
+
+ SpringAnimation mimics the oscillatory behavior of a spring, with the appropriate \l spring constant to
+ control the acceleration and the \l damping to control how quickly the effect dies away.
+
+ You can also limit the maximum \l velocity of the animation.
+
+ The following \l Rectangle moves to the position of the mouse using a
+ SpringAnimation when the mouse is clicked. The use of the \l Behavior
+ on the \c x and \c y values indicates that whenever these values are
+ changed, a SpringAnimation should be applied.
+
+ \snippet doc/src/snippets/declarative/springanimation.qml 0
+
+ Like any other animation element, a SpringAnimation can be applied in a
+ number of ways, including transitions, behaviors and property value
+ sources. The \l {QML Animation and Transitions} documentation shows a
+ variety of methods for creating animations.
+
+ \sa SmoothedAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example}
+*/
+
+QDeclarativeSpringAnimation::QDeclarativeSpringAnimation(QObject *parent)
+: QDeclarativeNumberAnimation(*(new QDeclarativeSpringAnimationPrivate),parent)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->clock = new QDeclarativeSpringAnimationPrivate::Clock(d, this);
+}
+
+QDeclarativeSpringAnimation::~QDeclarativeSpringAnimation()
+{
+}
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::velocity
+
+ This property holds the maximum velocity allowed when tracking the source.
+
+ The default value is 0 (no maximum velocity).
+*/
+
+qreal QDeclarativeSpringAnimation::velocity() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->maxVelocity;
+}
+
+void QDeclarativeSpringAnimation::setVelocity(qreal velocity)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->maxVelocity = velocity;
+ d->velocityms = velocity / 1000.0;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::spring
+
+ This property describes how strongly the target is pulled towards the
+ source. The default value is 0 (that is, the spring-like motion is disabled).
+
+ The useful value range is 0 - 5.0.
+
+ When this property is set and the \l velocity value is greater than 0,
+ the \l velocity limits the maximum speed.
+*/
+qreal QDeclarativeSpringAnimation::spring() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->spring;
+}
+
+void QDeclarativeSpringAnimation::setSpring(qreal spring)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->spring = spring;
+ d->updateMode();
+}
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::damping
+ This property holds the spring damping value.
+
+ This value describes how quickly the spring-like motion comes to rest.
+ The default value is 0.
+
+ The useful value range is 0 - 1.0. The lower the value, the faster it
+ comes to rest.
+*/
+qreal QDeclarativeSpringAnimation::damping() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->damping;
+}
+
+void QDeclarativeSpringAnimation::setDamping(qreal damping)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (damping > 1.)
+ damping = 1.;
+
+ d->damping = damping;
+}
+
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::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 QDeclarativeSpringAnimation::epsilon() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->epsilon;
+}
+
+void QDeclarativeSpringAnimation::setEpsilon(qreal epsilon)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ d->epsilon = epsilon;
+}
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::modulus
+ This property holds the modulus value. The default value is 0.
+
+ 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 QDeclarativeSpringAnimation::modulus() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->modulus;
+}
+
+void QDeclarativeSpringAnimation::setModulus(qreal modulus)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (d->modulus != modulus) {
+ d->haveModulus = modulus != 0.0;
+ d->modulus = modulus;
+ d->updateMode();
+ emit modulusChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick2::SpringAnimation::mass
+ This property holds the "mass" of the property being moved.
+
+ The value is 1.0 by default.
+
+ A greater mass causes slower movement and a greater spring-like
+ motion when an item comes to rest.
+*/
+qreal QDeclarativeSpringAnimation::mass() const
+{
+ Q_D(const QDeclarativeSpringAnimation);
+ return d->mass;
+}
+
+void QDeclarativeSpringAnimation::setMass(qreal mass)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ if (d->mass != mass && mass > 0.0) {
+ d->useMass = mass != 1.0;
+ d->mass = mass;
+ emit massChanged();
+ }
+}
+
+void QDeclarativeSpringAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
+{
+ Q_D(QDeclarativeSpringAnimation);
+ Q_UNUSED(direction);
+
+ if (d->clock->state() != QAbstractAnimation::Running) {
+ d->lastTime = 0;
+ }
+
+ QDeclarativeNumberAnimation::transition(actions, modified, direction);
+
+ if (!d->actions)
+ return;
+
+ if (!d->actions->isEmpty()) {
+ for (int i = 0; i < d->actions->size(); ++i) {
+ const QDeclarativeProperty &property = d->actions->at(i).property;
+ QDeclarativeSpringAnimationPrivate::SpringAnimation &animation
+ = d->activeAnimations[property];
+ animation.to = d->actions->at(i).toValue.toReal();
+ animation.start = d->lastTime;
+ if (d->fromIsDefined)
+ animation.currentValue = d->actions->at(i).fromValue.toReal();
+ else
+ animation.currentValue = property.read().toReal();
+ if (d->mode == QDeclarativeSpringAnimationPrivate::Velocity) {
+ qreal dist = qAbs(animation.currentValue - animation.to);
+ if (d->haveModulus && dist > d->modulus / 2)
+ dist = d->modulus - fmod(dist, d->modulus);
+ animation.duration = dist / d->velocityms;
+ }
+ }
+ }
+}
+
+
+QAbstractAnimation *QDeclarativeSpringAnimation::qtAnimation()
+{
+ Q_D(QDeclarativeSpringAnimation);
+ return d->clock;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativespringanimation_p.h b/src/quick/util/qdeclarativespringanimation_p.h
new file mode 100644
index 0000000000..13e983b9a5
--- /dev/null
+++ b/src/quick/util/qdeclarativespringanimation_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESPRINGANIMATION_H
+#define QDECLARATIVESPRINGANIMATION_H
+
+#include <qdeclarative.h>
+#include "qdeclarativeanimation_p.h"
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSpringAnimationPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSpringAnimation : public QDeclarativeNumberAnimation
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeSpringAnimation)
+ Q_INTERFACES(QDeclarativePropertyValueSource)
+
+ 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(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged)
+ Q_PROPERTY(qreal mass READ mass WRITE setMass NOTIFY massChanged)
+
+public:
+ QDeclarativeSpringAnimation(QObject *parent=0);
+ ~QDeclarativeSpringAnimation();
+
+ 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);
+
+ virtual void transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction);
+
+protected:
+ virtual QAbstractAnimation *qtAnimation();
+
+Q_SIGNALS:
+ void modulusChanged();
+ void massChanged();
+ void syncChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSpringAnimation)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESPRINGANIMATION_H
diff --git a/src/quick/util/qdeclarativestate.cpp b/src/quick/util/qdeclarativestate.cpp
new file mode 100644
index 0000000000..1250c0c2b5
--- /dev/null
+++ b/src/quick/util/qdeclarativestate.cpp
@@ -0,0 +1,734 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativestate_p_p.h"
+#include "qdeclarativestate_p.h"
+
+#include "qdeclarativestategroup_p.h"
+#include "qdeclarativestateoperations_p.h"
+
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+QDeclarativeAction::QDeclarativeAction()
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), event(0),
+ specifiedObject(0)
+{
+}
+
+QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
+ const QVariant &value)
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
+ property(target, propertyName, qmlEngine(target)), toValue(value),
+ fromBinding(0), event(0),
+ specifiedObject(target), specifiedProperty(propertyName)
+{
+ if (property.isValid())
+ fromValue = property.read();
+}
+
+QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
+ QDeclarativeContext *context, const QVariant &value)
+: restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
+ property(target, propertyName, context), toValue(value),
+ fromBinding(0), event(0),
+ specifiedObject(target), specifiedProperty(propertyName)
+{
+ if (property.isValid())
+ fromValue = property.read();
+}
+
+
+QDeclarativeActionEvent::~QDeclarativeActionEvent()
+{
+}
+
+QString QDeclarativeActionEvent::typeName() const
+{
+ return QString();
+}
+
+void QDeclarativeActionEvent::execute(Reason)
+{
+}
+
+bool QDeclarativeActionEvent::isReversable()
+{
+ return false;
+}
+
+void QDeclarativeActionEvent::reverse(Reason)
+{
+}
+
+bool QDeclarativeActionEvent::changesBindings()
+{
+ return false;
+}
+
+void QDeclarativeActionEvent::clearBindings()
+{
+}
+
+bool QDeclarativeActionEvent::override(QDeclarativeActionEvent *other)
+{
+ Q_UNUSED(other);
+ return false;
+}
+
+QDeclarativeStateOperation::QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ \qmlclass State QDeclarativeState
+ \inqmlmodule QtQuick 2
+ \ingroup qml-state-elements
+ \brief The State element defines configurations of objects and properties.
+
+ A \e state is a set of batched changes from the default configuration.
+
+ All items have a default state that defines the default configuration of objects
+ and property values. New states can be defined by adding State items to the \l {Item::states}{states} property to
+ allow items to switch between different configurations. These configurations
+ can, for example, be used to apply different sets of property values or execute
+ different scripts.
+
+ The following example displays a single \l Rectangle. In the default state, the rectangle
+ is colored black. In the "clicked" state, a PropertyChanges element changes the
+ rectangle's color to red. Clicking within the MouseArea toggles the rectangle's state
+ between the default state and the "clicked" state, thus toggling the color of the
+ rectangle between black and red.
+
+ \snippet doc/src/snippets/declarative/state.qml 0
+
+ Notice the default state is referred to using an empty string ("").
+
+ States are commonly used together with \l{QML Animation and Transitions}{Transitions} to provide
+ animations when state changes occur.
+
+ \note Setting the state of an object from within another state of the same object is
+ not allowed.
+
+ \sa {declarative/animation/states}{states example}, {qmlstates}{States},
+ {QML Animation and Transitions}{Transitions}, QtDeclarative
+*/
+QDeclarativeState::QDeclarativeState(QObject *parent)
+: QObject(*(new QDeclarativeStatePrivate), parent)
+{
+ Q_D(QDeclarativeState);
+ d->transitionManager.setState(this);
+}
+
+QDeclarativeState::~QDeclarativeState()
+{
+ Q_D(QDeclarativeState);
+ if (d->group)
+ d->group->removeState(this);
+}
+
+/*!
+ \qmlproperty string QtQuick2::State::name
+ This property holds the name of the state.
+
+ Each state should have a unique name within its item.
+*/
+QString QDeclarativeState::name() const
+{
+ Q_D(const QDeclarativeState);
+ return d->name;
+}
+
+void QDeclarativeState::setName(const QString &n)
+{
+ Q_D(QDeclarativeState);
+ d->name = n;
+ d->named = true;
+}
+
+bool QDeclarativeState::isNamed() const
+{
+ Q_D(const QDeclarativeState);
+ return d->named;
+}
+
+bool QDeclarativeState::isWhenKnown() const
+{
+ Q_D(const QDeclarativeState);
+ return d->when != 0;
+}
+
+/*!
+ \qmlproperty bool QtQuick2::State::when
+ This property holds when the state should be applied.
+
+ This should be set to an expression that evaluates to \c true when you want the state to
+ be applied. For example, the following \l Rectangle changes in and out of the "hidden"
+ state when the \l MouseArea is pressed:
+
+ \snippet doc/src/snippets/declarative/state-when.qml 0
+
+ If multiple states in a group have \c when clauses that evaluate to \c true
+ at the same time, the first matching state will be applied. For example, in
+ the following snippet \c state1 will always be selected rather than
+ \c state2 when sharedCondition becomes \c true.
+ \qml
+ Item {
+ states: [
+ State { name: "state1"; when: sharedCondition },
+ State { name: "state2"; when: sharedCondition }
+ ]
+ // ...
+ }
+ \endqml
+*/
+QDeclarativeBinding *QDeclarativeState::when() const
+{
+ Q_D(const QDeclarativeState);
+ return d->when;
+}
+
+void QDeclarativeState::setWhen(QDeclarativeBinding *when)
+{
+ Q_D(QDeclarativeState);
+ d->when = when;
+ if (d->group)
+ d->group->updateAutoState();
+}
+
+/*!
+ \qmlproperty string QtQuick2::State::extend
+ This property holds the state that this state extends.
+
+ When a state extends another state, it inherits all the changes of that state.
+
+ The state being extended is treated as the base state in regards to
+ the changes specified by the extending state.
+*/
+QString QDeclarativeState::extends() const
+{
+ Q_D(const QDeclarativeState);
+ return d->extends;
+}
+
+void QDeclarativeState::setExtends(const QString &extends)
+{
+ Q_D(QDeclarativeState);
+ d->extends = extends;
+}
+
+/*!
+ \qmlproperty list<Change> QtQuick2::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.
+*/
+QDeclarativeListProperty<QDeclarativeStateOperation> QDeclarativeState::changes()
+{
+ Q_D(QDeclarativeState);
+ return QDeclarativeListProperty<QDeclarativeStateOperation>(this, &d->operations, QDeclarativeStatePrivate::operations_append,
+ QDeclarativeStatePrivate::operations_count, QDeclarativeStatePrivate::operations_at,
+ QDeclarativeStatePrivate::operations_clear);
+}
+
+int QDeclarativeState::operationCount() const
+{
+ Q_D(const QDeclarativeState);
+ return d->operations.count();
+}
+
+QDeclarativeStateOperation *QDeclarativeState::operationAt(int index) const
+{
+ Q_D(const QDeclarativeState);
+ return d->operations.at(index);
+}
+
+QDeclarativeState &QDeclarativeState::operator<<(QDeclarativeStateOperation *op)
+{
+ Q_D(QDeclarativeState);
+ d->operations.append(QDeclarativeStatePrivate::OperationGuard(op, &d->operations));
+ return *this;
+}
+
+void QDeclarativeStatePrivate::complete()
+{
+ Q_Q(QDeclarativeState);
+
+ for (int ii = 0; ii < reverting.count(); ++ii) {
+ for (int jj = 0; jj < revertList.count(); ++jj) {
+ const QDeclarativeRevertAction &revert = reverting.at(ii);
+ const QDeclarativeSimpleAction &simple = revertList.at(jj);
+ if ((revert.event && simple.event() == revert.event) ||
+ simple.property() == revert.property) {
+ revertList.removeAt(jj);
+ break;
+ }
+ }
+ }
+ reverting.clear();
+
+ if (group)
+ group->stateAboutToComplete();
+ emit q->completed();
+}
+
+// Generate a list of actions for this state. This includes coelescing state
+// actions that this state "extends"
+QDeclarativeStateOperation::ActionList
+QDeclarativeStatePrivate::generateActionList() const
+{
+ QDeclarativeStateOperation::ActionList applyList;
+ if (inState)
+ return applyList;
+
+ // Prevent "extends" recursion
+ inState = true;
+
+ if (!extends.isEmpty()) {
+ QList<QDeclarativeState *> states = group ? group->states() : QList<QDeclarativeState *>();
+ for (int ii = 0; ii < states.count(); ++ii)
+ if (states.at(ii)->name() == extends) {
+ qmlExecuteDeferred(states.at(ii));
+ applyList = static_cast<QDeclarativeStatePrivate*>(states.at(ii)->d_func())->generateActionList();
+ }
+ }
+
+ foreach(QDeclarativeStateOperation *op, operations)
+ applyList << op->actions();
+
+ inState = false;
+ return applyList;
+}
+
+QDeclarativeStateGroup *QDeclarativeState::stateGroup() const
+{
+ Q_D(const QDeclarativeState);
+ return d->group;
+}
+
+void QDeclarativeState::setStateGroup(QDeclarativeStateGroup *group)
+{
+ Q_D(QDeclarativeState);
+ d->group = group;
+}
+
+void QDeclarativeState::cancel()
+{
+ Q_D(QDeclarativeState);
+ d->transitionManager.cancel();
+}
+
+void QDeclarativeAction::deleteFromBinding()
+{
+ if (fromBinding) {
+ QDeclarativePropertyPrivate::setBinding(property, 0);
+ fromBinding->destroy();
+ fromBinding = 0;
+ }
+}
+
+bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
+ simpleAction.setValue(revertValue);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
+ if (simpleAction.binding())
+ simpleAction.binding()->destroy();
+
+ simpleAction.setBinding(binding);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QString &name)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target && simpleAction.property().name() == name) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void QDeclarativeState::addEntryToRevertList(const QDeclarativeAction &action)
+{
+ Q_D(QDeclarativeState);
+
+ QDeclarativeSimpleAction simpleAction(action);
+
+ d->revertList.append(simpleAction);
+}
+
+void QDeclarativeState::removeAllEntriesFromRevertList(QObject *target)
+{
+ Q_D(QDeclarativeState);
+
+ if (isStateActive()) {
+ QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.property().object() == target) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding) {
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ oldBinding->destroy();
+ }
+
+ simpleAction.property().write(simpleAction.value());
+ if (simpleAction.binding())
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
+
+ revertListIterator.remove();
+ }
+ }
+ }
+}
+
+void QDeclarativeState::addEntriesToRevertList(const QList<QDeclarativeAction> &actionList)
+{
+ Q_D(QDeclarativeState);
+ if (isStateActive()) {
+ QList<QDeclarativeSimpleAction> simpleActionList;
+
+ QListIterator<QDeclarativeAction> actionListIterator(actionList);
+ while(actionListIterator.hasNext()) {
+ const QDeclarativeAction &action = actionListIterator.next();
+ QDeclarativeSimpleAction simpleAction(action);
+ action.property.write(action.toValue);
+ if (!action.toBinding.isNull()) {
+ QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
+ if (oldBinding)
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
+ QDeclarativePropertyPrivate::setBinding(simpleAction.property(), action.toBinding.data(), QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+
+ simpleActionList.append(simpleAction);
+ }
+
+ d->revertList.append(simpleActionList);
+ }
+}
+
+QVariant QDeclarativeState::valueInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return simpleAction.value();
+ }
+ }
+
+ return QVariant();
+}
+
+QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QString &name) const
+{
+ Q_D(const QDeclarativeState);
+
+ if (isStateActive()) {
+ QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
+
+ while (revertListIterator.hasNext()) {
+ const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
+ if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
+ return simpleAction.binding();
+ }
+ }
+
+ return 0;
+}
+
+bool QDeclarativeState::isStateActive() const
+{
+ return stateGroup() && stateGroup()->state() == name();
+}
+
+void QDeclarativeState::apply(QDeclarativeTransition *trans, QDeclarativeState *revert)
+{
+ Q_D(QDeclarativeState);
+
+ qmlExecuteDeferred(this);
+
+ cancel();
+ if (revert)
+ revert->cancel();
+ d->revertList.clear();
+ d->reverting.clear();
+
+ if (revert) {
+ QDeclarativeStatePrivate *revertPrivate =
+ static_cast<QDeclarativeStatePrivate*>(revert->d_func());
+ d->revertList = revertPrivate->revertList;
+ revertPrivate->revertList.clear();
+ }
+
+ // List of actions caused by this state
+ QDeclarativeStateOperation::ActionList applyList = d->generateActionList();
+
+ // List of actions that need to be reverted to roll back (just) this state
+ QDeclarativeStatePrivate::SimpleActionList additionalReverts;
+ // First add the reverse of all the applyList actions
+ for (int ii = 0; ii < applyList.count(); ++ii) {
+ QDeclarativeAction &action = applyList[ii];
+
+ if (action.event) {
+ if (!action.event->isReversable())
+ continue;
+ bool found = false;
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
+ QDeclarativeActionEvent *event = d->revertList.at(jj).event();
+ if (event && event->typeName() == action.event->typeName()) {
+ if (action.event->override(event)) {
+ found = true;
+
+ if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) {
+ action.event->copyOriginals(d->revertList.at(jj).event());
+
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ d->revertList.removeAt(jj);
+ --jj;
+ } else if (action.event->isRewindable()) //###why needed?
+ action.event->saveCurrentValues();
+
+ break;
+ }
+ }
+ }
+ if (!found) {
+ action.event->saveOriginals();
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
+ } else {
+ bool found = false;
+ action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
+
+ for (int jj = 0; jj < d->revertList.count(); ++jj) {
+ if (d->revertList.at(jj).property() == action.property) {
+ found = true;
+ if (d->revertList.at(jj).binding() != action.fromBinding) {
+ action.deleteFromBinding();
+ }
+ break;
+ }
+ }
+
+ if (!found) {
+ if (!action.restore) {
+ action.deleteFromBinding();;
+ } else {
+ // Only need to revert the applyList action if the previous
+ // state doesn't have a higher priority revert already
+ QDeclarativeSimpleAction r(action);
+ additionalReverts << r;
+ }
+ }
+ }
+ }
+
+ // 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()) {
+ QDeclarativeActionEvent *event = d->revertList.at(ii).event();
+ if (!event->isReversable())
+ continue;
+ for (int jj = 0; !found && jj < applyList.count(); ++jj) {
+ const QDeclarativeAction &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 QDeclarativeAction &action = applyList.at(jj);
+ if (action.property == d->revertList.at(ii).property())
+ found = true;
+ }
+ }
+ if (!found) {
+ QVariant cur = d->revertList.at(ii).property().read();
+ QDeclarativeAbstractBinding *delBinding =
+ QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0);
+ if (delBinding)
+ delBinding->destroy();
+
+ QDeclarativeAction a;
+ a.property = d->revertList.at(ii).property();
+ a.fromValue = cur;
+ a.toValue = d->revertList.at(ii).value();
+ a.toBinding = QDeclarativeAbstractBinding::getPointer(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
+ if (a.event)
+ d->reverting << a.event;
+ else
+ d->reverting << a.property;
+ }
+ }
+ // All the local reverts now become part of the ongoing revertList
+ d->revertList << additionalReverts;
+
+#ifndef QT_NO_DEBUG_STREAM
+ // Output for debugging
+ if (stateChangeDebug()) {
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event)
+ qWarning() << " QDeclarativeAction event:" << action.event->typeName();
+ else
+ qWarning() << " QDeclarativeAction:" << action.property.object()
+ << action.property.name() << "From:" << action.fromValue
+ << "To:" << action.toValue;
+ }
+ }
+#endif
+
+ d->transitionManager.transition(applyList, trans);
+}
+
+QDeclarativeStateOperation::ActionList QDeclarativeStateOperation::actions()
+{
+ return ActionList();
+}
+
+QDeclarativeState *QDeclarativeStateOperation::state() const
+{
+ Q_D(const QDeclarativeStateOperation);
+ return d->m_state;
+}
+
+void QDeclarativeStateOperation::setState(QDeclarativeState *state)
+{
+ Q_D(QDeclarativeStateOperation);
+ d->m_state = state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativestate_p.h b/src/quick/util/qdeclarativestate_p.h
new file mode 100644
index 0000000000..79038e50ea
--- /dev/null
+++ b/src/quick/util/qdeclarativestate_p.h
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESTATE_H
+#define QDECLARATIVESTATE_H
+
+#include <qdeclarative.h>
+#include <qdeclarativeproperty.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsharedpointer.h>
+#include <private/qtquickglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeActionEvent;
+class QDeclarativeAbstractBinding;
+class QDeclarativeBinding;
+class QDeclarativeExpression;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativeAction
+{
+public:
+ QDeclarativeAction();
+ QDeclarativeAction(QObject *, const QString &, const QVariant &);
+ QDeclarativeAction(QObject *, const QString &,
+ QDeclarativeContext *, const QVariant &);
+
+ bool restore:1;
+ bool actionDone:1;
+ bool reverseEvent:1;
+ bool deletableToBinding:1;
+
+ QDeclarativeProperty property;
+ QVariant fromValue;
+ QVariant toValue;
+
+ QDeclarativeAbstractBinding *fromBinding;
+ QWeakPointer<QDeclarativeAbstractBinding> toBinding;
+ QDeclarativeActionEvent *event;
+
+ //strictly for matching
+ QObject *specifiedObject;
+ QString specifiedProperty;
+
+ void deleteFromBinding();
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeActionEvent
+{
+public:
+ virtual ~QDeclarativeActionEvent();
+ virtual QString typeName() const;
+
+ enum Reason { ActualChange, FastForward };
+
+ virtual void execute(Reason reason = ActualChange);
+ virtual bool isReversable();
+ virtual void reverse(Reason reason = ActualChange);
+ virtual void saveOriginals() {}
+ virtual bool needsCopy() { return false; }
+ virtual void copyOriginals(QDeclarativeActionEvent *) {}
+
+ virtual bool isRewindable() { return isReversable(); }
+ virtual void rewind() {}
+ virtual void saveCurrentValues() {}
+ virtual void saveTargetValues() {}
+
+ virtual bool changesBindings();
+ virtual void clearBindings();
+ virtual bool override(QDeclarativeActionEvent*other);
+};
+
+//### rename to QDeclarativeStateChange?
+class QDeclarativeStateGroup;
+class QDeclarativeState;
+class QDeclarativeStateOperationPrivate;
+class Q_QUICK_EXPORT QDeclarativeStateOperation : public QObject
+{
+ Q_OBJECT
+public:
+ QDeclarativeStateOperation(QObject *parent = 0)
+ : QObject(parent) {}
+ typedef QList<QDeclarativeAction> ActionList;
+
+ virtual ActionList actions();
+
+ QDeclarativeState *state() const;
+ void setState(QDeclarativeState *state);
+
+protected:
+ QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeStateOperation)
+ Q_DISABLE_COPY(QDeclarativeStateOperation)
+};
+
+typedef QDeclarativeStateOperation::ActionList QDeclarativeStateActions;
+
+class QDeclarativeTransition;
+class QDeclarativeStatePrivate;
+class Q_QUICK_EXPORT QDeclarativeState : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QDeclarativeBinding *when READ when WRITE setWhen)
+ Q_PROPERTY(QString extend READ extends WRITE setExtends)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeStateOperation> changes READ changes)
+ Q_CLASSINFO("DefaultProperty", "changes")
+ Q_CLASSINFO("DeferredPropertyNames", "changes")
+
+public:
+ QDeclarativeState(QObject *parent=0);
+ virtual ~QDeclarativeState();
+
+ QString name() const;
+ void setName(const QString &);
+ bool isNamed() const;
+
+ /*'when' is a QDeclarativeBinding to limit state changes oscillation
+ due to the unpredictable order of evaluation of bound expressions*/
+ bool isWhenKnown() const;
+ QDeclarativeBinding *when() const;
+ void setWhen(QDeclarativeBinding *);
+
+ QString extends() const;
+ void setExtends(const QString &);
+
+ QDeclarativeListProperty<QDeclarativeStateOperation> changes();
+ int operationCount() const;
+ QDeclarativeStateOperation *operationAt(int) const;
+
+ QDeclarativeState &operator<<(QDeclarativeStateOperation *);
+
+ void apply(QDeclarativeTransition *, QDeclarativeState *revert);
+ void cancel();
+
+ QDeclarativeStateGroup *stateGroup() const;
+ void setStateGroup(QDeclarativeStateGroup *);
+
+ bool containsPropertyInRevertList(QObject *target, const QString &name) const;
+ bool changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue);
+ bool changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding);
+ bool removeEntryFromRevertList(QObject *target, const QString &name);
+ void addEntryToRevertList(const QDeclarativeAction &action);
+ void removeAllEntriesFromRevertList(QObject *target);
+ void addEntriesToRevertList(const QList<QDeclarativeAction> &actions);
+ QVariant valueInRevertList(QObject *target, const QString &name) const;
+ QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QString &name) const;
+
+ bool isStateActive() const;
+
+Q_SIGNALS:
+ void completed();
+
+private:
+ Q_DECLARE_PRIVATE(QDeclarativeState)
+ Q_DISABLE_COPY(QDeclarativeState)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeStateOperation)
+QML_DECLARE_TYPE(QDeclarativeState)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATE_H
diff --git a/src/quick/util/qdeclarativestate_p_p.h b/src/quick/util/qdeclarativestate_p_p.h
new file mode 100644
index 0000000000..55aeecde11
--- /dev/null
+++ b/src/quick/util/qdeclarativestate_p_p.h
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESTATE_P_H
+#define QDECLARATIVESTATE_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 "qdeclarativestate_p.h"
+
+#include "qdeclarativetransitionmanager_p_p.h"
+
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativeguard_p.h>
+
+#include <private/qdeclarativebinding_p.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSimpleAction
+{
+public:
+ enum State { StartState, EndState };
+ QDeclarativeSimpleAction(const QDeclarativeAction &a, State state = StartState)
+ {
+ m_property = a.property;
+ m_specifiedObject = a.specifiedObject;
+ m_specifiedProperty = a.specifiedProperty;
+ m_event = a.event;
+ if (state == StartState) {
+ m_value = a.fromValue;
+ if (QDeclarativePropertyPrivate::binding(m_property)) {
+ m_binding = QDeclarativeAbstractBinding::getPointer(QDeclarativePropertyPrivate::binding(m_property));
+ }
+ m_reverseEvent = true;
+ } else {
+ m_value = a.toValue;
+ m_binding = a.toBinding;
+ m_reverseEvent = false;
+ }
+ }
+
+ ~QDeclarativeSimpleAction()
+ {
+ }
+
+ QDeclarativeSimpleAction(const QDeclarativeSimpleAction &other)
+ : m_property(other.m_property),
+ m_value(other.m_value),
+ m_binding(QDeclarativeAbstractBinding::getPointer(other.binding())),
+ m_specifiedObject(other.m_specifiedObject),
+ m_specifiedProperty(other.m_specifiedProperty),
+ m_event(other.m_event),
+ m_reverseEvent(other.m_reverseEvent)
+ {
+ }
+
+ QDeclarativeSimpleAction &operator =(const QDeclarativeSimpleAction &other)
+ {
+ m_property = other.m_property;
+ m_value = other.m_value;
+ m_binding = QDeclarativeAbstractBinding::getPointer(other.binding());
+ m_specifiedObject = other.m_specifiedObject;
+ m_specifiedProperty = other.m_specifiedProperty;
+ m_event = other.m_event;
+ m_reverseEvent = other.m_reverseEvent;
+
+ return *this;
+ }
+
+ void setProperty(const QDeclarativeProperty &property)
+ {
+ m_property = property;
+ }
+
+ const QDeclarativeProperty &property() const
+ {
+ return m_property;
+ }
+
+ void setValue(const QVariant &value)
+ {
+ m_value = value;
+ }
+
+ const QVariant &value() const
+ {
+ return m_value;
+ }
+
+ void setBinding(QDeclarativeAbstractBinding *binding)
+ {
+ m_binding = QDeclarativeAbstractBinding::getPointer(binding);
+ }
+
+ QDeclarativeAbstractBinding *binding() const
+ {
+ return m_binding.data();
+ }
+
+ QObject *specifiedObject() const
+ {
+ return m_specifiedObject;
+ }
+
+ const QString &specifiedProperty() const
+ {
+ return m_specifiedProperty;
+ }
+
+ QDeclarativeActionEvent *event() const
+ {
+ return m_event;
+ }
+
+ bool reverseEvent() const
+ {
+ return m_reverseEvent;
+ }
+
+private:
+ QDeclarativeProperty m_property;
+ QVariant m_value;
+ QDeclarativeAbstractBinding::Pointer m_binding;
+ QObject *m_specifiedObject;
+ QString m_specifiedProperty;
+ QDeclarativeActionEvent *m_event;
+ bool m_reverseEvent;
+};
+
+class QDeclarativeRevertAction
+{
+public:
+ QDeclarativeRevertAction() : event(0) {}
+ QDeclarativeRevertAction(const QDeclarativeProperty &prop) : property(prop), event(0) {}
+ QDeclarativeRevertAction(QDeclarativeActionEvent *e) : event(e) {}
+ QDeclarativeProperty property;
+ QDeclarativeActionEvent *event;
+};
+
+class QDeclarativeStateOperationPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeStateOperation)
+
+public:
+
+ QDeclarativeStateOperationPrivate()
+ : m_state(0) {}
+
+ QDeclarativeState *m_state;
+};
+
+class QDeclarativeStatePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeState)
+
+public:
+ QDeclarativeStatePrivate()
+ : when(0), named(false), inState(false), group(0) {}
+
+ typedef QList<QDeclarativeSimpleAction> SimpleActionList;
+
+ QString name;
+ QDeclarativeBinding *when;
+ bool named;
+
+ struct OperationGuard : public QDeclarativeGuard<QDeclarativeStateOperation>
+ {
+ OperationGuard(QObject *obj, QList<OperationGuard> *l) : list(l) {
+ setObject(static_cast<QDeclarativeStateOperation *>(obj));
+ }
+ QList<OperationGuard> *list;
+ void objectDestroyed(QDeclarativeStateOperation *) {
+ // we assume priv will always be destroyed after objectDestroyed calls
+ list->removeOne(*this);
+ }
+ };
+ QList<OperationGuard> operations;
+
+ static void operations_append(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, QDeclarativeStateOperation *op) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ op->setState(qobject_cast<QDeclarativeState*>(prop->object));
+ list->append(OperationGuard(op, list));
+ }
+ static void operations_clear(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ QMutableListIterator<OperationGuard> listIterator(*list);
+ while(listIterator.hasNext())
+ listIterator.next()->setState(0);
+ list->clear();
+ }
+ static int operations_count(QDeclarativeListProperty<QDeclarativeStateOperation> *prop) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ return list->count();
+ }
+ static QDeclarativeStateOperation *operations_at(QDeclarativeListProperty<QDeclarativeStateOperation> *prop, int index) {
+ QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data);
+ return list->at(index);
+ }
+
+ QDeclarativeTransitionManager transitionManager;
+
+ SimpleActionList revertList;
+ QList<QDeclarativeRevertAction> reverting;
+ QString extends;
+ mutable bool inState;
+ QDeclarativeStateGroup *group;
+
+ QDeclarativeStateOperation::ActionList generateActionList() const;
+ void complete();
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESTATE_P_H
diff --git a/src/quick/util/qdeclarativestategroup.cpp b/src/quick/util/qdeclarativestategroup.cpp
new file mode 100644
index 0000000000..51e27e4bf0
--- /dev/null
+++ b/src/quick/util/qdeclarativestategroup.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativestategroup_p.h"
+
+#include "qdeclarativetransition_p.h"
+
+#include <private/qdeclarativebinding_p.h>
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtCore/qstringbuilder.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdebug.h>
+
+#include <private/qobject_p.h>
+#include <qdeclarativeinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+class QDeclarativeStateGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeStateGroup)
+public:
+ QDeclarativeStateGroupPrivate()
+ : nullState(0), componentComplete(true),
+ ignoreTrans(false), applyingState(false), unnamedCount(0) {}
+
+ QString currentState;
+ QDeclarativeState *nullState;
+
+ static void append_state(QDeclarativeListProperty<QDeclarativeState> *list, QDeclarativeState *state);
+ static int count_state(QDeclarativeListProperty<QDeclarativeState> *list);
+ static QDeclarativeState *at_state(QDeclarativeListProperty<QDeclarativeState> *list, int index);
+ static void clear_states(QDeclarativeListProperty<QDeclarativeState> *list);
+
+ static void append_transition(QDeclarativeListProperty<QDeclarativeTransition> *list, QDeclarativeTransition *state);
+ static int count_transitions(QDeclarativeListProperty<QDeclarativeTransition> *list);
+ static QDeclarativeTransition *at_transition(QDeclarativeListProperty<QDeclarativeTransition> *list, int index);
+ static void clear_transitions(QDeclarativeListProperty<QDeclarativeTransition> *list);
+
+ QList<QDeclarativeState *> states;
+ QList<QDeclarativeTransition *> transitions;
+
+ bool componentComplete;
+ bool ignoreTrans;
+ bool applyingState;
+ int unnamedCount;
+
+ QDeclarativeTransition *findTransition(const QString &from, const QString &to);
+ void setCurrentStateInternal(const QString &state, bool = false);
+ bool updateAutoState();
+};
+
+/*!
+ \qmlclass StateGroup QDeclarativeStateGroup
+ \inqmlmodule QtQuick 2
+ \ingroup qml-state-elements
+ \brief The StateGroup element provides state support for non-Item elements.
+
+ Item (and all derived elements) provides built in support for states and transitions
+ via its \l{Item::state}{state}, \l{Item::states}{states} and \l{Item::transitions}{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} {QML Animation and Transitions}{Transitions}, {QtDeclarative}
+*/
+
+QDeclarativeStateGroup::QDeclarativeStateGroup(QObject *parent)
+ : QObject(*(new QDeclarativeStateGroupPrivate), parent)
+{
+}
+
+QDeclarativeStateGroup::~QDeclarativeStateGroup()
+{
+ Q_D(const QDeclarativeStateGroup);
+ for (int i = 0; i < d->states.count(); ++i)
+ d->states.at(i)->setStateGroup(0);
+}
+
+QList<QDeclarativeState *> QDeclarativeStateGroup::states() const
+{
+ Q_D(const QDeclarativeStateGroup);
+ return d->states;
+}
+
+/*!
+ \qmlproperty list<State> QtQuick2::StateGroup::states
+ This property holds a list of states defined by the state group.
+
+ \qml
+ StateGroup {
+ states: [
+ State {
+ // State definition...
+ },
+ State {
+ // ...
+ }
+ // Other states...
+ ]
+ }
+ \endqml
+
+ \sa {qmlstate}{States}
+*/
+QDeclarativeListProperty<QDeclarativeState> QDeclarativeStateGroup::statesProperty()
+{
+ Q_D(QDeclarativeStateGroup);
+ return QDeclarativeListProperty<QDeclarativeState>(this, &d->states, &QDeclarativeStateGroupPrivate::append_state,
+ &QDeclarativeStateGroupPrivate::count_state,
+ &QDeclarativeStateGroupPrivate::at_state,
+ &QDeclarativeStateGroupPrivate::clear_states);
+}
+
+void QDeclarativeStateGroupPrivate::append_state(QDeclarativeListProperty<QDeclarativeState> *list, QDeclarativeState *state)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ if (state) {
+ _this->d_func()->states.append(state);
+ state->setStateGroup(_this);
+ }
+
+}
+
+int QDeclarativeStateGroupPrivate::count_state(QDeclarativeListProperty<QDeclarativeState> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->states.count();
+}
+
+QDeclarativeState *QDeclarativeStateGroupPrivate::at_state(QDeclarativeListProperty<QDeclarativeState> *list, int index)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->states.at(index);
+}
+
+void QDeclarativeStateGroupPrivate::clear_states(QDeclarativeListProperty<QDeclarativeState> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ _this->d_func()->setCurrentStateInternal(QString(), true);
+ for (int i = 0; i < _this->d_func()->states.count(); ++i) {
+ _this->d_func()->states.at(i)->setStateGroup(0);
+ }
+ _this->d_func()->states.clear();
+}
+
+/*!
+ \qmlproperty list<Transition> QtQuick2::StateGroup::transitions
+ This property holds a list of transitions defined by the state group.
+
+ \qml
+ StateGroup {
+ transitions: [
+ Transition {
+ // ...
+ },
+ Transition {
+ // ...
+ }
+ // ...
+ ]
+ }
+ \endqml
+
+ \sa {QML Animation and Transitions}{Transitions}
+*/
+QDeclarativeListProperty<QDeclarativeTransition> QDeclarativeStateGroup::transitionsProperty()
+{
+ Q_D(QDeclarativeStateGroup);
+ return QDeclarativeListProperty<QDeclarativeTransition>(this, &d->transitions, &QDeclarativeStateGroupPrivate::append_transition,
+ &QDeclarativeStateGroupPrivate::count_transitions,
+ &QDeclarativeStateGroupPrivate::at_transition,
+ &QDeclarativeStateGroupPrivate::clear_transitions);
+}
+
+void QDeclarativeStateGroupPrivate::append_transition(QDeclarativeListProperty<QDeclarativeTransition> *list, QDeclarativeTransition *trans)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ if (trans)
+ _this->d_func()->transitions.append(trans);
+}
+
+int QDeclarativeStateGroupPrivate::count_transitions(QDeclarativeListProperty<QDeclarativeTransition> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->transitions.count();
+}
+
+QDeclarativeTransition *QDeclarativeStateGroupPrivate::at_transition(QDeclarativeListProperty<QDeclarativeTransition> *list, int index)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ return _this->d_func()->transitions.at(index);
+}
+
+void QDeclarativeStateGroupPrivate::clear_transitions(QDeclarativeListProperty<QDeclarativeTransition> *list)
+{
+ QDeclarativeStateGroup *_this = static_cast<QDeclarativeStateGroup *>(list->object);
+ _this->d_func()->transitions.clear();
+}
+
+/*!
+ \qmlproperty string QtQuick2::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:
+
+ \js
+ function toggle() {
+ if (button.state == 'On')
+ button.state = 'Off';
+ else
+ button.state = 'On';
+ }
+ \endjs
+
+ 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 QDeclarativeStateGroup::state() const
+{
+ Q_D(const QDeclarativeStateGroup);
+ return d->currentState;
+}
+
+void QDeclarativeStateGroup::setState(const QString &state)
+{
+ Q_D(QDeclarativeStateGroup);
+ if (d->currentState == state)
+ return;
+
+ d->setCurrentStateInternal(state);
+}
+
+void QDeclarativeStateGroup::classBegin()
+{
+ Q_D(QDeclarativeStateGroup);
+ d->componentComplete = false;
+}
+
+void QDeclarativeStateGroup::componentComplete()
+{
+ Q_D(QDeclarativeStateGroup);
+ d->componentComplete = true;
+
+ for (int ii = 0; ii < d->states.count(); ++ii) {
+ QDeclarativeState *state = d->states.at(ii);
+ if (!state->isNamed())
+ state->setName(QLatin1String("anonymousState") % QString::number(++d->unnamedCount));
+ }
+
+ if (d->updateAutoState()) {
+ return;
+ } else if (!d->currentState.isEmpty()) {
+ QString cs = d->currentState;
+ d->currentState.clear();
+ d->setCurrentStateInternal(cs, true);
+ }
+}
+
+/*!
+ Returns true if the state was changed, otherwise false.
+*/
+bool QDeclarativeStateGroup::updateAutoState()
+{
+ Q_D(QDeclarativeStateGroup);
+ return d->updateAutoState();
+}
+
+bool QDeclarativeStateGroupPrivate::updateAutoState()
+{
+ Q_Q(QDeclarativeStateGroup);
+ if (!componentComplete)
+ return false;
+
+ bool revert = false;
+ for (int ii = 0; ii < states.count(); ++ii) {
+ QDeclarativeState *state = states.at(ii);
+ if (state->isWhenKnown()) {
+ if (state->isNamed()) {
+ if (state->when() && state->when()->evaluate().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.isEmpty();
+ q->setState(QString());
+ return rv;
+ } else {
+ return false;
+ }
+}
+
+QDeclarativeTransition *QDeclarativeStateGroupPrivate::findTransition(const QString &from, const QString &to)
+{
+ QDeclarativeTransition *highest = 0;
+ int score = 0;
+ bool reversed = false;
+ bool done = false;
+
+ for (int ii = 0; !done && ii < transitions.count(); ++ii) {
+ QDeclarativeTransition *t = transitions.at(ii);
+ if (!t->enabled())
+ continue;
+ 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(','));
+ for (int jj = 0; jj < fromState.count(); ++jj)
+ fromState[jj] = fromState.at(jj).trimmed();
+ toState = t->toState().split(QLatin1Char(','));
+ for (int jj = 0; jj < toState.count(); ++jj)
+ toState[jj] = toState.at(jj).trimmed();
+ 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 QDeclarativeStateGroupPrivate::setCurrentStateInternal(const QString &state,
+ bool ignoreTrans)
+{
+ Q_Q(QDeclarativeStateGroup);
+ if (!componentComplete) {
+ currentState = state;
+ return;
+ }
+
+ if (applyingState) {
+ qmlInfo(q) << "Can't apply a state change as part of a state definition.";
+ return;
+ }
+
+ applyingState = true;
+
+ QDeclarativeTransition *transition = ignoreTrans ? 0 : findTransition(currentState, state);
+ if (stateChangeDebug()) {
+ qWarning() << this << "Changing state. From" << currentState << ". To" << state;
+ if (transition)
+ qWarning() << " using transition" << transition->fromState()
+ << transition->toState();
+ }
+
+ QDeclarativeState *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);
+
+ QDeclarativeState *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 QDeclarativeState;
+ QDeclarative_setParent_noEvent(nullState, q);
+ nullState->setStateGroup(q);
+ }
+ if (!oldState) oldState = nullState;
+ if (!newState) newState = nullState;
+ }
+
+ newState->apply(transition, oldState);
+ applyingState = false; //### consider removing this (don't allow state changes in transition)
+}
+
+QDeclarativeState *QDeclarativeStateGroup::findState(const QString &name) const
+{
+ Q_D(const QDeclarativeStateGroup);
+ for (int i = 0; i < d->states.count(); ++i) {
+ QDeclarativeState *state = d->states.at(i);
+ if (state->name() == name)
+ return state;
+ }
+
+ return 0;
+}
+
+void QDeclarativeStateGroup::removeState(QDeclarativeState *state)
+{
+ Q_D(QDeclarativeStateGroup);
+ d->states.removeOne(state);
+}
+
+void QDeclarativeStateGroup::stateAboutToComplete()
+{
+ Q_D(QDeclarativeStateGroup);
+ d->applyingState = false;
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/quick/util/qdeclarativestategroup_p.h b/src/quick/util/qdeclarativestategroup_p.h
new file mode 100644
index 0000000000..0ddc3db312
--- /dev/null
+++ b/src/quick/util/qdeclarativestategroup_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESTATEGROUP_H
+#define QDECLARATIVESTATEGROUP_H
+
+#include "qdeclarativestate_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStateGroupPrivate;
+class Q_QUICK_EXPORT QDeclarativeStateGroup : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_DECLARE_PRIVATE(QDeclarativeStateGroup)
+
+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeState> states READ statesProperty DESIGNABLE false)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeTransition> transitions READ transitionsProperty DESIGNABLE false)
+
+public:
+ QDeclarativeStateGroup(QObject * = 0);
+ virtual ~QDeclarativeStateGroup();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QDeclarativeListProperty<QDeclarativeState> statesProperty();
+ QList<QDeclarativeState *> states() const;
+
+ QDeclarativeListProperty<QDeclarativeTransition> transitionsProperty();
+
+ QDeclarativeState *findState(const QString &name) const;
+ void removeState(QDeclarativeState *state);
+
+ virtual void classBegin();
+ virtual void componentComplete();
+Q_SIGNALS:
+ void stateChanged(const QString &);
+
+private:
+ friend class QDeclarativeState;
+ friend class QDeclarativeStatePrivate;
+ bool updateAutoState();
+ void stateAboutToComplete();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeStateGroup)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATEGROUP_H
diff --git a/src/quick/util/qdeclarativestateoperations.cpp b/src/quick/util/qdeclarativestateoperations.cpp
new file mode 100644
index 0000000000..d8a5369568
--- /dev/null
+++ b/src/quick/util/qdeclarativestateoperations.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativestateoperations_p.h"
+
+#include <qdeclarative.h>
+#include <qdeclarativecontext.h>
+#include <qdeclarativeexpression.h>
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativecontext_p.h>
+#include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativebinding_p.h>
+#include "qdeclarativestate_p_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmath.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate
+{
+public:
+ QDeclarativeStateChangeScriptPrivate() {}
+
+ QDeclarativeScriptString script;
+ QString name;
+};
+
+/*!
+ \qmlclass StateChangeScript QDeclarativeStateChangeScript
+ \inqmlmodule QtQuick 2
+ \ingroup qml-state-elements
+ \brief The StateChangeScript element allows you to run a script in a state.
+
+ A StateChangeScript is run upon entering a state. You can optionally use
+ ScriptAction to specify the point in the transition at which
+ the StateChangeScript should to be run.
+
+ \snippet snippets/declarative/states/statechangescript.qml state and transition
+
+ \sa ScriptAction
+*/
+
+QDeclarativeStateChangeScript::QDeclarativeStateChangeScript(QObject *parent)
+: QDeclarativeStateOperation(*(new QDeclarativeStateChangeScriptPrivate), parent)
+{
+}
+
+QDeclarativeStateChangeScript::~QDeclarativeStateChangeScript()
+{
+}
+
+/*!
+ \qmlproperty script QtQuick2::StateChangeScript::script
+ This property holds the script to run when the state is current.
+*/
+QDeclarativeScriptString QDeclarativeStateChangeScript::script() const
+{
+ Q_D(const QDeclarativeStateChangeScript);
+ return d->script;
+}
+
+void QDeclarativeStateChangeScript::setScript(const QDeclarativeScriptString &s)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ d->script = s;
+}
+
+/*!
+ \qmlproperty string QtQuick2::StateChangeScript::name
+ This property holds the name of the script. This name can be used by a
+ ScriptAction to target a specific script.
+
+ \sa ScriptAction::scriptName
+*/
+QString QDeclarativeStateChangeScript::name() const
+{
+ Q_D(const QDeclarativeStateChangeScript);
+ return d->name;
+}
+
+void QDeclarativeStateChangeScript::setName(const QString &n)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ d->name = n;
+}
+
+void QDeclarativeStateChangeScript::execute(Reason)
+{
+ Q_D(QDeclarativeStateChangeScript);
+ if (!d->script.script().isEmpty()) {
+ QDeclarativeExpression expr(d->script);
+ expr.evaluate();
+ if (expr.hasError())
+ qmlInfo(this, expr.error());
+ }
+}
+
+QDeclarativeStateChangeScript::ActionList QDeclarativeStateChangeScript::actions()
+{
+ ActionList rv;
+ QDeclarativeAction a;
+ a.event = this;
+ rv << a;
+ return rv;
+}
+
+QString QDeclarativeStateChangeScript::typeName() const
+{
+ return QLatin1String("StateChangeScript");
+}
+
+
+#include <moc_qdeclarativestateoperations_p.cpp>
+
+QT_END_NAMESPACE
+
diff --git a/src/quick/util/qdeclarativestateoperations_p.h b/src/quick/util/qdeclarativestateoperations_p.h
new file mode 100644
index 0000000000..872a296025
--- /dev/null
+++ b/src/quick/util/qdeclarativestateoperations_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESTATEOPERATIONS_H
+#define QDECLARATIVESTATEOPERATIONS_H
+
+#include "qdeclarativestate_p.h"
+#include <qdeclarativescriptstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStateChangeScriptPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeStateChangeScript : public QDeclarativeStateOperation, public QDeclarativeActionEvent
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeStateChangeScript)
+
+ Q_PROPERTY(QDeclarativeScriptString script READ script WRITE setScript)
+ Q_PROPERTY(QString name READ name WRITE setName)
+
+public:
+ QDeclarativeStateChangeScript(QObject *parent=0);
+ ~QDeclarativeStateChangeScript();
+
+ virtual ActionList actions();
+
+ virtual QString typeName() const;
+
+ QDeclarativeScriptString script() const;
+ void setScript(const QDeclarativeScriptString &);
+
+ QString name() const;
+ void setName(const QString &);
+
+ virtual void execute(Reason reason = ActualChange);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeStateChangeScript)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESTATEOPERATIONS_H
diff --git a/src/quick/util/qdeclarativestyledtext.cpp b/src/quick/util/qdeclarativestyledtext.cpp
new file mode 100644
index 0000000000..1c7ca5fbfd
--- /dev/null
+++ b/src/quick/util/qdeclarativestyledtext.cpp
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QStack>
+#include <QVector>
+#include <QPainter>
+#include <QTextLayout>
+#include <QDebug>
+#include <qmath.h>
+#include "qdeclarativestyledtext_p.h"
+
+/*
+ QDeclarativeStyledText supports few tags:
+
+ <b></b> - bold
+ <i></i> - italic
+ <br> - new line
+ <p> - paragraph
+ <u> - underlined text
+ <font color="color_name" size="1-7"></font>
+ <h1> to <h6> - headers
+ <a href=""> - anchor
+ <ol type="">, <ul type=""> and <li> - ordered and unordered lists
+
+ The opening and closing tags must be correctly nested.
+*/
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStyledTextPrivate
+{
+public:
+ enum ListType { Ordered, Unordered };
+ enum ListFormat { Bullet, Disc, Square, Decimal, LowerAlpha, UpperAlpha, LowerRoman, UpperRoman };
+
+ struct List {
+ int level;
+ ListType type;
+ ListFormat format;
+ };
+
+ QDeclarativeStyledTextPrivate(const QString &t, QTextLayout &l)
+ : text(t), layout(l), baseFont(layout.font()), hasNewLine(false)
+ {
+ }
+
+ void parse();
+ bool parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format);
+ bool parseCloseTag(const QChar *&ch, const QString &textIn, QString &textOut);
+ void parseEntity(const QChar *&ch, const QString &textIn, QString &textOut);
+ bool parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format);
+ bool parseOrderedListAttributes(const QChar *&ch, const QString &textIn);
+ bool parseUnorderedListAttributes(const QChar *&ch, const QString &textIn);
+ bool parseAnchorAttributes(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;
+ }
+
+ static QString toAlpha(int value, bool upper);
+ static QString toRoman(int value, bool upper);
+
+ QString text;
+ QTextLayout &layout;
+ QFont baseFont;
+ QStack<List> listStack;
+ bool hasNewLine;
+
+ 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;
+ static const QChar bullet;
+ static const QChar disc;
+ static const QChar square;
+ static const int tabsize = 6;
+};
+
+const QChar QDeclarativeStyledTextPrivate::lessThan(QLatin1Char('<'));
+const QChar QDeclarativeStyledTextPrivate::greaterThan(QLatin1Char('>'));
+const QChar QDeclarativeStyledTextPrivate::equals(QLatin1Char('='));
+const QChar QDeclarativeStyledTextPrivate::singleQuote(QLatin1Char('\''));
+const QChar QDeclarativeStyledTextPrivate::doubleQuote(QLatin1Char('\"'));
+const QChar QDeclarativeStyledTextPrivate::slash(QLatin1Char('/'));
+const QChar QDeclarativeStyledTextPrivate::ampersand(QLatin1Char('&'));
+const QChar QDeclarativeStyledTextPrivate::bullet(0x2022);
+const QChar QDeclarativeStyledTextPrivate::disc(0x25e6);
+const QChar QDeclarativeStyledTextPrivate::square(0x25a1);
+
+QDeclarativeStyledText::QDeclarativeStyledText(const QString &string, QTextLayout &layout)
+: d(new QDeclarativeStyledTextPrivate(string, layout))
+{
+}
+
+QDeclarativeStyledText::~QDeclarativeStyledText()
+{
+ delete d;
+}
+
+void QDeclarativeStyledText::parse(const QString &string, QTextLayout &layout)
+{
+ if (string.isEmpty())
+ return;
+ QDeclarativeStyledText styledText(string, layout);
+ styledText.d->parse();
+}
+
+void QDeclarativeStyledTextPrivate::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) {
+ QStringRef ref = QStringRef(&text, textStart, textLength);
+ const QChar *c = ref.constData();
+ bool isWhiteSpace = true;
+ for (int i = 0; isWhiteSpace && (i < textLength); ++c, ++i) {
+ if (!c->isSpace())
+ isWhiteSpace = false;
+ }
+ if (!isWhiteSpace) {
+ drawText.append(ref);
+ hasNewLine = false;
+ }
+ }
+ 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, drawText)) {
+ if (formatStack.count())
+ formatStack.pop();
+ }
+ } else {
+ QTextCharFormat format;
+ if (formatStack.count())
+ format = formatStack.top();
+ 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;
+ }
+ if (!ch->isNull())
+ ++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 QDeclarativeStyledTextPrivate::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) {
+ if (tagLength == 0)
+ return false;
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ if (char0 == QLatin1Char('b')) {
+ if (tagLength == 1)
+ format.setFontWeight(QFont::Bold);
+ else if (tagLength == 2 && tag.at(1) == QLatin1Char('r')) {
+ textOut.append(QChar(QChar::LineSeparator));
+ return false;
+ }
+ } else if (char0 == QLatin1Char('i')) {
+ if (tagLength == 1)
+ format.setFontItalic(true);
+ } else if (char0 == QLatin1Char('p')) {
+ if (tagLength == 1) {
+ if (!hasNewLine)
+ textOut.append(QChar::LineSeparator);
+ }
+ } else if (char0 == QLatin1Char('u')) {
+ if (tagLength == 1)
+ format.setFontUnderline(true);
+ else if (tag == QLatin1String("ul")) {
+ List listItem;
+ listItem.level = 0;
+ listItem.type = Unordered;
+ listItem.format = Bullet;
+ listStack.push(listItem);
+ }
+ } else if (char0 == QLatin1Char('h') && tagLength == 2) {
+ int level = tag.at(1).digitValue();
+ if (level >= 1 && level <= 6) {
+ static const qreal scaling[] = { 2.0, 1.5, 1.2, 1.0, 0.8, 0.7 };
+ if (!hasNewLine)
+ textOut.append(QChar::LineSeparator);
+ format.setFontPointSize(baseFont.pointSize() * scaling[level - 1]);
+ format.setFontWeight(QFont::Bold);
+ }
+ } else if (tag == QLatin1String("ol")) {
+ List listItem;
+ listItem.level = 0;
+ listItem.type = Ordered;
+ listItem.format = Decimal;
+ listStack.push(listItem);
+ } else if (tag == QLatin1String("li")) {
+ if (!hasNewLine)
+ textOut.append(QChar(QChar::LineSeparator));
+ if (!listStack.isEmpty()) {
+ int count = ++listStack.top().level;
+ for (int i = 0; i < listStack.size(); ++i)
+ textOut += QString(tabsize, QChar::Nbsp);
+ switch (listStack.top().format) {
+ case Decimal:
+ textOut += QString::number(count) % QLatin1Char('.');
+ break;
+ case LowerAlpha:
+ textOut += toAlpha(count, false) % QLatin1Char('.');
+ break;
+ case UpperAlpha:
+ textOut += toAlpha(count, true) % QLatin1Char('.');
+ break;
+ case LowerRoman:
+ textOut += toRoman(count, false) % QLatin1Char('.');
+ break;
+ case UpperRoman:
+ textOut += toRoman(count, true) % QLatin1Char('.');
+ break;
+ case Bullet:
+ textOut += bullet;
+ break;
+ case Disc:
+ textOut += disc;
+ break;
+ case Square:
+ textOut += square;
+ break;
+ }
+ textOut += QString(2, QChar::Nbsp);
+ }
+ }
+ return true;
+ } else if (ch->isSpace()) {
+ // may have params.
+ QStringRef tag(&textIn, tagStart, tagLength);
+ if (tag == QLatin1String("font"))
+ return parseFontAttributes(ch, textIn, format);
+ if (tag == QLatin1String("ol"))
+ return parseOrderedListAttributes(ch, textIn);
+ if (tag == QLatin1String("ul"))
+ return parseUnorderedListAttributes(ch, textIn);
+ if (tag == QLatin1String("a")) {
+ return parseAnchorAttributes(ch, textIn, format);
+ }
+ if (*ch == greaterThan || ch->isNull())
+ continue;
+ } else if (*ch != slash) {
+ tagLength++;
+ }
+ ++ch;
+ }
+ return false;
+}
+
+bool QDeclarativeStyledTextPrivate::parseCloseTag(const QChar *&ch, const QString &textIn, QString &textOut)
+{
+ skipSpace(ch);
+
+ int tagStart = ch - textIn.constData();
+ int tagLength = 0;
+ while (!ch->isNull()) {
+ if (*ch == greaterThan) {
+ if (tagLength == 0)
+ return false;
+ QStringRef tag(&textIn, tagStart, tagLength);
+ const QChar char0 = tag.at(0);
+ hasNewLine = false;
+ 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 (char0 == QLatin1Char('a')) {
+ if (tagLength == 1)
+ return true;
+ } else if (char0 == QLatin1Char('p')) {
+ if (tagLength == 1) {
+ textOut.append(QChar::LineSeparator);
+ hasNewLine = true;
+ return true;
+ }
+ } else if (char0 == QLatin1Char('u')) {
+ if (tagLength == 1)
+ return true;
+ else if (tag == QLatin1String("ul")) {
+ if (!listStack.isEmpty()) {
+ listStack.pop();
+ if (!listStack.count())
+ textOut.append(QChar::LineSeparator);
+ }
+ return true;
+ }
+ } else if (char0 == QLatin1Char('h') && tagLength == 2) {
+ textOut.append(QChar::LineSeparator);
+ hasNewLine = true;
+ return true;
+ } else if (tag == QLatin1String("font")) {
+ return true;
+ } else if (tag == QLatin1String("ol")) {
+ if (!listStack.isEmpty()) {
+ listStack.pop();
+ if (!listStack.count())
+ textOut.append(QChar::LineSeparator);
+ }
+ return true;
+ } else if (tag == QLatin1String("li")) {
+ return true;
+ }
+ return false;
+ } else if (!ch->isSpace()){
+ tagLength++;
+ }
+ ++ch;
+ }
+
+ return false;
+}
+
+void QDeclarativeStyledTextPrivate::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 QDeclarativeStyledTextPrivate::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;
+}
+
+bool QDeclarativeStyledTextPrivate::parseOrderedListAttributes(const QChar *&ch, const QString &textIn)
+{
+ bool valid = false;
+
+ List listItem;
+ listItem.level = 0;
+ listItem.type = Ordered;
+ listItem.format = Decimal;
+
+ QPair<QStringRef,QStringRef> attr;
+ do {
+ attr = parseAttribute(ch, textIn);
+ if (attr.first == QLatin1String("type")) {
+ valid = true;
+ if (attr.second == QLatin1String("a"))
+ listItem.format = LowerAlpha;
+ else if (attr.second == QLatin1String("A"))
+ listItem.format = UpperAlpha;
+ else if (attr.second == QLatin1String("i"))
+ listItem.format = LowerRoman;
+ else if (attr.second == QLatin1String("I"))
+ listItem.format = UpperRoman;
+ }
+ } while (!ch->isNull() && !attr.first.isEmpty());
+
+ listStack.push(listItem);
+ return valid;
+}
+
+bool QDeclarativeStyledTextPrivate::parseUnorderedListAttributes(const QChar *&ch, const QString &textIn)
+{
+ bool valid = false;
+
+ List listItem;
+ listItem.level = 0;
+ listItem.type = Unordered;
+ listItem.format = Bullet;
+
+ QPair<QStringRef,QStringRef> attr;
+ do {
+ attr = parseAttribute(ch, textIn);
+ if (attr.first == QLatin1String("type")) {
+ valid = true;
+ if (attr.second == QLatin1String("disc"))
+ listItem.format = Disc;
+ else if (attr.second == QLatin1String("square"))
+ listItem.format = Square;
+ }
+ } while (!ch->isNull() && !attr.first.isEmpty());
+
+ listStack.push(listItem);
+ return valid;
+}
+
+bool QDeclarativeStyledTextPrivate::parseAnchorAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
+{
+ bool valid = false;
+
+ QPair<QStringRef,QStringRef> attr;
+ do {
+ attr = parseAttribute(ch, textIn);
+ if (attr.first == QLatin1String("href")) {
+ format.setAnchorHref(attr.second.toString());
+ format.setAnchor(true);
+ format.setFontUnderline(true);
+ format.setForeground(QColor("blue"));
+ valid = true;
+ }
+ } while (!ch->isNull() && !attr.first.isEmpty());
+
+ return valid;
+}
+
+QPair<QStringRef,QStringRef> QDeclarativeStyledTextPrivate::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 QDeclarativeStyledTextPrivate::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);
+}
+
+QString QDeclarativeStyledTextPrivate::toAlpha(int value, bool upper)
+{
+ const char baseChar = upper ? 'A' : 'a';
+
+ QString result;
+ int c = value;
+ while (c > 0) {
+ c--;
+ result.prepend(QChar(baseChar + (c % 26)));
+ c /= 26;
+ }
+ return result;
+}
+
+QString QDeclarativeStyledTextPrivate::toRoman(int value, bool upper)
+{
+ QString result = QLatin1String("?");
+ // works for up to 4999 items
+ if (value < 5000) {
+ QByteArray romanNumeral;
+
+ static const char romanSymbolsLower[] = "iiivixxxlxcccdcmmmm";
+ static const char romanSymbolsUpper[] = "IIIVIXXXLXCCCDCMMMM";
+ QByteArray romanSymbols;
+ if (!upper)
+ romanSymbols = QByteArray::fromRawData(romanSymbolsLower, sizeof(romanSymbolsLower));
+ else
+ romanSymbols = QByteArray::fromRawData(romanSymbolsUpper, sizeof(romanSymbolsUpper));
+
+ int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
+ int n = value;
+ for (int i = 12; i >= 0; n %= c[i], i--) {
+ int q = n / c[i];
+ if (q > 0) {
+ int startDigit = i + (i + 3) / 4;
+ int numDigits;
+ if (i % 4) {
+ if ((i - 2) % 4)
+ numDigits = 2;
+ else
+ numDigits = 1;
+ }
+ else
+ numDigits = q;
+ romanNumeral.append(romanSymbols.mid(startDigit, numDigits));
+ }
+ }
+ result = QString::fromLatin1(romanNumeral);
+ }
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativestyledtext_p.h b/src/quick/util/qdeclarativestyledtext_p.h
new file mode 100644
index 0000000000..beffb4d22a
--- /dev/null
+++ b/src/quick/util/qdeclarativestyledtext_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESTYLEDTEXT_H
+#define QDECLARATIVESTYLEDTEXT_H
+
+#include <QSizeF>
+
+QT_BEGIN_NAMESPACE
+
+class QPainter;
+class QPointF;
+class QString;
+class QDeclarativeStyledTextPrivate;
+class QTextLayout;
+
+class Q_AUTOTEST_EXPORT QDeclarativeStyledText
+{
+public:
+ static void parse(const QString &string, QTextLayout &layout);
+
+private:
+ QDeclarativeStyledText(const QString &string, QTextLayout &layout);
+ ~QDeclarativeStyledText();
+
+ QDeclarativeStyledTextPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/util/qdeclarativesvgparser.cpp b/src/quick/util/qdeclarativesvgparser.cpp
new file mode 100644
index 0000000000..e8ceb2116c
--- /dev/null
+++ b/src/quick/util/qdeclarativesvgparser.cpp
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativesvgparser_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+static const double Q_PI = 3.14159265358979323846; // pi
+
+//copied from QtSvg (qsvghandler.cpp).
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+// '0' is 0x30 and '9' is 0x39
+static inline bool isDigit(ushort ch)
+{
+ static quint16 magic = 0x3ff;
+ return ((ch >> 4) == 3) && (magic >> (ch & 15));
+}
+
+static qreal toDouble(const QChar *&str)
+{
+ const int maxLen = 255;//technically doubles can go til 308+ but whatever
+ char temp[maxLen+1];
+ int pos = 0;
+
+ if (*str == QLatin1Char('-')) {
+ temp[pos++] = '-';
+ ++str;
+ } else if (*str == QLatin1Char('+')) {
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ if (*str == QLatin1Char('.') && pos < maxLen) {
+ temp[pos++] = '.';
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ bool exponent = false;
+ if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) {
+ exponent = true;
+ temp[pos++] = 'e';
+ ++str;
+ if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ }
+
+ temp[pos] = '\0';
+
+ qreal val;
+ if (!exponent && pos < 10) {
+ int ival = 0;
+ const char *t = temp;
+ bool neg = false;
+ if(*t == '-') {
+ neg = true;
+ ++t;
+ }
+ while(*t && *t != '.') {
+ ival *= 10;
+ ival += (*t) - '0';
+ ++t;
+ }
+ if(*t == '.') {
+ ++t;
+ int div = 1;
+ while(*t) {
+ ival *= 10;
+ ival += (*t) - '0';
+ div *= 10;
+ ++t;
+ }
+ val = ((qreal)ival)/((qreal)div);
+ } else {
+ val = ival;
+ }
+ if (neg)
+ val = -val;
+ } else {
+#if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS)
+ if(sizeof(qreal) == sizeof(float))
+ val = strtof(temp, 0);
+ else
+#endif
+ {
+ bool ok = false;
+ val = qstrtod(temp, 0, &ok);
+ }
+ }
+ return val;
+
+}
+static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points)
+{
+ while (str->isSpace())
+ ++str;
+ while (isDigit(str->unicode()) ||
+ *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
+ *str == QLatin1Char('.')) {
+
+ points.append(toDouble(str));
+
+ while (str->isSpace())
+ ++str;
+ if (*str == QLatin1Char(','))
+ ++str;
+
+ //eat the rest of space
+ while (str->isSpace())
+ ++str;
+ }
+}
+
+static void pathArcSegment(QPainterPath &path,
+ qreal xc, qreal yc,
+ qreal th0, qreal th1,
+ qreal rx, qreal ry, qreal xAxisRotation)
+{
+ qreal sinTh, cosTh;
+ qreal a00, a01, a10, a11;
+ qreal x1, y1, x2, y2, x3, y3;
+ qreal t;
+ qreal thHalf;
+
+ sinTh = qSin(xAxisRotation * (Q_PI / 180.0));
+ cosTh = qCos(xAxisRotation * (Q_PI / 180.0));
+
+ a00 = cosTh * rx;
+ a01 = -sinTh * ry;
+ a10 = sinTh * rx;
+ a11 = cosTh * ry;
+
+ thHalf = 0.5 * (th1 - th0);
+ t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
+ x1 = xc + qCos(th0) - t * qSin(th0);
+ y1 = yc + qSin(th0) + t * qCos(th0);
+ x3 = xc + qCos(th1);
+ y3 = yc + qSin(th1);
+ x2 = x3 + t * qSin(th1);
+ y2 = y3 - t * qCos(th1);
+
+ path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
+ a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
+ a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
+}
+
+void QDeclarativeSvgParser::pathArc(QPainterPath &path,
+ qreal rx,
+ qreal ry,
+ qreal x_axis_rotation,
+ int large_arc_flag,
+ int sweep_flag,
+ qreal x,
+ qreal y,
+ qreal curx, qreal cury)
+{
+ qreal sin_th, cos_th;
+ qreal a00, a01, a10, a11;
+ qreal x0, y0, x1, y1, xc, yc;
+ qreal d, sfactor, sfactor_sq;
+ qreal th0, th1, th_arc;
+ int i, n_segs;
+ qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
+
+ rx = qAbs(rx);
+ ry = qAbs(ry);
+
+ sin_th = qSin(x_axis_rotation * (Q_PI / 180.0));
+ cos_th = qCos(x_axis_rotation * (Q_PI / 180.0));
+
+ dx = (curx - x) / 2.0;
+ dy = (cury - y) / 2.0;
+ dx1 = cos_th * dx + sin_th * dy;
+ dy1 = -sin_th * dx + cos_th * dy;
+ Pr1 = rx * rx;
+ Pr2 = ry * ry;
+ Px = dx1 * dx1;
+ Py = dy1 * dy1;
+ /* Spec : check if radii are large enough */
+ check = Px / Pr1 + Py / Pr2;
+ if (check > 1) {
+ rx = rx * qSqrt(check);
+ ry = ry * qSqrt(check);
+ }
+
+ a00 = cos_th / rx;
+ a01 = sin_th / rx;
+ a10 = -sin_th / ry;
+ a11 = cos_th / ry;
+ x0 = a00 * curx + a01 * cury;
+ y0 = a10 * curx + a11 * cury;
+ x1 = a00 * x + a01 * y;
+ y1 = a10 * x + a11 * y;
+ /* (x0, y0) is current point in transformed coordinate space.
+ (x1, y1) is new point in transformed coordinate space.
+
+ The arc fits a unit-radius circle in this space.
+ */
+ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+ sfactor_sq = 1.0 / d - 0.25;
+ if (sfactor_sq < 0) sfactor_sq = 0;
+ sfactor = qSqrt(sfactor_sq);
+ if (sweep_flag == large_arc_flag) sfactor = -sfactor;
+ xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+ yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+ /* (xc, yc) is center of the circle. */
+
+ th0 = qAtan2(y0 - yc, x0 - xc);
+ th1 = qAtan2(y1 - yc, x1 - xc);
+
+ th_arc = th1 - th0;
+ if (th_arc < 0 && sweep_flag)
+ th_arc += 2 * Q_PI;
+ else if (th_arc > 0 && !sweep_flag)
+ th_arc -= 2 * Q_PI;
+
+ n_segs = qCeil(qAbs(th_arc / (Q_PI * 0.5 + 0.001)));
+
+ for (i = 0; i < n_segs; i++) {
+ pathArcSegment(path, xc, yc,
+ th0 + i * th_arc / n_segs,
+ th0 + (i + 1) * th_arc / n_segs,
+ rx, ry, x_axis_rotation);
+ }
+}
+
+
+bool QDeclarativeSvgParser::parsePathDataFast(const QString &dataStr, QPainterPath &path)
+{
+ qreal x0 = 0, y0 = 0; // starting point
+ qreal x = 0, y = 0; // current point
+ char lastMode = 0;
+ QPointF ctrlPt;
+ const QChar *str = dataStr.constData();
+ const QChar *end = str + dataStr.size();
+
+ while (str != end) {
+ while (str->isSpace())
+ ++str;
+ QChar pathElem = *str;
+ ++str;
+ QChar endc = *end;
+ *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
+ QVarLengthArray<qreal, 8> arg;
+ parseNumbersArray(str, arg);
+ *const_cast<QChar *>(end) = endc;
+ if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
+ arg.append(0);//dummy
+ const qreal *num = arg.constData();
+ int count = arg.count();
+ while (count > 0) {
+ qreal offsetX = x; // correction offsets
+ qreal offsetY = y; // for relative commands
+ switch (pathElem.unicode()) {
+ case 'm': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = x0 = num[0] + offsetX;
+ y = y0 = num[1] + offsetY;
+ num += 2;
+ count -= 2;
+ path.moveTo(x0, y0);
+
+ // As per 1.2 spec 8.3.2 The "moveto" commands
+ // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+ // the subsequent pairs shall be treated as implicit 'lineto' commands.
+ pathElem = QLatin1Char('l');
+ }
+ break;
+ case 'M': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = x0 = num[0];
+ y = y0 = num[1];
+ num += 2;
+ count -= 2;
+ path.moveTo(x0, y0);
+
+ // As per 1.2 spec 8.3.2 The "moveto" commands
+ // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+ // the subsequent pairs shall be treated as implicit 'lineto' commands.
+ pathElem = QLatin1Char('L');
+ }
+ break;
+ case 'z':
+ case 'Z': {
+ x = x0;
+ y = y0;
+ count--; // skip dummy
+ num++;
+ path.closeSubpath();
+ }
+ break;
+ case 'l': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = num[0] + offsetX;
+ y = num[1] + offsetY;
+ num += 2;
+ count -= 2;
+ path.lineTo(x, y);
+
+ }
+ break;
+ case 'L': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = num[0];
+ y = num[1];
+ num += 2;
+ count -= 2;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'h': {
+ x = num[0] + offsetX;
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'H': {
+ x = num[0];
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'v': {
+ y = num[0] + offsetY;
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'V': {
+ y = num[0];
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'c': {
+ if (count < 6) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1(num[0] + offsetX, num[1] + offsetY);
+ QPointF c2(num[2] + offsetX, num[3] + offsetY);
+ QPointF e(num[4] + offsetX, num[5] + offsetY);
+ num += 6;
+ count -= 6;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'C': {
+ if (count < 6) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1(num[0], num[1]);
+ QPointF c2(num[2], num[3]);
+ QPointF e(num[4], num[5]);
+ num += 6;
+ count -= 6;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 's': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1;
+ if (lastMode == 'c' || lastMode == 'C' ||
+ lastMode == 's' || lastMode == 'S')
+ c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c1 = QPointF(x, y);
+ QPointF c2(num[0] + offsetX, num[1] + offsetY);
+ QPointF e(num[2] + offsetX, num[3] + offsetY);
+ num += 4;
+ count -= 4;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'S': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1;
+ if (lastMode == 'c' || lastMode == 'C' ||
+ lastMode == 's' || lastMode == 'S')
+ c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c1 = QPointF(x, y);
+ QPointF c2(num[0], num[1]);
+ QPointF e(num[2], num[3]);
+ num += 4;
+ count -= 4;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'q': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c(num[0] + offsetX, num[1] + offsetY);
+ QPointF e(num[2] + offsetX, num[3] + offsetY);
+ num += 4;
+ count -= 4;
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'Q': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c(num[0], num[1]);
+ QPointF e(num[2], num[3]);
+ num += 4;
+ count -= 4;
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 't': {
+ if (count < 2) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF e(num[0] + offsetX, num[1] + offsetY);
+ num += 2;
+ count -= 2;
+ QPointF c;
+ if (lastMode == 'q' || lastMode == 'Q' ||
+ lastMode == 't' || lastMode == 'T')
+ c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c = QPointF(x, y);
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'T': {
+ if (count < 2) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF e(num[0], num[1]);
+ num += 2;
+ count -= 2;
+ QPointF c;
+ if (lastMode == 'q' || lastMode == 'Q' ||
+ lastMode == 't' || lastMode == 'T')
+ c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c = QPointF(x, y);
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'a': {
+ if (count < 7) {
+ num += count;
+ count = 0;
+ break;
+ }
+ qreal rx = (*num++);
+ qreal ry = (*num++);
+ qreal xAxisRotation = (*num++);
+ qreal largeArcFlag = (*num++);
+ qreal sweepFlag = (*num++);
+ qreal ex = (*num++) + offsetX;
+ qreal ey = (*num++) + offsetY;
+ count -= 7;
+ qreal curx = x;
+ qreal cury = y;
+ pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+ int(sweepFlag), ex, ey, curx, cury);
+
+ x = ex;
+ y = ey;
+ }
+ break;
+ case 'A': {
+ if (count < 7) {
+ num += count;
+ count = 0;
+ break;
+ }
+ qreal rx = (*num++);
+ qreal ry = (*num++);
+ qreal xAxisRotation = (*num++);
+ qreal largeArcFlag = (*num++);
+ qreal sweepFlag = (*num++);
+ qreal ex = (*num++);
+ qreal ey = (*num++);
+ count -= 7;
+ qreal curx = x;
+ qreal cury = y;
+ pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+ int(sweepFlag), ex, ey, curx, cury);
+
+ x = ex;
+ y = ey;
+ }
+ break;
+ default:
+ return false;
+ }
+ lastMode = pathElem.toLatin1();
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativesvgparser_p.h b/src/quick/util/qdeclarativesvgparser_p.h
new file mode 100644
index 0000000000..0d7be10761
--- /dev/null
+++ b/src/quick/util/qdeclarativesvgparser_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESVGPARSER_P_H
+#define QDECLARATIVESVGPARSER_P_H
+
+#include <QtCore/qstring.h>
+#include <QtGui/qpainterpath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeSvgParser
+{
+ bool parsePathDataFast(const QString &dataStr, QPainterPath &path);
+ void pathArc(QPainterPath &path, qreal rx, qreal ry, qreal x_axis_rotation,
+ int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx,
+ qreal cury);
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESVGPARSER_P_H
diff --git a/src/quick/util/qdeclarativesystempalette.cpp b/src/quick/util/qdeclarativesystempalette.cpp
new file mode 100644
index 0000000000..61d8406141
--- /dev/null
+++ b/src/quick/util/qdeclarativesystempalette.cpp
@@ -0,0 +1,312 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativesystempalette_p.h"
+
+#include <QGuiApplication>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSystemPalettePrivate : public QObjectPrivate
+{
+public:
+ QPalette palette;
+ QPalette::ColorGroup group;
+};
+
+
+
+/*!
+ \qmlclass SystemPalette QDeclarativeSystemPalette
+ \inqmlmodule QtQuick 2
+ \ingroup qml-utility-elements
+ \brief The SystemPalette element provides access to the Qt palettes.
+
+ The SystemPalette element provides access to the Qt application
+ palettes. This provides information about the standard colors used
+ for application windows, buttons and other features. These colors
+ are grouped into three \e {color groups}: \c Active, \c Inactive,
+ and \c Disabled. See the QPalette documentation for details about
+ color groups and the properties provided by SystemPalette.
+
+ This can be used to color items in a way that provides a more
+ native look and feel.
+
+ The following example creates a palette from the \c Active color
+ group and uses this to color the window and text items
+ appropriately:
+
+ \snippet doc/src/snippets/declarative/systempalette.qml 0
+
+ \sa QPalette
+*/
+QDeclarativeSystemPalette::QDeclarativeSystemPalette(QObject *parent)
+ : QObject(*(new QDeclarativeSystemPalettePrivate), parent)
+{
+ Q_D(QDeclarativeSystemPalette);
+ d->palette = QGuiApplication::palette();
+ d->group = QPalette::Active;
+ qApp->installEventFilter(this);
+}
+
+QDeclarativeSystemPalette::~QDeclarativeSystemPalette()
+{
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::window
+ The window (general background) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::window() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Window);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::windowText
+ The window text (general foreground) color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::windowText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::WindowText);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::base
+ The base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::base() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Base);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::text
+ The text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::text() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Text);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::alternateBase
+ The alternate base color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::alternateBase() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::AlternateBase);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::button
+ The button color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::button() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Button);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::buttonText
+ The button text foreground color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::buttonText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::ButtonText);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::light
+ The light color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::light() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Light);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::midlight
+ The midlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::midlight() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Midlight);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::dark
+ The dark color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::dark() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Dark);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::mid
+ The mid color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::mid() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Mid);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::shadow
+ The shadow color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::shadow() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Shadow);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::highlight
+ The highlight color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::highlight() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::Highlight);
+}
+
+/*!
+ \qmlproperty color QtQuick2::SystemPalette::highlightedText
+ The highlighted text color of the current color group.
+
+ \sa QPalette::ColorRole
+*/
+QColor QDeclarativeSystemPalette::highlightedText() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return d->palette.color(d->group, QPalette::HighlightedText);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::SystemPalette::colorGroup
+
+ The color group of the palette. This can be one of:
+
+ \list
+ \o SystemPalette.Active (default)
+ \o SystemPalette.Inactive
+ \o SystemPalette.Disabled
+ \endlist
+
+ \sa QPalette::ColorGroup
+*/
+QDeclarativeSystemPalette::ColorGroup QDeclarativeSystemPalette::colorGroup() const
+{
+ Q_D(const QDeclarativeSystemPalette);
+ return (QDeclarativeSystemPalette::ColorGroup)d->group;
+}
+
+void QDeclarativeSystemPalette::setColorGroup(QDeclarativeSystemPalette::ColorGroup colorGroup)
+{
+ Q_D(QDeclarativeSystemPalette);
+ d->group = (QPalette::ColorGroup)colorGroup;
+ emit paletteChanged();
+}
+
+bool QDeclarativeSystemPalette::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched == qApp) {
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ QGuiApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
+ return false;
+ }
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+bool QDeclarativeSystemPalette::event(QEvent *event)
+{
+ Q_D(QDeclarativeSystemPalette);
+ if (event->type() == QEvent::ApplicationPaletteChange) {
+ d->palette = QGuiApplication::palette();
+ emit paletteChanged();
+ return true;
+ }
+ return QObject::event(event);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativesystempalette_p.h b/src/quick/util/qdeclarativesystempalette_p.h
new file mode 100644
index 0000000000..25224fd4d1
--- /dev/null
+++ b/src/quick/util/qdeclarativesystempalette_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESYSTEMPALETTE_H
+#define QDECLARATIVESYSTEMPALETTE_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QPalette>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeSystemPalettePrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeSystemPalette : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ColorGroup)
+ Q_DECLARE_PRIVATE(QDeclarativeSystemPalette)
+
+ Q_PROPERTY(QDeclarativeSystemPalette::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:
+ QDeclarativeSystemPalette(QObject *parent=0);
+ ~QDeclarativeSystemPalette();
+
+ 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;
+
+ QDeclarativeSystemPalette::ColorGroup colorGroup() const;
+ void setColorGroup(QDeclarativeSystemPalette::ColorGroup);
+
+Q_SIGNALS:
+ void paletteChanged();
+
+private:
+ bool eventFilter(QObject *watched, QEvent *event);
+ bool event(QEvent *event);
+
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeSystemPalette)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVESYSTEMPALETTE_H
diff --git a/src/quick/util/qdeclarativetimeline.cpp b/src/quick/util/qdeclarativetimeline.cpp
new file mode 100644
index 0000000000..7066d3d062
--- /dev/null
+++ b/src/quick/util/qdeclarativetimeline.cpp
@@ -0,0 +1,947 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativetimeline_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(QDeclarativeTimeLineValue *_g, qreal _v)
+ : g(_g), v(_v) {}
+ Update(const QDeclarativeTimeLineCallback &_e)
+ : g(0), v(0), e(_e) {}
+
+ QDeclarativeTimeLineValue *g;
+ qreal v;
+ QDeclarativeTimeLineCallback e;
+};
+
+struct QDeclarativeTimeLinePrivate
+{
+ QDeclarativeTimeLinePrivate(QDeclarativeTimeLine *);
+
+ struct Op {
+ enum Type {
+ Pause,
+ Set,
+ Move,
+ MoveBy,
+ Accel,
+ AccelDistance,
+ Execute
+ };
+ Op() {}
+ Op(Type t, int l, qreal v, qreal v2, int o,
+ const QDeclarativeTimeLineCallback &ev = QDeclarativeTimeLineCallback(), 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;
+ QDeclarativeTimeLineCallback 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<QDeclarativeTimeLineObject *, TimeLine> Ops;
+ Ops ops;
+ QDeclarativeTimeLine *q;
+
+ void add(QDeclarativeTimeLineObject &, const Op &);
+ qreal value(const Op &op, int time, qreal base, bool *) const;
+
+ int advance(int);
+
+ bool clockRunning;
+ int prevTime;
+
+ int order;
+
+ QDeclarativeTimeLine::SyncMode syncMode;
+ int syncAdj;
+ QList<QPair<int, Update> > *updateQueue;
+};
+
+QDeclarativeTimeLinePrivate::QDeclarativeTimeLinePrivate(QDeclarativeTimeLine *parent)
+: length(0), syncPoint(0), q(parent), clockRunning(false), prevTime(0), order(0), syncMode(QDeclarativeTimeLine::LocalSync), syncAdj(0), updateQueue(0)
+{
+}
+
+void QDeclarativeTimeLinePrivate::add(QDeclarativeTimeLineObject &g, const Op &o)
+{
+ if (g._t && g._t != q) {
+ qWarning() << "QDeclarativeTimeLine: Cannot modify a QDeclarativeTimeLineValue 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 == QDeclarativeTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ q->start();
+/* q->tick(0);
+ if (syncMode == QDeclarativeTimeLine::LocalSync) {
+ syncAdj = -1;
+ } else {
+ syncAdj = 0;
+ }
+ */
+ }
+}
+
+qreal QDeclarativeTimeLinePrivate::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.d0(op.event.d1);
+ *changed = false;
+ return -1;
+ }
+
+ return base;
+}
+
+/*!
+ \internal
+ \class QDeclarativeTimeLine
+ \brief The QDeclarativeTimeLine class provides a timeline for controlling animations.
+
+ QDeclarativeTimeLine is similar to QTimeLine except:
+ \list
+ \i It updates QDeclarativeTimeLineValue instances directly, rather than maintaining a single
+ current value.
+
+ For example, the following animates a simple value over 200 milliseconds:
+ \code
+ QDeclarativeTimeLineValue v(<starting value>);
+ QDeclarativeTimeLine 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 QDeclarativeTimeLine's updated() signal, or inherit from QDeclarativeTimeLineValue
+ and reimplement the QDeclarativeTimeLineValue::setValue() method.
+
+ \i Supports multiple QDeclarativeTimeLineValue, 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
+ QDeclarativeTimeLineValue x(<starting value>);
+ QDeclarativeTimeLineValue y(<starting value>);
+
+ QDeclarativeTimeLine tl;
+ tl.start();
+
+ tl.move(x, 100., 50);
+ tl.move(y, 100., 50);
+ tl.move(y, 200., 50);
+ \endcode
+
+ \i All QDeclarativeTimeLine 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
+ QDeclarativeTimeLine and across separate QDeclarativeTimeLine's within the same process.
+
+ \endlist
+
+ Currently easing functions are not supported.
+*/
+
+
+/*!
+ Construct a new QDeclarativeTimeLine with the specified \a parent.
+*/
+QDeclarativeTimeLine::QDeclarativeTimeLine(QObject *parent)
+: QAbstractAnimation(parent)
+{
+ d = new QDeclarativeTimeLinePrivate(this);
+}
+
+/*!
+ Destroys the time line. Any inprogress animations are canceled, but not
+ completed.
+*/
+QDeclarativeTimeLine::~QDeclarativeTimeLine()
+{
+ for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
+ iter != d->ops.end();
+ ++iter)
+ iter.key()->_t = 0;
+
+ delete d; d = 0;
+}
+
+/*!
+ \enum QDeclarativeTimeLine::SyncMode
+ */
+
+/*!
+ Return the timeline's synchronization mode.
+ */
+QDeclarativeTimeLine::SyncMode QDeclarativeTimeLine::syncMode() const
+{
+ return d->syncMode;
+}
+
+/*!
+ Set the timeline's synchronization mode to \a syncMode.
+ */
+void QDeclarativeTimeLine::setSyncMode(SyncMode syncMode)
+{
+ d->syncMode = syncMode;
+}
+
+/*!
+ Pause \a obj for \a time milliseconds.
+*/
+void QDeclarativeTimeLine::pause(QDeclarativeTimeLineObject &obj, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
+ d->add(obj, op);
+}
+
+/*!
+ Execute the \a event.
+ */
+void QDeclarativeTimeLine::callback(const QDeclarativeTimeLineCallback &callback)
+{
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, callback);
+ d->add(*callback.callbackObject(), op);
+}
+
+/*!
+ Set the \a value of \a timeLineValue.
+*/
+void QDeclarativeTimeLine::set(QDeclarativeTimeLineValue &timeLineValue, qreal value)
+{
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine will ensure
+ that the deceleration is in the opposite direction to the initial velocity.
+*/
+int QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
+{
+ if (acceleration == 0.0f)
+ return -1;
+
+ if ((velocity > 0.0f) == (acceleration > 0.0f))
+ acceleration = acceleration * -1.0f;
+
+ int time = static_cast<int>(-1000 * velocity / acceleration);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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, QDeclarativeTimeLine 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 QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
+{
+ if (maxDistance == 0.0f || acceleration == 0.0f)
+ return -1;
+
+ 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);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine calculates the exact
+ deceleration to use.
+
+ \a distance should be positive.
+*/
+int QDeclarativeTimeLine::accelDistance(QDeclarativeTimeLineValue &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);
+
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QDeclarativeTimeLineCallback(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Linearly change the \a timeLineValue from its current value by the \a change amount
+ over \a time milliseconds.
+*/
+void QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
+{
+ if (time <= 0) return;
+ QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QDeclarativeTimeLineCallback(), easing);
+ d->add(timeLineValue, op);
+}
+
+/*!
+ Cancel (but don't complete) all scheduled actions for \a timeLineValue.
+*/
+void QDeclarativeTimeLine::reset(QDeclarativeTimeLineValue &timeLineValue)
+{
+ if (!timeLineValue._t)
+ return;
+ if (timeLineValue._t != this) {
+ qWarning() << "QDeclarativeTimeLine: Cannot reset a QDeclarativeTimeLineValue owned by another timeline.";
+ return;
+ }
+ remove(&timeLineValue);
+ timeLineValue._t = 0;
+}
+
+int QDeclarativeTimeLine::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
+ pseudo-code this is equivalent to:
+ \code
+ QDeclarativeTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
+ \endcode
+*/
+void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue, QDeclarativeTimeLineValue &syncTo)
+{
+ QDeclarativeTimeLinePrivate::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 pseudo-code, this is equivalent to:
+ \code
+ QDeclarativeTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
+ \endcode
+*/
+void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue)
+{
+ QDeclarativeTimeLinePrivate::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.);
+ QDeclarativeTimeLine 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 QDeclarativeTimeLine::sync()
+{
+ for (QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine::setSyncPoint(int sp)
+{
+ d->syncPoint = sp;
+}
+
+/*!
+ \internal
+
+ Temporary hack.
+ */
+int QDeclarativeTimeLine::syncPoint() const
+{
+ return d->syncPoint;
+}
+
+/*!
+ Returns true if the timeline is active. An active timeline is one where
+ QDeclarativeTimeLineValue actions are still pending.
+*/
+bool QDeclarativeTimeLine::isActive() const
+{
+ return !d->ops.isEmpty();
+}
+
+/*!
+ Completes the timeline. All queued actions are played to completion, and then discarded. For example,
+ \code
+ QDeclarativeTimeLineValue v(0.);
+ QDeclarativeTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.complete();
+ // v.value() == 100.
+ \endcode
+*/
+void QDeclarativeTimeLine::complete()
+{
+ d->advance(d->length);
+}
+
+/*!
+ Resets the timeline. All queued actions are discarded and QDeclarativeTimeLineValue's retain their current value. For example,
+ \code
+ QDeclarativeTimeLineValue v(0.);
+ QDeclarativeTimeLine tl;
+ tl.move(v, 100., 1000.);
+ // 500 ms passes
+ // v.value() == 50.
+ tl.clear();
+ // v.value() == 50.
+ \endcode
+*/
+void QDeclarativeTimeLine::clear()
+{
+ for (QDeclarativeTimeLinePrivate::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 QDeclarativeTimeLine::time() const
+{
+ return d->prevTime;
+}
+
+/*!
+ \fn void QDeclarativeTimeLine::updated()
+
+ Emitted each time the timeline modifies QDeclarativeTimeLineValues. Even if multiple
+ QDeclarativeTimeLineValues are changed, this signal is only emitted once for each clock tick.
+*/
+
+void QDeclarativeTimeLine::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 QDeclarativeTimeLinePrivate::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(); ) {
+ QDeclarativeTimeLineValue *v = static_cast<QDeclarativeTimeLineValue *>(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.d0(v.e.d1);
+ }
+ }
+ updateQueue = 0;
+ } while(t);
+
+ return pauseTime;
+}
+
+void QDeclarativeTimeLine::remove(QDeclarativeTimeLineObject *v)
+{
+ QDeclarativeTimeLinePrivate::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 (QDeclarativeTimeLinePrivate::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 == QDeclarativeTimeLine::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.callbackObject() == v) {
+ d->updateQueue->removeAt(ii);
+ --ii;
+ }
+ }
+ }
+
+
+}
+
+/*!
+ \internal
+ \class QDeclarativeTimeLineValue
+ \brief The QDeclarativeTimeLineValue class provides a value that can be modified by QDeclarativeTimeLine.
+*/
+
+/*!
+ \fn QDeclarativeTimeLineValue::QDeclarativeTimeLineValue(qreal value = 0)
+
+ Construct a new QDeclarativeTimeLineValue with an initial \a value.
+*/
+
+/*!
+ \fn qreal QDeclarativeTimeLineValue::value() const
+
+ Return the current value.
+*/
+
+/*!
+ \fn void QDeclarativeTimeLineValue::setValue(qreal value)
+
+ Set the current \a value.
+*/
+
+/*!
+ \fn QDeclarativeTimeLine *QDeclarativeTimeLineValue::timeLine() const
+
+ If a QDeclarativeTimeLine is operating on this value, return a pointer to it,
+ otherwise return null.
+*/
+
+
+QDeclarativeTimeLineObject::QDeclarativeTimeLineObject()
+: _t(0)
+{
+}
+
+QDeclarativeTimeLineObject::~QDeclarativeTimeLineObject()
+{
+ if (_t) {
+ _t->remove(this);
+ _t = 0;
+ }
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback()
+: d0(0), d1(0), d2(0)
+{
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback f, void *d)
+: d0(f), d1(d), d2(b)
+{
+}
+
+QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o)
+: d0(o.d0), d1(o.d1), d2(o.d2)
+{
+}
+
+QDeclarativeTimeLineCallback &QDeclarativeTimeLineCallback::operator=(const QDeclarativeTimeLineCallback &o)
+{
+ d0 = o.d0;
+ d1 = o.d1;
+ d2 = o.d2;
+ return *this;
+}
+
+QDeclarativeTimeLineObject *QDeclarativeTimeLineCallback::callbackObject() const
+{
+ return d2;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativetimeline_p_p.h b/src/quick/util/qdeclarativetimeline_p_p.h
new file mode 100644
index 0000000000..d84053903f
--- /dev/null
+++ b/src/quick/util/qdeclarativetimeline_p_p.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVETIMELINE_H
+#define QDECLARATIVETIMELINE_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 QDeclarativeTimeLineValue;
+class QDeclarativeTimeLineCallback;
+struct QDeclarativeTimeLinePrivate;
+class QDeclarativeTimeLineObject;
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLine : public QAbstractAnimation
+{
+Q_OBJECT
+public:
+ QDeclarativeTimeLine(QObject *parent = 0);
+ ~QDeclarativeTimeLine();
+
+ enum SyncMode { LocalSync, GlobalSync };
+ SyncMode syncMode() const;
+ void setSyncMode(SyncMode);
+
+ void pause(QDeclarativeTimeLineObject &, int);
+ void callback(const QDeclarativeTimeLineCallback &);
+ void set(QDeclarativeTimeLineValue &, qreal);
+
+ int accel(QDeclarativeTimeLineValue &, qreal velocity, qreal accel);
+ int accel(QDeclarativeTimeLineValue &, qreal velocity, qreal accel, qreal maxDistance);
+ int accelDistance(QDeclarativeTimeLineValue &, qreal velocity, qreal distance);
+
+ void move(QDeclarativeTimeLineValue &, qreal destination, int time = 500);
+ void move(QDeclarativeTimeLineValue &, qreal destination, const QEasingCurve &, int time = 500);
+ void moveBy(QDeclarativeTimeLineValue &, qreal change, int time = 500);
+ void moveBy(QDeclarativeTimeLineValue &, qreal change, const QEasingCurve &, int time = 500);
+
+ void sync();
+ void setSyncPoint(int);
+ int syncPoint() const;
+
+ void sync(QDeclarativeTimeLineValue &);
+ void sync(QDeclarativeTimeLineValue &, QDeclarativeTimeLineValue &);
+
+ void reset(QDeclarativeTimeLineValue &);
+
+ 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(QDeclarativeTimeLineObject *);
+ friend class QDeclarativeTimeLineObject;
+ friend struct QDeclarativeTimeLinePrivate;
+ QDeclarativeTimeLinePrivate *d;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineObject
+{
+public:
+ QDeclarativeTimeLineObject();
+ virtual ~QDeclarativeTimeLineObject();
+
+protected:
+ friend class QDeclarativeTimeLine;
+ friend struct QDeclarativeTimeLinePrivate;
+ QDeclarativeTimeLine *_t;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineValue : public QDeclarativeTimeLineObject
+{
+public:
+ QDeclarativeTimeLineValue(qreal v = 0.) : _v(v) {}
+
+ virtual qreal value() const { return _v; }
+ virtual void setValue(qreal v) { _v = v; }
+
+ QDeclarativeTimeLine *timeLine() const { return _t; }
+
+ operator qreal() const { return _v; }
+ QDeclarativeTimeLineValue &operator=(qreal v) { setValue(v); return *this; }
+private:
+ friend class QDeclarativeTimeLine;
+ friend struct QDeclarativeTimeLinePrivate;
+ qreal _v;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativeTimeLineCallback
+{
+public:
+ typedef void (*Callback)(void *);
+
+ QDeclarativeTimeLineCallback();
+ QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback, void * = 0);
+ QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o);
+
+ QDeclarativeTimeLineCallback &operator=(const QDeclarativeTimeLineCallback &o);
+ QDeclarativeTimeLineObject *callbackObject() const;
+
+private:
+ friend struct QDeclarativeTimeLinePrivate;
+ Callback d0;
+ void *d1;
+ QDeclarativeTimeLineObject *d2;
+};
+
+template<class T>
+class QDeclarativeTimeLineValueProxy : public QDeclarativeTimeLineValue
+{
+public:
+ QDeclarativeTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.)
+ : QDeclarativeTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0)
+ {
+ Q_ASSERT(_class);
+ }
+
+ QDeclarativeTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.)
+ : QDeclarativeTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func)
+ {
+ Q_ASSERT(_class);
+ }
+
+ virtual void setValue(qreal v)
+ {
+ QDeclarativeTimeLineValue::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/quick/util/qdeclarativetimer.cpp b/src/quick/util/qdeclarativetimer.cpp
new file mode 100644
index 0000000000..a4a2362680
--- /dev/null
+++ b/src/quick/util/qdeclarativetimer.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativetimer_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpauseanimation.h>
+#include <qdebug.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+
+class QDeclarativeTimerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTimer)
+public:
+ QDeclarativeTimerPrivate()
+ : 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 QDeclarativeTimer
+ \inqmlmodule QtQuick 2
+ \ingroup qml-utility-elements
+ \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. It uses the JavaScript \c Date
+ object to access the current time.
+
+ \qml
+ import QtQuick 1.0
+
+ Item {
+ Timer {
+ interval: 500; running: true; repeat: true
+ onTriggered: time.text = Date().toString()
+ }
+
+ Text { id: time }
+ }
+ \endqml
+
+ The Timer element is synchronized with the animation timer. Since the animation
+ timer is usually set to 60fps, the resolution of Timer 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.
+
+ \sa {declarative/toys/clocks}{Clocks example}
+*/
+
+QDeclarativeTimer::QDeclarativeTimer(QObject *parent)
+ : QObject(*(new QDeclarativeTimerPrivate), parent)
+{
+ Q_D(QDeclarativeTimer);
+ 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 QtQuick2::Timer::interval
+
+ Sets the \a interval between triggers, in milliseconds.
+
+ The default interval is 1000 milliseconds.
+*/
+void QDeclarativeTimer::setInterval(int interval)
+{
+ Q_D(QDeclarativeTimer);
+ if (interval != d->interval) {
+ d->interval = interval;
+ update();
+ emit intervalChanged();
+ }
+}
+
+int QDeclarativeTimer::interval() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->interval;
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 QDeclarativeTimer::isRunning() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->running;
+}
+
+void QDeclarativeTimer::setRunning(bool running)
+{
+ Q_D(QDeclarativeTimer);
+ if (d->running != running) {
+ d->running = running;
+ d->firstTick = true;
+ emit runningChanged();
+ update();
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 QDeclarativeTimer::isRepeating() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->repeating;
+}
+
+void QDeclarativeTimer::setRepeating(bool repeating)
+{
+ Q_D(QDeclarativeTimer);
+ if (repeating != d->repeating) {
+ d->repeating = repeating;
+ update();
+ emit repeatChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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 QDeclarativeTimer::triggeredOnStart() const
+{
+ Q_D(const QDeclarativeTimer);
+ return d->triggeredOnStart;
+}
+
+void QDeclarativeTimer::setTriggeredOnStart(bool triggeredOnStart)
+{
+ Q_D(QDeclarativeTimer);
+ if (d->triggeredOnStart != triggeredOnStart) {
+ d->triggeredOnStart = triggeredOnStart;
+ update();
+ emit triggeredOnStartChanged();
+ }
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeTimer::start()
+{
+ setRunning(true);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeTimer::stop()
+{
+ setRunning(false);
+}
+
+/*!
+ \qmlmethod QtQuick2::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 QDeclarativeTimer::restart()
+{
+ setRunning(false);
+ setRunning(true);
+}
+
+void QDeclarativeTimer::update()
+{
+ Q_D(QDeclarativeTimer);
+ 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 QDeclarativeTimer::classBegin()
+{
+ Q_D(QDeclarativeTimer);
+ d->classBegun = true;
+}
+
+void QDeclarativeTimer::componentComplete()
+{
+ Q_D(QDeclarativeTimer);
+ d->componentComplete = true;
+ update();
+}
+
+/*!
+ \qmlsignal QtQuick2::Timer::onTriggered()
+
+ This handler is called when the Timer is triggered.
+*/
+void QDeclarativeTimer::ticked()
+{
+ Q_D(QDeclarativeTimer);
+ if (d->running && (d->pause.currentTime() > 0 || (d->triggeredOnStart && d->firstTick)))
+ emit triggered();
+ d->firstTick = false;
+}
+
+void QDeclarativeTimer::finished()
+{
+ Q_D(QDeclarativeTimer);
+ if (d->repeating || !d->running)
+ return;
+ emit triggered();
+ d->running = false;
+ d->firstTick = false;
+ emit runningChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/util/qdeclarativetimer_p.h b/src/quick/util/qdeclarativetimer_p.h
new file mode 100644
index 0000000000..acf728236d
--- /dev/null
+++ b/src/quick/util/qdeclarativetimer_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVETIMER_H
+#define QDECLARATIVETIMER_H
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractanimation.h>
+
+#include <private/qtquickglobal_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeTimerPrivate;
+class Q_QUICK_PRIVATE_EXPORT QDeclarativeTimer : public QObject, public QDeclarativeParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeTimer)
+ Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating NOTIFY repeatChanged)
+ Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart NOTIFY triggeredOnStartChanged)
+ Q_PROPERTY(QObject *parent READ parent CONSTANT)
+
+public:
+ QDeclarativeTimer(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();
+ void intervalChanged();
+ void repeatChanged();
+ void triggeredOnStartChanged();
+
+private:
+ void update();
+
+private Q_SLOTS:
+ void ticked();
+ void finished();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTimer)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/quick/util/qdeclarativetransition.cpp b/src/quick/util/qdeclarativetransition.cpp
new file mode 100644
index 0000000000..916e599cc6
--- /dev/null
+++ b/src/quick/util/qdeclarativetransition.cpp
@@ -0,0 +1,392 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativetransition_p.h"
+
+#include "qdeclarativestate_p.h"
+#include "qdeclarativestate_p_p.h"
+#include "qdeclarativestateoperations_p.h"
+#include "qdeclarativeanimation_p.h"
+#include "qdeclarativeanimation_p_p.h"
+#include "qdeclarativetransitionmanager_p_p.h"
+
+#include <QParallelAnimationGroup>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass Transition QDeclarativeTransition
+ \inqmlmodule QtQuick 2
+ \ingroup qml-animation-transition
+ \brief The Transition element defines animated transitions that occur on state changes.
+
+ A Transition defines the animations to be applied when a \l State change occurs.
+
+ For example, the following \l Rectangle has two states: the default state, and
+ an added "moved" state. In the "moved state, the rectangle's position changes
+ to (50, 50). The added Transition specifies that when the rectangle
+ changes between the default and the "moved" state, any changes
+ to the \c x and \c y properties should be animated, using an \c Easing.InOutQuad.
+
+ \snippet doc/src/snippets/declarative/transition.qml 0
+
+ Notice the example does not require \l{PropertyAnimation::}{to} and
+ \l{PropertyAnimation::}{from} values for the NumberAnimation. As a convenience,
+ these properties are automatically set to the values of \c x and \c y before
+ and after the state change; the \c from values are provided by
+ the current values of \c x and \c y, and the \c to values are provided by
+ the PropertyChanges object. If you wish, you can provide \l{PropertyAnimation::}{to} and
+ \l{PropertyAnimation::}{from} values anyway to override the default values.
+
+ By default, a Transition's animations are applied for any state change in the
+ parent item. The Transition \l {Transition::}{from} and \l {Transition::}{to}
+ values can be set to restrict the animations to only be applied when changing
+ from one particular state to another.
+
+ To define multiple transitions, specify \l Item::transitions as a list:
+
+ \snippet doc/src/snippets/declarative/transitions-list.qml list of transitions
+
+ If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular
+ state change. In the example above, when changing to \c state1, the first transition will be used, rather
+ than the more generic second transition.
+
+ If a state change has a Transition that matches the same property as a
+ \l Behavior, the Transition animation overrides the \l Behavior for that
+ state change.
+
+ \sa {QML Animation and Transitions}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtDeclarative}
+*/
+
+//ParallelAnimationWrapper allows 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) {}
+ QDeclarativeTransitionPrivate *trans;
+protected:
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState);
+};
+
+class QDeclarativeTransitionPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDeclarativeTransition)
+public:
+ QDeclarativeTransitionPrivate()
+ : fromState(QLatin1String("*")), toState(QLatin1String("*")),
+ reversed(false), reversible(false), enabled(true), manager(0)
+ {
+ group.trans = this;
+ }
+
+ QString fromState;
+ QString toState;
+ bool reversed;
+ bool reversible;
+ bool enabled;
+ ParallelAnimationWrapper group;
+ QDeclarativeTransitionManager *manager;
+
+ void complete()
+ {
+ manager->complete();
+ }
+ static void append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a);
+ static int animation_count(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list);
+ static QDeclarativeAbstractAnimation* animation_at(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, int pos);
+ static void clear_animations(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list);
+ QList<QDeclarativeAbstractAnimation *> animations;
+};
+
+void QDeclarativeTransitionPrivate::append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *a)
+{
+ QDeclarativeTransition *q = static_cast<QDeclarativeTransition *>(list->object);
+ q->d_func()->animations.append(a);
+ q->d_func()->group.addAnimation(a->qtAnimation());
+ a->setDisableUserControl();
+}
+
+int QDeclarativeTransitionPrivate::animation_count(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list)
+{
+ QDeclarativeTransition *q = static_cast<QDeclarativeTransition *>(list->object);
+ return q->d_func()->animations.count();
+}
+
+QDeclarativeAbstractAnimation* QDeclarativeTransitionPrivate::animation_at(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, int pos)
+{
+ QDeclarativeTransition *q = static_cast<QDeclarativeTransition *>(list->object);
+ return q->d_func()->animations.at(pos);
+}
+
+void QDeclarativeTransitionPrivate::clear_animations(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list)
+{
+ QDeclarativeTransition *q = static_cast<QDeclarativeTransition *>(list->object);
+ while (q->d_func()->animations.count()) {
+ QDeclarativeAbstractAnimation *firstAnim = q->d_func()->animations.at(0);
+ q->d_func()->group.removeAnimation(firstAnim->qtAnimation());
+ q->d_func()->animations.removeAll(firstAnim);
+ }
+}
+
+void ParallelAnimationWrapper::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+{
+ QParallelAnimationGroup::updateState(newState, oldState);
+ if (newState == Stopped && (duration() == -1
+ || (direction() == QAbstractAnimation::Forward && currentLoopTime() == duration())
+ || (direction() == QAbstractAnimation::Backward && currentLoopTime() == 0)))
+ {
+ trans->complete();
+ }
+}
+
+
+
+QDeclarativeTransition::QDeclarativeTransition(QObject *parent)
+ : QObject(*(new QDeclarativeTransitionPrivate), parent)
+{
+}
+
+QDeclarativeTransition::~QDeclarativeTransition()
+{
+}
+
+void QDeclarativeTransition::stop()
+{
+ Q_D(QDeclarativeTransition);
+ d->group.stop();
+}
+
+void QDeclarativeTransition::setReversed(bool r)
+{
+ Q_D(QDeclarativeTransition);
+ d->reversed = r;
+}
+
+void QDeclarativeTransition::prepare(QDeclarativeStateOperation::ActionList &actions,
+ QList<QDeclarativeProperty> &after,
+ QDeclarativeTransitionManager *manager)
+{
+ Q_D(QDeclarativeTransition);
+
+ qmlExecuteDeferred(this);
+
+ if (d->reversed) {
+ for (int ii = d->animations.count() - 1; ii >= 0; --ii) {
+ d->animations.at(ii)->transition(actions, after, QDeclarativeAbstractAnimation::Backward);
+ }
+ } else {
+ for (int ii = 0; ii < d->animations.count(); ++ii) {
+ d->animations.at(ii)->transition(actions, after, QDeclarativeAbstractAnimation::Forward);
+ }
+ }
+
+ d->manager = manager;
+ d->group.setDirection(d->reversed ? QAbstractAnimation::Backward : QAbstractAnimation::Forward);
+ d->group.start();
+}
+
+/*!
+ \qmlproperty string QtQuick2::Transition::from
+ \qmlproperty string QtQuick2::Transition::to
+
+ These properties indicate the state changes that trigger the transition.
+
+ The default values for these properties is "*" (that is, any state).
+
+ For example, the following transition has not set the \c to and \c from
+ properties, so the animation is always applied when changing between
+ the two states (i.e. when the mouse is pressed and released).
+
+ \snippet doc/src/snippets/declarative/transition-from-to.qml 0
+
+ If the transition was changed to this:
+
+ \snippet doc/src/snippets/declarative/transition-from-to-modified.qml modified transition
+
+ The animation would only be applied when changing from the default state to
+ the "brighter" state (i.e. when the mouse is pressed, but not on release).
+
+ Multiple \c to and \from values can be set by using a comma-separated string.
+
+ \sa reversible
+*/
+QString QDeclarativeTransition::fromState() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->fromState;
+}
+
+void QDeclarativeTransition::setFromState(const QString &f)
+{
+ Q_D(QDeclarativeTransition);
+ if (f == d->fromState)
+ return;
+
+ d->fromState = f;
+ emit fromChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::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.
+
+ By default, transitions run in parallel and are applied to all state
+ changes if the \l from and \l to states have not been set. In this
+ situation, the transition is automatically applied when a state change
+ is reversed, and it is not necessary to set this property to reverse
+ the transition.
+
+ However, if a SequentialAnimation is used, or if the \l from or \l to
+ properties have been set, this property will need to be set to reverse
+ a transition when a state change is reverted. For example, the following
+ transition applies a sequential animation when the mouse is pressed,
+ and reverses the sequence of the animation when the mouse is released:
+
+ \snippet doc/src/snippets/declarative/transition-reversible.qml 0
+
+ If the transition did not set the \c to and \c reversible values, then
+ on the mouse release, the transition would play the PropertyAnimation
+ before the ColorAnimation instead of reversing the sequence.
+*/
+bool QDeclarativeTransition::reversible() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->reversible;
+}
+
+void QDeclarativeTransition::setReversible(bool r)
+{
+ Q_D(QDeclarativeTransition);
+ if (r == d->reversible)
+ return;
+
+ d->reversible = r;
+ emit reversibleChanged();
+}
+
+QString QDeclarativeTransition::toState() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->toState;
+}
+
+void QDeclarativeTransition::setToState(const QString &t)
+{
+ Q_D(QDeclarativeTransition);
+ if (t == d->toState)
+ return;
+
+ d->toState = t;
+ emit toChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::Transition::enabled
+
+ This property holds whether the Transition will be run when moving
+ from the \c from state to the \c to state.
+
+ By default a Transition is enabled.
+
+ Note that in some circumstances disabling a Transition may cause an
+ alternative Transition to be used in its place. In the following
+ example, the generic Transition will be used to animate the change
+ from \c state1 to \c state2, as the more specific Transition has
+ been disabled.
+
+ \qml
+ Item {
+ states: [
+ State { name: "state1" ... }
+ State { name: "state2" ... }
+ ]
+ transitions: [
+ Transition { from: "state1"; to: "state2"; enabled: false ... }
+ Transition { ... }
+ ]
+ }
+ \endqml
+*/
+
+bool QDeclarativeTransition::enabled() const
+{
+ Q_D(const QDeclarativeTransition);
+ return d->enabled;
+}
+
+void QDeclarativeTransition::setEnabled(bool enabled)
+{
+ Q_D(QDeclarativeTransition);
+ if (d->enabled == enabled)
+ return;
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty list<Animation> QtQuick2::Transition::animations
+ \default
+
+ This property holds a list of the animations to be run for this transition.
+
+ \snippet examples/declarative/toys/dynamicscene/dynamicscene.qml top-level transitions
+
+ The top-level animations are run in parallel. To run them sequentially,
+ define them within a SequentialAnimation:
+
+ \snippet doc/src/snippets/declarative/transition-reversible.qml sequential animations
+*/
+QDeclarativeListProperty<QDeclarativeAbstractAnimation> QDeclarativeTransition::animations()
+{
+ Q_D(QDeclarativeTransition);
+ return QDeclarativeListProperty<QDeclarativeAbstractAnimation>(this, &d->animations, QDeclarativeTransitionPrivate::append_animation,
+ QDeclarativeTransitionPrivate::animation_count,
+ QDeclarativeTransitionPrivate::animation_at,
+ QDeclarativeTransitionPrivate::clear_animations);
+}
+
+QT_END_NAMESPACE
+
+#include <qdeclarativetransition.moc>
diff --git a/src/quick/util/qdeclarativetransition_p.h b/src/quick/util/qdeclarativetransition_p.h
new file mode 100644
index 0000000000..439458b6af
--- /dev/null
+++ b/src/quick/util/qdeclarativetransition_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVETRANSITION_H
+#define QDECLARATIVETRANSITION_H
+
+#include "qdeclarativestate_p.h"
+
+#include <qdeclarative.h>
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeAbstractAnimation;
+class QDeclarativeTransitionPrivate;
+class QDeclarativeTransitionManager;
+class Q_QUICK_EXPORT QDeclarativeTransition : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QDeclarativeTransition)
+
+ Q_PROPERTY(QString from READ fromState WRITE setFromState NOTIFY fromChanged)
+ Q_PROPERTY(QString to READ toState WRITE setToState NOTIFY toChanged)
+ Q_PROPERTY(bool reversible READ reversible WRITE setReversible NOTIFY reversibleChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations READ animations)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_CLASSINFO("DefaultProperty", "animations")
+ Q_CLASSINFO("DeferredPropertyNames", "animations")
+
+public:
+ QDeclarativeTransition(QObject *parent=0);
+ ~QDeclarativeTransition();
+
+ QString fromState() const;
+ void setFromState(const QString &);
+
+ QString toState() const;
+ void setToState(const QString &);
+
+ bool reversible() const;
+ void setReversible(bool);
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ QDeclarativeListProperty<QDeclarativeAbstractAnimation> animations();
+
+ void prepare(QDeclarativeStateOperation::ActionList &actions,
+ QList<QDeclarativeProperty> &after,
+ QDeclarativeTransitionManager *end);
+
+ void setReversed(bool r);
+ void stop();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void reversibleChanged();
+ void enabledChanged();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeTransition)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVETRANSITION_H
diff --git a/src/quick/util/qdeclarativetransitionmanager.cpp b/src/quick/util/qdeclarativetransitionmanager.cpp
new file mode 100644
index 0000000000..2dd1da70ed
--- /dev/null
+++ b/src/quick/util/qdeclarativetransitionmanager.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativetransitionmanager_p_p.h"
+
+#include "qdeclarativetransition_p.h"
+#include "qdeclarativestate_p_p.h"
+#include "qdeclarativestate_p.h"
+
+#include <private/qdeclarativebinding_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <private/qdeclarativeproperty_p.h>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+
+class QDeclarativeTransitionManagerPrivate
+{
+public:
+ QDeclarativeTransitionManagerPrivate()
+ : state(0) {}
+
+ void applyBindings();
+ typedef QList<QDeclarativeSimpleAction> SimpleActionList;
+ QDeclarativeState *state;
+ QDeclarativeGuard<QDeclarativeTransition> transition;
+ QDeclarativeStateOperation::ActionList bindingsList;
+ SimpleActionList completeList;
+};
+
+QDeclarativeTransitionManager::QDeclarativeTransitionManager()
+: d(new QDeclarativeTransitionManagerPrivate)
+{
+}
+
+void QDeclarativeTransitionManager::setState(QDeclarativeState *s)
+{
+ d->state = s;
+}
+
+QDeclarativeTransitionManager::~QDeclarativeTransitionManager()
+{
+ delete d; d = 0;
+}
+
+void QDeclarativeTransitionManager::complete()
+{
+ d->applyBindings();
+
+ for (int ii = 0; ii < d->completeList.count(); ++ii) {
+ const QDeclarativeProperty &prop = d->completeList.at(ii).property();
+ prop.write(d->completeList.at(ii).value());
+ }
+
+ d->completeList.clear();
+
+ if (d->state)
+ static_cast<QDeclarativeStatePrivate*>(QObjectPrivate::get(d->state))->complete();
+}
+
+void QDeclarativeTransitionManagerPrivate::applyBindings()
+{
+ foreach(const QDeclarativeAction &action, bindingsList) {
+ if (!action.toBinding.isNull()) {
+ QDeclarativePropertyPrivate::setBinding(action.property, action.toBinding.data());
+ } else if (action.event) {
+ if (action.reverseEvent)
+ action.event->reverse();
+ else
+ action.event->execute();
+ }
+
+ }
+
+ bindingsList.clear();
+}
+
+void QDeclarativeTransitionManager::transition(const QList<QDeclarativeAction> &list,
+ QDeclarativeTransition *transition)
+{
+ cancel();
+
+ QDeclarativeStateOperation::ActionList applyList = list;
+ // Determine which actions are binding changes and disable any current bindings
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.toBinding)
+ d->bindingsList << action;
+ if (action.fromBinding)
+ QDeclarativePropertyPrivate::setBinding(action.property, 0); // Disable current binding
+ if (action.event && action.event->changesBindings()) { //### assume isReversable()?
+ d->bindingsList << action;
+ action.event->clearBindings();
+ }
+ }
+
+ // 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?
+ //
+ // Note that we only fast forward if both a transition and bindings are
+ // present, as it is unneccessary (and potentially expensive) otherwise.
+
+ if (transition && !d->bindingsList.isEmpty()) {
+
+ // Apply all the property and binding changes
+ for (int ii = 0; ii < applyList.size(); ++ii) {
+ const QDeclarativeAction &action = applyList.at(ii);
+ if (!action.toBinding.isNull()) {
+ QDeclarativePropertyPrivate::setBinding(action.property, action.toBinding.data(), QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ } else if (!action.event) {
+ QDeclarativePropertyPrivate::write(action.property, action.toValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ } else if (action.event->isReversable()) {
+ if (action.reverseEvent)
+ action.event->reverse(QDeclarativeActionEvent::FastForward);
+ else
+ action.event->execute(QDeclarativeActionEvent::FastForward);
+ }
+ }
+
+ // Read all the end values for binding changes
+ for (int ii = 0; ii < applyList.size(); ++ii) {
+ QDeclarativeAction *action = &applyList[ii];
+ if (action->event) {
+ action->event->saveTargetValues();
+ continue;
+ }
+ const QDeclarativeProperty &prop = action->property;
+ if (!action->toBinding.isNull() || !action->toValue.isValid()) {
+ action->toValue = prop.read();
+ }
+ }
+
+ // Revert back to the original values
+ foreach(const QDeclarativeAction &action, applyList) {
+ if (action.event) {
+ if (action.event->isReversable()) {
+ action.event->clearBindings();
+ action.event->rewind();
+ action.event->clearBindings(); //### shouldn't be needed
+ }
+ continue;
+ }
+
+ if (action.toBinding)
+ QDeclarativePropertyPrivate::setBinding(action.property, 0); // Make sure this is disabled during the transition
+
+ QDeclarativePropertyPrivate::write(action.property, action.fromValue, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding);
+ }
+ }
+
+ if (transition) {
+ QList<QDeclarativeProperty> 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 QDeclarativeAction &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 <<
+ QDeclarativeSimpleAction(action, QDeclarativeSimpleAction::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 QDeclarativeAction &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);
+ }
+ }
+#ifndef QT_NO_DEBUG_STREAM
+ if (stateChangeDebug()) {
+ foreach(const QDeclarativeAction &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;
+ }
+ }
+#endif
+ if (!transition)
+ complete();
+}
+
+void QDeclarativeTransitionManager::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) {
+ QDeclarativeAction action = d->bindingsList[i];
+ if (!action.toBinding.isNull() && action.deletableToBinding) {
+ QDeclarativePropertyPrivate::setBinding(action.property, 0);
+ action.toBinding.data()->destroy();
+ action.toBinding.clear();
+ 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/quick/util/qdeclarativetransitionmanager_p_p.h b/src/quick/util/qdeclarativetransitionmanager_p_p.h
new file mode 100644
index 0000000000..94a2dd1539
--- /dev/null
+++ b/src/quick/util/qdeclarativetransitionmanager_p_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVETRANSITIONMANAGER_P_H
+#define QDECLARATIVETRANSITIONMANAGER_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 "qdeclarativestateoperations_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeStatePrivate;
+class QDeclarativeTransitionManagerPrivate;
+class Q_AUTOTEST_EXPORT QDeclarativeTransitionManager
+{
+public:
+ QDeclarativeTransitionManager();
+ ~QDeclarativeTransitionManager();
+
+ void transition(const QList<QDeclarativeAction> &, QDeclarativeTransition *transition);
+
+ void cancel();
+
+private:
+ Q_DISABLE_COPY(QDeclarativeTransitionManager)
+ QDeclarativeTransitionManagerPrivate *d;
+
+ void complete();
+ void setState(QDeclarativeState *);
+
+ friend class QDeclarativeState;
+ friend class QDeclarativeTransitionPrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVETRANSITIONMANAGER_P_H
diff --git a/src/quick/util/qdeclarativeutilmodule.cpp b/src/quick/util/qdeclarativeutilmodule.cpp
new file mode 100644
index 0000000000..2e82364a42
--- /dev/null
+++ b/src/quick/util/qdeclarativeutilmodule.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativeutilmodule_p.h"
+#include "qdeclarativeanimation_p.h"
+#include "qdeclarativeanimation_p_p.h"
+#include "qdeclarativebehavior_p.h"
+#include "qdeclarativebind_p.h"
+#include "qdeclarativeconnections_p.h"
+#include "qdeclarativesmoothedanimation_p.h"
+#include "qdeclarativefontloader_p.h"
+#include "qdeclarativepackage_p.h"
+#include "qdeclarativepropertychanges_p.h"
+#include "qdeclarativespringanimation_p.h"
+#include "qdeclarativestategroup_p.h"
+#include "qdeclarativestateoperations_p.h"
+#include "qdeclarativestate_p.h"
+#include "qdeclarativestate_p_p.h"
+#include "qdeclarativesystempalette_p.h"
+#include "qdeclarativetimer_p.h"
+#include "qdeclarativetransition_p.h"
+#include <qdeclarativeinfo.h>
+#include <private/qdeclarativetypenotavailable_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/QInputPanel>
+
+void QDeclarativeUtilModule::defineModule()
+{
+ qmlRegisterUncreatableType<QInputPanel>("QtQuick",2,0,"InputPanel", QInputPanel::tr("InputPanel is an abstract class"));
+ qmlRegisterUncreatableType<QDeclarativeAbstractAnimation>("QtQuick",2,0,"Animation",QDeclarativeAbstractAnimation::tr("Animation is an abstract class"));
+
+ qmlRegisterType<QDeclarativeBehavior>("QtQuick",2,0,"Behavior");
+ qmlRegisterType<QDeclarativeBind>("QtQuick",2,0,"Binding");
+ qmlRegisterType<QDeclarativeColorAnimation>("QtQuick",2,0,"ColorAnimation");
+ qmlRegisterType<QDeclarativeConnections>("QtQuick",2,0,"Connections");
+ qmlRegisterType<QDeclarativeSmoothedAnimation>("QtQuick",2,0,"SmoothedAnimation");
+ qmlRegisterType<QDeclarativeFontLoader>("QtQuick",2,0,"FontLoader");
+ qmlRegisterType<QDeclarativeNumberAnimation>("QtQuick",2,0,"NumberAnimation");
+ qmlRegisterType<QDeclarativePackage>("QtQuick",2,0,"Package");
+ qmlRegisterType<QDeclarativeParallelAnimation>("QtQuick",2,0,"ParallelAnimation");
+ qmlRegisterType<QDeclarativePauseAnimation>("QtQuick",2,0,"PauseAnimation");
+ qmlRegisterType<QDeclarativePropertyAction>("QtQuick",2,0,"PropertyAction");
+ qmlRegisterType<QDeclarativePropertyAnimation>("QtQuick",2,0,"PropertyAnimation");
+ qmlRegisterType<QDeclarativeRotationAnimation>("QtQuick",2,0,"RotationAnimation");
+ qmlRegisterType<QDeclarativeScriptAction>("QtQuick",2,0,"ScriptAction");
+ qmlRegisterType<QDeclarativeSequentialAnimation>("QtQuick",2,0,"SequentialAnimation");
+ qmlRegisterType<QDeclarativeSpringAnimation>("QtQuick",2,0,"SpringAnimation");
+ qmlRegisterType<QDeclarativeStateChangeScript>("QtQuick",2,0,"StateChangeScript");
+ qmlRegisterType<QDeclarativeStateGroup>("QtQuick",2,0,"StateGroup");
+ qmlRegisterType<QDeclarativeState>("QtQuick",2,0,"State");
+ qmlRegisterType<QDeclarativeSystemPalette>("QtQuick",2,0,"SystemPalette");
+ qmlRegisterType<QDeclarativeTimer>("QtQuick",2,0,"Timer");
+ qmlRegisterType<QDeclarativeTransition>("QtQuick",2,0,"Transition");
+ qmlRegisterType<QDeclarativeVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation");
+
+ qmlRegisterType<QDeclarativeStateOperation>();
+
+ qmlRegisterCustomType<QDeclarativePropertyChanges>("QtQuick",2,0,"PropertyChanges", new QDeclarativePropertyChangesParser);
+ qmlRegisterCustomType<QDeclarativeConnections>("QtQuick",2,0,"Connections", new QDeclarativeConnectionsParser);
+}
diff --git a/src/quick/util/qdeclarativeutilmodule_p.h b/src/quick/util/qdeclarativeutilmodule_p.h
new file mode 100644
index 0000000000..13739c8170
--- /dev/null
+++ b/src/quick/util/qdeclarativeutilmodule_p.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEUTILMODULE_H
+#define QDECLARATIVEUTILMODULE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeUtilModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEUTILMODULE_H
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
new file mode 100644
index 0000000000..9c8964bfef
--- /dev/null
+++ b/src/quick/util/util.pri
@@ -0,0 +1,59 @@
+SOURCES += \
+ $$PWD/qdeclarativeutilmodule.cpp\
+ $$PWD/qdeclarativeconnections.cpp \
+ $$PWD/qdeclarativepackage.cpp \
+ $$PWD/qdeclarativeanimation.cpp \
+ $$PWD/qdeclarativesystempalette.cpp \
+ $$PWD/qdeclarativespringanimation.cpp \
+ $$PWD/qdeclarativesmoothedanimation.cpp \
+ $$PWD/qdeclarativestate.cpp\
+ $$PWD/qdeclarativetransitionmanager.cpp \
+ $$PWD/qdeclarativestateoperations.cpp \
+ $$PWD/qdeclarativepropertychanges.cpp \
+ $$PWD/qdeclarativestategroup.cpp \
+ $$PWD/qdeclarativetransition.cpp \
+ $$PWD/qdeclarativelistaccessor.cpp \
+ $$PWD/qdeclarativetimeline.cpp \
+ $$PWD/qdeclarativetimer.cpp \
+ $$PWD/qdeclarativebind.cpp \
+ $$PWD/qdeclarativepixmapcache.cpp \
+ $$PWD/qdeclarativebehavior.cpp \
+ $$PWD/qdeclarativefontloader.cpp \
+ $$PWD/qdeclarativestyledtext.cpp \
+ $$PWD/qdeclarativepath.cpp \
+ $$PWD/qdeclarativechangeset.cpp \
+ $$PWD/qdeclarativelistcompositor.cpp \
+ $$PWD/qdeclarativepathinterpolator.cpp \
+ $$PWD/qdeclarativesvgparser.cpp
+
+HEADERS += \
+ $$PWD/qdeclarativeutilmodule_p.h\
+ $$PWD/qdeclarativeconnections_p.h \
+ $$PWD/qdeclarativepackage_p.h \
+ $$PWD/qdeclarativeanimation_p.h \
+ $$PWD/qdeclarativeanimation_p_p.h \
+ $$PWD/qdeclarativesystempalette_p.h \
+ $$PWD/qdeclarativespringanimation_p.h \
+ $$PWD/qdeclarativesmoothedanimation_p.h \
+ $$PWD/qdeclarativesmoothedanimation_p_p.h \
+ $$PWD/qdeclarativestate_p.h\
+ $$PWD/qdeclarativestateoperations_p.h \
+ $$PWD/qdeclarativepropertychanges_p.h \
+ $$PWD/qdeclarativestate_p_p.h\
+ $$PWD/qdeclarativetransitionmanager_p_p.h \
+ $$PWD/qdeclarativestategroup_p.h \
+ $$PWD/qdeclarativetransition_p.h \
+ $$PWD/qdeclarativelistaccessor_p.h \
+ $$PWD/qdeclarativetimeline_p_p.h \
+ $$PWD/qdeclarativetimer_p.h \
+ $$PWD/qdeclarativebind_p.h \
+ $$PWD/qdeclarativepixmapcache_p.h \
+ $$PWD/qdeclarativebehavior_p.h \
+ $$PWD/qdeclarativefontloader_p.h \
+ $$PWD/qdeclarativestyledtext_p.h \
+ $$PWD/qdeclarativepath_p.h \
+ $$PWD/qdeclarativepath_p_p.h \
+ $$PWD/qdeclarativechangeset_p.h \
+ $$PWD/qdeclarativelistcompositor_p.h \
+ $$PWD/qdeclarativepathinterpolator_p.h \
+ $$PWD/qdeclarativesvgparser_p.h