summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/animation/animation.pri25
-rw-r--r--src/corelib/animation/qabstractanimation.cpp757
-rw-r--r--src/corelib/animation/qabstractanimation.h141
-rw-r--r--src/corelib/animation/qabstractanimation_p.h141
-rw-r--r--src/corelib/animation/qanimationgroup.cpp274
-rw-r--r--src/corelib/animation/qanimationgroup.h92
-rw-r--r--src/corelib/animation/qanimationgroup_p.h79
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp298
-rw-r--r--src/corelib/animation/qparallelanimationgroup.h90
-rw-r--r--src/corelib/animation/qparallelanimationgroup_p.h85
-rw-r--r--src/corelib/animation/qpauseanimation.cpp139
-rw-r--r--src/corelib/animation/qpauseanimation.h88
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp256
-rw-r--r--src/corelib/animation/qpropertyanimation.h94
-rw-r--r--src/corelib/animation/qpropertyanimation_p.h89
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.cpp572
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.h100
-rw-r--r--src/corelib/animation/qsequentialanimationgroup_p.h111
-rw-r--r--src/corelib/animation/qvariantanimation.cpp599
-rw-r--r--src/corelib/animation/qvariantanimation.h136
-rw-r--r--src/corelib/animation/qvariantanimation_p.h143
-rw-r--r--src/corelib/arch/qatomic_bootstrap.h14
-rw-r--r--src/corelib/corelib.pro2
-rw-r--r--src/corelib/global/qglobal.h29
-rw-r--r--src/corelib/kernel/kernel.pri18
-rw-r--r--src/corelib/kernel/qabstractitemmodel.cpp31
-rw-r--r--src/corelib/kernel/qabstractitemmodel.h3
-rw-r--r--src/corelib/kernel/qabstractitemmodel_p.h5
-rw-r--r--src/corelib/kernel/qcoreevent.h9
-rw-r--r--src/corelib/kernel/qmetaobject.cpp89
-rw-r--r--src/corelib/kernel/qmetaobject.h3
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp2438
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h269
-rw-r--r--src/corelib/kernel/qobject.cpp9
-rw-r--r--src/corelib/kernel/qobject.h11
-rw-r--r--src/corelib/kernel/qobject_p.h8
-rw-r--r--src/corelib/kernel/qobjectdefs.h4
-rw-r--r--src/corelib/kernel/qvariant_p.h34
-rw-r--r--src/corelib/statemachine/qabstractstate.cpp155
-rw-r--r--src/corelib/statemachine/qabstractstate.h57
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h64
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp281
-rw-r--r--src/corelib/statemachine/qabstracttransition.h69
-rw-r--r--src/corelib/statemachine/qabstracttransition_p.h65
-rw-r--r--src/corelib/statemachine/qactionstate.cpp385
-rw-r--r--src/corelib/statemachine/qactionstate.h85
-rw-r--r--src/corelib/statemachine/qactionstate_p.h55
-rw-r--r--src/corelib/statemachine/qanimationstate.cpp574
-rw-r--r--src/corelib/statemachine/qanimationstate.h63
-rw-r--r--src/corelib/statemachine/qboundevent_p.h52
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp263
-rw-r--r--src/corelib/statemachine/qeventtransition.h68
-rw-r--r--src/corelib/statemachine/qeventtransition_p.h48
-rw-r--r--src/corelib/statemachine/qfinalstate.cpp103
-rw-r--r--src/corelib/statemachine/qfinalstate.h50
-rw-r--r--src/corelib/statemachine/qhistorystate.cpp145
-rw-r--r--src/corelib/statemachine/qhistorystate.h56
-rw-r--r--src/corelib/statemachine/qhistorystate_p.h53
-rw-r--r--src/corelib/statemachine/qsignalevent.h45
-rw-r--r--src/corelib/statemachine/qsignaleventgenerator_p.h55
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp228
-rw-r--r--src/corelib/statemachine/qsignaltransition.h63
-rw-r--r--src/corelib/statemachine/qsignaltransition_p.h48
-rw-r--r--src/corelib/statemachine/qstate.cpp469
-rw-r--r--src/corelib/statemachine/qstate.h94
-rw-r--r--src/corelib/statemachine/qstate_p.h54
-rw-r--r--src/corelib/statemachine/qstateaction.cpp469
-rw-r--r--src/corelib/statemachine/qstateaction.h121
-rw-r--r--src/corelib/statemachine/qstateaction_p.h92
-rw-r--r--src/corelib/statemachine/qstatefinishedevent.h40
-rw-r--r--src/corelib/statemachine/qstatefinishedtransition.cpp152
-rw-r--r--src/corelib/statemachine/qstatefinishedtransition.h58
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp1847
-rw-r--r--src/corelib/statemachine/qstatemachine.h116
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h175
-rw-r--r--src/corelib/statemachine/qtransition.cpp230
-rw-r--r--src/corelib/statemachine/qtransition.h68
-rw-r--r--src/corelib/statemachine/qtransition_p.h50
-rw-r--r--src/corelib/statemachine/statemachine.pri47
-rw-r--r--src/corelib/tools/qeasingcurve.cpp844
-rw-r--r--src/corelib/tools/qeasingcurve.h114
-rw-r--r--src/corelib/tools/qtimeline.cpp114
-rw-r--r--src/corelib/tools/qtimeline.h7
-rw-r--r--src/corelib/tools/tools.pri2
84 files changed, 15465 insertions, 113 deletions
diff --git a/src/corelib/animation/animation.pri b/src/corelib/animation/animation.pri
new file mode 100644
index 0000000..cb7850c
--- /dev/null
+++ b/src/corelib/animation/animation.pri
@@ -0,0 +1,25 @@
+# Qt core animation module
+
+HEADERS += \
+ animation/qabstractanimation.h \
+ animation/qabstractanimation_p.h \
+ animation/qvariantanimation.h \
+ animation/qvariantanimation_p.h \
+ animation/qpropertyanimation.h \
+ animation/qpropertyanimation_p.h \
+ animation/qanimationgroup.h \
+ animation/qanimationgroup_p.h \
+ animation/qsequentialanimationgroup.h \
+ animation/qsequentialanimationgroup_p.h \
+ animation/qparallelanimationgroup.h \
+ animation/qparallelanimationgroup_p.h \
+ animation/qpauseanimation.h
+
+SOURCES += \
+ animation/qabstractanimation.cpp \
+ animation/qvariantanimation.cpp \
+ animation/qpropertyanimation.cpp \
+ animation/qanimationgroup.cpp \
+ animation/qsequentialanimationgroup.cpp \
+ animation/qparallelanimationgroup.cpp \
+ animation/qpauseanimation.cpp
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
new file mode 100644
index 0000000..08dc11c
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -0,0 +1,757 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QAbstractAnimation
+ \ingroup animation
+ \brief The QAbstractAnimation class provides an abstract base class for animations.
+ \since 4.5
+ \preliminary
+
+ This class is part of \l{The Animation Framework}. It serves as a base class
+ for standard animations and groups, with functions for shared
+ functionality, and it also makes it easy for you to define custom
+ animations that plug into the rest of the animation framework.
+
+ If you want to create an animation, you should look at the two subclasses,
+ QVariantAnimation and QAnimationGroup, instead.
+
+ QAbstractAnimation provides an interface for the current time and
+ duration, the iteration count, and the state of an animation. These properties
+ define the base functionality common to all animations in Qt. The virtual
+ duration() function returns the local duration of the animation; i.e., for
+ how long the animation should update the current time before
+ looping. Subclasses can implement this function differently; for example,
+ QVariantAnimation returns the duration of a simple animated property, whereas
+ QAnimationGroup returns the duration of a set or sequence of
+ animations. You can also set a loop count by calling setIterationCount(); a
+ iteration count of 2 will let the animation run twice (the default value is
+ 1).
+
+ Like QTimeLine, QAbstractAnimation also provides an interface for starting
+ and stopping an animation, and for tracking its progress. You can call the
+ start() slot to start the animation. When the animation starts, the
+ stateChanged() signal is emitted, and state() returns Running. If you call the
+ stop() slot, the stateChanged() signal is emitted, and state() returns
+ Stopped. If you call the pause() slot, the stateChanged() signal is emitted
+ and state() returns Paused. If the animation reaches the end, the finished()
+ signal is emitted. You can check the current state by calling state().
+
+ QAbstractAnimation provides two functions that are pure virtual, and must
+ be reimplemented in a subclass: duration(), and updateCurrentTime(). The
+ duration() function lets you report a duration for the animation (a return
+ value of -1 signals that the animation runs forever until explicitly
+ stopped). The current time is delivered by the framework through calls to
+ updateCurrentTime(). By reimplementing this function, you can track the
+ animation progress and update your target objects accordingly. By
+ reimplementing updateState(), you can track the animation's state
+ changes, which is particularily useful for animations that are not driven
+ by time.
+
+ \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
+*/
+
+/*!
+ \enum QAbstractAnimation::DeletionPolicy
+
+ \value KeepWhenStopped The animation will not be deleted when stopped.
+ \value DeleteWhenStopped The animation will be automatically deleted when
+ stopped.
+*/
+
+/*!
+ \fn QAbstractAnimation::finished()
+
+ QAbstractAnimation emits this signal after the animation has stopped and
+ has reached the end.
+
+ This signal is emitted after stateChanged().
+
+ \sa stateChanged()
+*/
+
+/*!
+ \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState)
+
+ QAbstractAnimation emits this signal whenever the state of the animation has
+ changed from \a oldState to \a newState. This signal is emitted after the virtual
+ updateState() function is called.
+
+ \sa updateState()
+*/
+
+/*!
+ \fn QAbstractAnimation::currentIterationChanged(int currentIteration)
+
+ QAbstractAnimation emits this signal whenever the current iteration
+ changes. \a currentIteration is the current iteration.
+
+ \sa currentIteration(), iterationCount()
+*/
+
+/*!
+ \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection);
+
+ QAbstractAnimation emits this signal whenever the direction has been
+ changed. \a newDirection is the new direction.
+
+ \sa direction
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qabstractanimation.h"
+#include "qanimationgroup.h"
+#include <QtCore/qdebug.h>
+
+#include "qabstractanimation_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qthreadstorage.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qpointer.h>
+
+#define TIMER_INTERVAL 5
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer);
+
+QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), consistentTiming(false)
+{
+}
+
+QUnifiedTimer *QUnifiedTimer::instance()
+{
+ QUnifiedTimer *inst;
+ if (!unifiedTimer()->hasLocalData()) {
+ inst = new QUnifiedTimer;
+ unifiedTimer()->setLocalData(inst);
+ } else {
+ inst = unifiedTimer()->localData();
+ }
+ return inst;
+}
+
+void QUnifiedTimer::updateRecentlyStartedAnimations()
+{
+ if (animationsToStart.isEmpty())
+ return;
+
+ animations += animationsToStart;
+ updateTimer(); //we make sure we start the timer there
+
+ animationsToStart.clear();
+}
+
+void QUnifiedTimer::setConsistentTiming(bool c)
+{
+ consistentTiming = c;
+}
+
+int QUnifiedTimer::elapsedTime()
+{
+ return lastTick;
+}
+
+void QUnifiedTimer::timerEvent(QTimerEvent *event)
+{
+ //this is simply the time we last received a tick
+ int oldLastTick = lastTick;
+ if (time.isValid())
+ lastTick = consistentTiming ? oldLastTick + 5 : time.elapsed();
+
+ //we transfer the waiting animations into the "really running" state
+ updateRecentlyStartedAnimations();
+
+ if (event->timerId() == startStopAnimationTimer.timerId()) {
+ startStopAnimationTimer.stop();
+ if (animations.isEmpty()) {
+ animationTimer.stop();
+ time = QTime();
+ } else {
+ animationTimer.start(TIMER_INTERVAL, this);
+ lastTick = 0;
+ time.start();
+ }
+ } else if (event->timerId() == animationTimer.timerId()) {
+ const int delta = lastTick - oldLastTick;
+ for (int i = 0; i < animations.count(); ++i) {
+ QAbstractAnimation *animation = animations.at(i);
+ int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
+ + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
+ animation->setCurrentTime(elapsed);
+ }
+ }
+}
+
+void QUnifiedTimer::updateTimer()
+{
+ //we delay the call to start and stop for the animation timer so that if you
+ //stop and start animations in batch you don't stop/start the timer too often.
+ if (!startStopAnimationTimer.isActive())
+ startStopAnimationTimer.start(0, this); // we delay the actual start of the animation
+}
+
+void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation)
+{
+ if (animations.contains(animation) ||animationsToStart.contains(animation))
+ return;
+ animationsToStart << animation;
+ updateTimer();
+}
+
+void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
+{
+ animations.removeAll(animation);
+ animationsToStart.removeAll(animation);
+ updateTimer();
+}
+
+
+void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
+{
+ Q_Q(QAbstractAnimation);
+ if (state == newState)
+ return;
+
+ QAbstractAnimation::State oldState = state;
+ int oldCurrentTime = currentTime;
+ int oldCurrentIteration = currentIteration;
+ QAbstractAnimation::Direction oldDirection = direction;
+
+ state = newState;
+
+ QPointer<QAbstractAnimation> guard(q);
+
+ guard->updateState(oldState, newState);
+
+ //this is to be safe if updateState changes the state
+ if (state == oldState)
+ return;
+
+ // Notify state change
+ if (guard)
+ emit guard->stateChanged(oldState, newState);
+
+ // Enter running state.
+ switch (state)
+ {
+ case QAbstractAnimation::Paused:
+ case QAbstractAnimation::Running:
+ {
+ // Rewind
+ if (oldState == QAbstractAnimation::Stopped) {
+ if (guard) {
+ if (direction == QAbstractAnimation::Forward)
+ q->setCurrentTime(0);
+ else
+ q->setCurrentTime(iterationCount == -1 ? q->duration() : q->totalDuration());
+ }
+
+ // Check if the setCurrentTime() function called stop().
+ // This can happen for a 0-duration animation
+ if (state == QAbstractAnimation::Stopped)
+ return;
+ }
+
+ // Register timer if our parent is not running.
+ if (state == QAbstractAnimation::Running && guard) {
+ if (!group || group->state() == QAbstractAnimation::Stopped) {
+ QUnifiedTimer::instance()->registerAnimation(q);
+ }
+ } else {
+ //new state is paused
+ QUnifiedTimer::instance()->unregisterAnimation(q);
+ }
+ }
+ break;
+ case QAbstractAnimation::Stopped:
+ // Leave running state.
+ int dura = q->duration();
+ if (deleteWhenStopped && guard)
+ q->deleteLater();
+
+ QUnifiedTimer::instance()->unregisterAnimation(q);
+
+ if (dura == -1 || iterationCount < 0
+ || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentIteration + 1)) == (dura * iterationCount))
+ || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
+ if (guard)
+ emit q->finished();
+ }
+ break;
+ }
+
+}
+
+/*!
+ Constructs the QAbstractAnimation base class, and passes \a parent to
+ QObject's constructor.
+
+ \sa QVariantAnimation, QAnimationGroup
+*/
+#ifdef QT_EXPERIMENTAL_SOLUTION
+QAbstractAnimation::QAbstractAnimation(QObject *parent)
+ : d_ptr(new QAbstractAnimationPrivate)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+ d_ptr->q_ptr = this;
+}
+#else
+QAbstractAnimation::QAbstractAnimation(QObject *parent)
+ : QObject(*new QAbstractAnimationPrivate, 0)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+}
+#endif
+
+/*!
+ \internal
+*/
+#ifdef QT_EXPERIMENTAL_SOLUTION
+QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
+ : d_ptr(&dd)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+ d_ptr->q_ptr = this;
+}
+#else
+QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
+ : QObject(dd, 0)
+{
+ // Allow auto-add on reparent
+ setParent(parent);
+}
+#endif
+
+/*!
+ Stops the animation if it's running, then destroys the
+ QAbstractAnimation. If the animation is part of a QAnimationGroup, it is
+ automatically removed before it's destroyed.
+*/
+QAbstractAnimation::~QAbstractAnimation()
+{
+ Q_D(QAbstractAnimation);
+ //we can't call stop here. Otherwise we get pure virtual calls
+ if (d->state != Stopped) {
+ QAbstractAnimation::State oldState = d->state;
+ d->state = Stopped;
+ emit stateChanged(oldState, d->state);
+ QUnifiedTimer::instance()->unregisterAnimation(this);
+ }
+}
+
+/*!
+ \property QAbstractAnimation::state
+ \brief state of the animation.
+
+ This property describes the current state of the animation. When the
+ animation state changes, QAbstractAnimation emits the stateChanged()
+ signal.
+*/
+QAbstractAnimation::State QAbstractAnimation::state() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->state;
+}
+
+/*!
+ If this animation is part of a QAnimationGroup, this function returns a
+ pointer to the group; otherwise, it returns 0.
+
+ \sa QAnimationGroup::addAnimation()
+*/
+QAnimationGroup *QAbstractAnimation::group() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->group;
+}
+
+/*!
+ \enum QAbstractAnimation::State
+
+ This enum describes the state of the animation.
+
+ \value Stopped The animation is not running. This is the initial state
+ of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current
+ time remain unchanged until either setCurrentTime() is
+ called, or the animation is started by calling start().
+
+ \value Paused The animation is paused (i.e., temporarily
+ suspended). Calling resume() will resume animation activity.
+
+ \value Running The animation is running. While control is in the event
+ loop, QAbstractAnimation will update its current time at regular intervals,
+ calling updateCurrentTime() when appropriate.
+
+ \sa state(), stateChanged()
+*/
+
+/*!
+ \enum QAbstractAnimation::Direction
+
+ This enum describes the direction of the animation when in \l Running state.
+
+ \value Forward The current time of the animation increases with time (i.e.,
+ moves from 0 and towards the end / duration).
+
+ \value Backward The current time of the animation decreases with time (i.e.,
+ moves from the end / duration and towards 0).
+
+ \sa direction
+*/
+
+/*!
+ \property QAbstractAnimation::direction
+ \brief the direction of the animation when it is in \l Running
+ state.
+
+ This direction indicates whether the time moves from 0 towards the
+ animation duration, or from the value of the duration and towards 0 after
+ start() has been called.
+
+ By default, this property is set to \l Forward.
+*/
+QAbstractAnimation::Direction QAbstractAnimation::direction() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->direction;
+}
+void QAbstractAnimation::setDirection(Direction direction)
+{
+ Q_D(QAbstractAnimation);
+ if (d->direction == direction)
+ return;
+
+ d->direction = direction;
+ if (state() == Stopped) {
+ if (direction == Backward) {
+ d->currentTime = duration();
+ d->currentIteration = d->iterationCount - 1;
+ } else {
+ d->currentTime = 0;
+ d->currentIteration = 0;
+ }
+ }
+ updateDirection(direction);
+ emit directionChanged(direction);
+}
+
+/*!
+ \property QAbstractAnimation::duration
+ \brief the duration of the animation.
+
+ If the duration is -1, it means that the duration is undefined.
+ In this case, iterationCount is ignored.
+*/
+
+/*!
+ \property QAbstractAnimation::iterationCount
+ \brief the iteration count of the animation
+
+ This property describes the iteration count of the animation as an integer.
+ By default this value is 1, indicating that the animation
+ should run once only, and then stop. By changing it you can let the
+ animation loop several times. With a value of 0, the animation will not
+ run at all, and with a value of -1, the animation will loop forever
+ until stopped.
+ It is not supported to have loop on an animation that has an undefined
+ duration. It will only run once.
+*/
+int QAbstractAnimation::iterationCount() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->iterationCount;
+}
+void QAbstractAnimation::setIterationCount(int iterationCount)
+{
+ Q_D(QAbstractAnimation);
+ d->iterationCount = iterationCount;
+}
+
+/*!
+ \property QAbstractAnimation::currentIteration
+ \brief the current iteration of the animation
+
+ This property describes the current iteration of the animation. By default,
+ the animation's iteration count is 1, and so the current iteration will
+ always be 0. If the iteration count is 2 and the animation runs past its
+ duration, it will automatically rewind and restart at current time 0, and
+ current iteration 1, and so on.
+
+ When the current iteration changes, QAbstractAnimation emits the
+ currentIterationChanged() signal.
+*/
+int QAbstractAnimation::currentIteration() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->currentIteration;
+}
+
+/*!
+ \fn virtual int QAbstractAnimation::duration() const = 0
+
+ This pure virtual function returns the duration of the animation, and
+ defines for how long QAbstractAnimation should update the current
+ time. This duration is local, and does not include the iteration count.
+
+ A return value of -1 indicates that the animation has no defined duration;
+ the animation should run forever until stopped. This is useful for
+ animations that are not time driven, or where you cannot easily predict
+ its duration (e.g., event driven audio playback in a game).
+
+ If the animation is a parallel QAnimationGroup, the duration will be the longest
+ duration of all its animations. If the animation is a sequential QAnimationGroup,
+ the duration will be the sum of the duration of all its animations.
+ \sa iterationCount
+*/
+
+/*!
+ Returns the total and effective duration of the animation, including the
+ iteration count.
+
+ \sa duration(), currentTime
+*/
+int QAbstractAnimation::totalDuration() const
+{
+ Q_D(const QAbstractAnimation);
+ if (d->iterationCount < 0)
+ return -1;
+ int dura = duration();
+ if (dura == -1)
+ return -1;
+ return dura * d->iterationCount;
+}
+
+/*!
+ \property QAbstractAnimation::currentTime
+ \brief the current time and progress of the animation
+
+ This property describes the animation's current time. You can change the
+ current time by calling setCurrentTime, or you can call start() and let
+ the animation run, setting the current time automatically as the animation
+ progresses.
+
+ The animation's current time starts at 0, and ends at duration(). If the
+ animation's iterationCount is larger than 1, the current time will rewind and
+ start at 0 again for the consecutive loops. If the animation has a pause.
+ currentTime will also include the duration of the pause.
+
+ \sa iterationCount
+ */
+int QAbstractAnimation::currentTime() const
+{
+ Q_D(const QAbstractAnimation);
+ return d->currentTime;
+}
+void QAbstractAnimation::setCurrentTime(int msecs)
+{
+ Q_D(QAbstractAnimation);
+ msecs = qMax(msecs, 0);
+
+ // Calculate new time and loop.
+ int dura = duration();
+ int totalDura = (d->iterationCount < 0 || dura == -1) ? -1 : dura * d->iterationCount;
+ if (totalDura != -1)
+ msecs = qMin(totalDura, msecs);
+ d->totalCurrentTime = msecs;
+
+ // Update new values.
+ int oldLoop = d->currentIteration;
+ d->currentIteration = ((dura <= 0) ? 0 : (msecs / dura));
+ if (d->currentIteration == d->iterationCount) {
+ //we're at the end
+ d->currentTime = qMax(0, dura);
+ d->currentIteration = qMax(0, d->iterationCount - 1);
+ } else {
+ if (d->direction == Forward) {
+ d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ } else {
+ d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
+ if (d->currentTime == dura)
+ --d->currentIteration;
+ }
+ }
+
+ updateCurrentTime(msecs);
+ if (d->currentIteration != oldLoop)
+ emit currentIterationChanged(d->currentIteration);
+
+ // All animations are responsible for stopping the animation when their
+ // own end state is reached; in this case the animation is time driven,
+ // and has reached the end.
+ if ((d->direction == Forward && d->totalCurrentTime == totalDura)
+ || (d->direction == Backward && d->totalCurrentTime == 0)) {
+ stop();
+ }
+}
+
+/*!
+ Starts the animation. The \a policy argument says whether or not the
+ animation should be deleted when it's done. When the animation starts, the
+ stateChanged() signal is emitted, and state() returns Running. When control
+ reaches the event loop, the animation will run by itself, periodically
+ calling updateCurrentTime() as the animation progresses.
+
+ If the animation is currently stopped or has already reached the end,
+ calling start() will rewind the animation and start again from the beginning.
+ When the animation reaches the end, the animation will either stop, or
+ if the loop level is more than 1, it will rewind and continue from the beginning.
+
+ If the animation is already running, this function does nothing.
+
+ \sa stop(), state()
+*/
+void QAbstractAnimation::start(DeletionPolicy policy)
+{
+ Q_D(QAbstractAnimation);
+ if (d->state == Running)
+ return;
+ d->setState(Running);
+ d->deleteWhenStopped = policy;
+}
+
+/*!
+ Stops the animation. When the animation is stopped, it emits the stateChanged()
+ signal, and state() returns Stopped. The current time is not changed.
+
+ If the animation stops by itself after reaching the end (i.e.,
+ currentTime() == duration() and currentIteration() > iterationCount() - 1), the
+ finished() signal is emitted.
+
+ \sa start(), state()
+ */
+void QAbstractAnimation::stop()
+{
+ Q_D(QAbstractAnimation);
+
+ d->setState(Stopped);
+}
+
+/*!
+ Pauses the animation. When the animation is paused, state() returns Paused.
+ The currenttime will remain unchanged until resume() or start() is called.
+ If you want to continue from the current time, call resume().
+
+
+ \sa start(), state(), resume()
+ */
+void QAbstractAnimation::pause()
+{
+ Q_D(QAbstractAnimation);
+ if (d->state == Stopped) {
+ qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
+ return;
+ }
+
+ d->setState(Paused);
+}
+
+/*!
+ Resumes the animation after it was paused. When the animation is resumed,
+ it emits the resumed() and stateChanged() signals. The currenttime is not
+ changed.
+
+ \sa start(), pause(), state()
+ */
+void QAbstractAnimation::resume()
+{
+ Q_D(QAbstractAnimation);
+ if (d->state != Paused) {
+ qWarning("QAbstractAnimation::resume: "
+ "Cannot resume an animation that is not paused");
+ return;
+ }
+
+ d->setState(Running);
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractAnimation::event(QEvent *event)
+{
+ return QObject::event(event);
+}
+
+/*!
+ \fn virtual void QAbstractAnimation::updateCurrentTime(int msecs) = 0;
+
+ This pure virtual function is called every time the animation's current
+ time changes. The \a msecs argument is the current time.
+
+ \sa updateState()
+*/
+
+/*!
+ This virtual function is called by QAbstractAnimation when the state
+ of the animation is changed from \a oldState to \a newState.
+
+ \sa start(), stop(), pause(), resume()
+*/
+void QAbstractAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+}
+
+/*!
+ This virtual function is called by QAbstractAnimation when the direction
+ of the animation is changed. The \a direction argument is the new direction.
+
+ \sa setDirection(), direction()
+*/
+void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_UNUSED(direction);
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h
new file mode 100644
index 0000000..d6260cd
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATION_H
+#define QABSTRACTANIMATION_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QAnimationGroup;
+class QSequentialAnimationGroup;
+
+class QAbstractAnimationPrivate;
+class Q_CORE_EXPORT QAbstractAnimation : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(int iterationCount READ iterationCount WRITE setIterationCount)
+ Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime)
+ Q_PROPERTY(int currentIteration READ currentIteration NOTIFY currentIterationChanged)
+ Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged)
+ Q_PROPERTY(int duration READ duration)
+
+public:
+ enum Direction {
+ Forward,
+ Backward
+ };
+
+ enum State {
+ Stopped,
+ Paused,
+ Running
+ };
+
+ enum DeletionPolicy {
+ KeepWhenStopped = 0,
+ DeleteWhenStopped
+ };
+
+ QAbstractAnimation(QObject *parent = 0);
+ virtual ~QAbstractAnimation();
+
+ State state() const;
+
+ QAnimationGroup *group() const;
+
+ Direction direction() const;
+ void setDirection(Direction direction);
+
+ int iterationCount() const;
+ void setIterationCount(int iterationCount);
+ int currentIteration() const;
+
+ virtual int duration() const = 0;
+ int totalDuration() const;
+
+ int currentTime() const;
+
+Q_SIGNALS:
+ void finished();
+ void stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void currentIterationChanged(int currentIteration);
+ void directionChanged(QAbstractAnimation::Direction);
+
+public Q_SLOTS:
+ void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped);
+ void pause();
+ void resume();
+ void stop();
+ void setCurrentTime(int msecs);
+
+protected:
+ QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0);
+ bool event(QEvent *event);
+
+ virtual void updateCurrentTime(int msecs) = 0;
+ virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ virtual void updateDirection(QAbstractAnimation::Direction direction);
+
+#ifdef QT_EXPERIMENTAL_SOLUTION
+ QAbstractAnimationPrivate *d_ptr;
+#endif
+
+private:
+ Q_DISABLE_COPY(QAbstractAnimation)
+ Q_DECLARE_PRIVATE(QAbstractAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTANIMATION_H
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
new file mode 100644
index 0000000..39cca56
--- /dev/null
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTANIMATION_P_H
+#define QABSTRACTANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qtimer.h>
+#ifndef QT_EXPERIMENTAL_SOLUTION
+#include <private/qobject_p.h>
+#include <qabstractanimation.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QAnimationGroup;
+class QAbstractAnimation;
+#ifdef QT_EXPERIMENTAL_SOLUTION
+class QAbstractAnimationPrivate
+#else
+class QAbstractAnimationPrivate : public QObjectPrivate
+#endif
+{
+public:
+ QAbstractAnimationPrivate()
+ : state(QAbstractAnimation::Stopped),
+ direction(QAbstractAnimation::Forward),
+ deleteWhenStopped(false),
+ totalCurrentTime(0),
+ currentTime(0),
+ iterationCount(1),
+ currentIteration(0),
+ group(0)
+ {
+ }
+
+ virtual ~QAbstractAnimationPrivate() {}
+
+ static QAbstractAnimationPrivate *get(QAbstractAnimation *q)
+ {
+ return q->d_func();
+ }
+
+ QAbstractAnimation::State state;
+ QAbstractAnimation::Direction direction;
+ bool deleteWhenStopped;
+ void setState(QAbstractAnimation::State state);
+
+ int totalCurrentTime;
+ int currentTime;
+ int iterationCount;
+ int currentIteration;
+
+ QAnimationGroup *group;
+#ifdef QT_EXPERIMENTAL_SOLUTION
+ QAbstractAnimation *q_ptr;
+#endif
+
+private:
+ Q_DECLARE_PUBLIC(QAbstractAnimation)
+};
+
+
+class Q_CORE_EXPORT QUnifiedTimer : public QObject
+{
+private:
+ QUnifiedTimer();
+
+public:
+ static QUnifiedTimer *instance();
+
+ void timerEvent(QTimerEvent *);
+ void updateTimer();
+ void registerAnimation(QAbstractAnimation *animation);
+ void unregisterAnimation(QAbstractAnimation *animation);
+
+ void setConsistentTiming(bool c);
+ int elapsedTime();
+
+private:
+ void updateRecentlyStartedAnimations();
+
+ QBasicTimer animationTimer, startStopAnimationTimer;
+ QTime time;
+ int lastTick;
+ bool consistentTiming;
+ QList<QAbstractAnimation*> animations, animationsToStart;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp
new file mode 100644
index 0000000..f39738b
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QAnimationGroup
+ \brief The QAnimationGroup is an abstract base class for group of animations.
+ \since 4.5
+ \ingroup animation
+ \preliminary
+
+ QAnimationGroup represents a group of animations, such as parallel or sequential,
+ and lets you combine different animations into one. The group manages any animation
+ that inherits QAbstractAnimation. By combining groups, you can easily construct
+ complex animation graphs.
+
+ The QAnimationGroup base class provides methods for adding and retrieving animations.
+ Besides that, you can remove animations by calling remove(), and clear the animation
+ group by calling clearAnimations(). You may keep track of changes in the group's animations by
+ listening to QEvent::ChildAdded and QEvent::ChildRemoved events.
+
+ QAnimationGroup takes ownership of the animations it manages, and ensures that they are
+ deleted when the animation group is deleted.
+
+ \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework}
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qanimationgroup.h"
+#include <QtCore/qdebug.h>
+#include <QtCore/qcoreevent.h>
+#include "qanimationgroup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Constructs a QAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QAnimationGroup::QAnimationGroup(QObject *parent)
+ : QAbstractAnimation(*new QAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent)
+ : QAbstractAnimation(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QAnimationGroup::~QAnimationGroup()
+{
+}
+
+/*!
+ Returns a pointer to the animation at \a index in this group. This
+ function is useful when you need access to a particular animation. \a
+ index is between 0 and animationCount() - 1.
+
+ \sa animationCount(), indexOfAnimation()
+*/
+QAbstractAnimation *QAnimationGroup::animationAt(int index) const
+{
+ Q_D(const QAnimationGroup);
+
+ if (index < 0 || index >= d->animations.size()) {
+ qWarning("QAnimationGroup::animationAt: index is out of bounds");
+ return 0;
+ }
+
+ return d->animations.at(index);
+}
+
+
+/*!
+ Returns the number of animations managed by this group.
+
+ \sa indexOfAnimation(), addAnimation(), animationAt()
+*/
+int QAnimationGroup::animationCount() const
+{
+ Q_D(const QAnimationGroup);
+ return d->animations.size();
+}
+
+/*!
+ Returns the index of \a animation. The returned index can be passed
+ to the other functions that take an index as an argument.
+
+ \sa insertAnimationAt() animationAt(), takeAnimationAt()
+*/
+int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const
+{
+ Q_D(const QAnimationGroup);
+ return d->animations.indexOf(animation);
+}
+
+/*!
+ Adds \a animation to this group. This will call insertAnimationAt with
+ index equals to animationCount()
+*/
+void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+ insertAnimationAt(d->animations.count(), animation);
+}
+
+/*!
+ Inserts \a animation into this animation group at \a index.
+ If \a index is 0 the animation is inserted at the beginning.
+ If \a index is animationCount(), the animation is inserted at the end.
+ \sa takeAnimationAt(), addAnimation(), indexOfAnimation()
+*/
+void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+
+ if (index < 0 || index > d->animations.size()) {
+ qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds");
+ return;
+ }
+
+ d->animations.insert(index, animation);
+ if (QAnimationGroup *oldGroup = animation->group())
+ oldGroup->removeAnimation(animation);
+ QAbstractAnimationPrivate::get(animation)->group = this;
+ // this will make sure that ChildAdded event is sent to 'this'
+ animation->setParent(this);
+ d->animationInsertedAt(index);
+}
+
+/*!
+ Removes \a animation from this group. The ownership of \a animation is
+ transferred to the caller.
+
+ \sa takeAnimationAt(), insertAnimationAt(), addAnimation()
+*/
+void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationGroup);
+
+ if (!animation) {
+ qWarning("QAnimationGroup::remove: cannot remove null animation");
+ return;
+ }
+ int index = d->animations.indexOf(animation);
+ if (index == -1) {
+ qWarning("QAnimationGroup::remove: animation is not part of this group");
+ return;
+ }
+
+ takeAnimationAt(index);
+}
+
+/*!
+ Removes the animation at \a index from this animation group. The ownership
+ of the animation is transferred to the caller, and a pointer to the removed
+ animation is returned.
+
+ \sa addAnimation()
+*/
+QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index)
+{
+ Q_D(QAnimationGroup);
+ if (index < 0 || index >= d->animations.size()) {
+ qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index);
+ return 0;
+ }
+ QAbstractAnimation *animation = d->animations.at(index);
+ QAbstractAnimationPrivate::get(animation)->group = 0;
+ // ### removing from list before doing setParent to avoid inifinite recursion
+ // in ChildRemoved event
+ d->animations.removeAt(index);
+ animation->setParent(0);
+ d->animationRemovedAt(index);
+ return animation;
+}
+
+/*!
+ Removes and deletes all animations in this animation group, and resets the current
+ time to 0.
+
+ \sa addAnimation(), removeAnimation()
+*/
+void QAnimationGroup::clearAnimations()
+{
+ Q_D(QAnimationGroup);
+ qDeleteAll(d->animations);
+}
+
+/*!
+ \reimp
+*/
+bool QAnimationGroup::event(QEvent *event)
+{
+ Q_D(QAnimationGroup);
+ if (event->type() == QEvent::ChildAdded) {
+ QChildEvent *childEvent = static_cast<QChildEvent *>(event);
+ if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
+ if (a->group() != this)
+ addAnimation(a);
+ }
+ } else if (event->type() == QEvent::ChildRemoved) {
+ QChildEvent *childEvent = static_cast<QChildEvent *>(event);
+ QAbstractAnimation *a = static_cast<QAbstractAnimation *>(childEvent->child());
+ // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
+ // case it might be called from the destructor.
+ int index = d->animations.indexOf(a);
+ if (index != -1)
+ takeAnimationAt(index);
+ }
+ return QAbstractAnimation::event(event);
+}
+
+
+void QAnimationGroupPrivate::animationRemovedAt(int index)
+{
+ Q_Q(QAnimationGroup);
+ Q_UNUSED(index);
+ if (animations.isEmpty()) {
+ currentTime = 0;
+ q->stop();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h
new file mode 100644
index 0000000..7dee070
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUP_H
+#define QANIMATIONGROUP_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qabstractanimation.h"
+#else
+# include <QtCore/qabstractanimation.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QAnimationGroupPrivate;
+class Q_CORE_EXPORT QAnimationGroup : public QAbstractAnimation
+{
+ Q_OBJECT
+
+public:
+ QAnimationGroup(QObject *parent = 0);
+ ~QAnimationGroup();
+
+ QAbstractAnimation *animationAt(int index) const;
+ int animationCount() const;
+ int indexOfAnimation(QAbstractAnimation *animation) const;
+ void addAnimation(QAbstractAnimation *animation);
+ void insertAnimationAt(int index, QAbstractAnimation *animation);
+ void removeAnimation(QAbstractAnimation *animation);
+ QAbstractAnimation *takeAnimationAt(int index);
+ void clearAnimations();
+
+protected:
+ QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+private:
+ Q_DISABLE_COPY(QAnimationGroup)
+ Q_DECLARE_PRIVATE(QAnimationGroup)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATIONGROUP_H
diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h
new file mode 100644
index 0000000..a7bd0fa
--- /dev/null
+++ b/src/corelib/animation/qanimationgroup_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONGROUP_P_H
+#define QANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qanimationgroup.h"
+
+#include <QtCore/qlist.h>
+
+#include "qabstractanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAnimationGroupPrivate : public QAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QAnimationGroup)
+public:
+ QAnimationGroupPrivate()
+ { }
+
+ virtual void animationInsertedAt(int index) { Q_UNUSED(index) };
+ virtual void animationRemovedAt(int index);
+
+ QList<QAbstractAnimation *> animations;
+};
+
+QT_END_NAMESPACE
+
+#endif //QANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
new file mode 100644
index 0000000..993c577
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QParallelAnimationGroup
+ \brief The QParallelAnimationGroup class provides a parallel group of animations.
+ \since 4.5
+ \ingroup animation
+ \preliminary
+
+ The animations are all started at the same time, and run in parallel. The animation group
+ finishes when the longest lasting animation has finished.
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qparallelanimationgroup.h"
+#include "qparallelanimationgroup_p.h"
+//#define QANIMATION_DEBUG
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs a QParallelAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
+ : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd,
+ QObject *parent)
+ : QAnimationGroup(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QParallelAnimationGroup::~QParallelAnimationGroup()
+{
+}
+
+/*!
+ \reimp
+*/
+int QParallelAnimationGroup::duration() const
+{
+ Q_D(const QParallelAnimationGroup);
+ int ret = 0;
+
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int currentDuration = animation->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret = qMax(ret, currentDuration);
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateCurrentTime(int)
+{
+ Q_D(QParallelAnimationGroup);
+ if (d->animations.isEmpty())
+ return;
+
+ if (d->currentIteration > d->lastIteration) {
+ // simulate completion of the loop
+ int dura = duration();
+ if (dura > 0) {
+ foreach (QAbstractAnimation *animation, d->animations) {
+ animation->setCurrentTime(dura); // will stop
+ }
+ }
+ } else if (d->currentIteration < d->lastIteration) {
+ // simulate completion of the loop seeking backwards
+ foreach (QAbstractAnimation *animation, d->animations) {
+ animation->setCurrentTime(0);
+ animation->stop();
+ }
+ }
+
+ bool timeFwd = ((d->currentIteration == d->lastIteration && d->currentTime >= d->lastCurrentTime)
+ || d->currentIteration > d->lastIteration);
+#ifdef QANIMATION_DEBUG
+ qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d",
+ __LINE__, d->currentTime, d->currentIteration, d->lastIteration, timeFwd, d->lastCurrentTime, state());
+#endif
+ // finally move into the actual time of the current loop
+ foreach (QAbstractAnimation *animation, d->animations) {
+ const int dura = animation->totalDuration();
+ if (dura == -1 && d->isUncontrolledAnimationFinished(animation))
+ continue;
+ if (dura == -1 || (d->currentTime <= dura && dura != 0)
+ || (dura == 0 && d->currentIteration != d->lastIteration)) {
+ switch (state()) {
+ case Running:
+ animation->start();
+ break;
+ case Paused:
+ animation->pause();
+ break;
+ case Stopped:
+ default:
+ break;
+ }
+ }
+
+ if (dura <= 0) {
+ if (dura == -1)
+ animation->setCurrentTime(d->currentTime);
+ continue;
+ }
+
+ if ((timeFwd && d->lastCurrentTime <= dura)
+ || (!timeFwd && d->currentTime <= dura))
+ animation->setCurrentTime(d->currentTime);
+ if (d->currentTime > dura)
+ animation->stop();
+ }
+ d->lastIteration = d->currentIteration;
+ d->lastCurrentTime = d->currentTime;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QParallelAnimationGroup);
+ QAnimationGroup::updateState(oldState, newState);
+
+ switch (newState) {
+ case Stopped:
+ foreach (QAbstractAnimation *animation, d->animations)
+ animation->stop();
+ d->disconnectUncontrolledAnimations();
+ break;
+ case Paused:
+ foreach (QAbstractAnimation *animation, d->animations)
+ animation->pause();
+ break;
+ case Running:
+ d->connectUncontrolledAnimations();
+ foreach (QAbstractAnimation *animation, d->animations) {
+ animation->stop();
+ animation->setDirection(d->direction);
+ animation->start();
+ }
+ break;
+ }
+}
+
+void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender());
+ Q_ASSERT(animation);
+
+ int uncontrolledRunningCount = 0;
+ if (animation->duration() == -1 || animation->iterationCount() < 0) {
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ if (it.key() == animation) {
+ *it = animation->currentTime();
+ }
+ if (it.value() == -1)
+ ++uncontrolledRunningCount;
+ ++it;
+ }
+ }
+
+ if (uncontrolledRunningCount > 0)
+ return;
+
+ int maxDuration = 0;
+ foreach (QAbstractAnimation *a, animations)
+ maxDuration = qMax(maxDuration, a->totalDuration());
+
+ if (currentTime >= maxDuration)
+ q->stop();
+}
+
+void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ QObject::disconnect(it.key(), SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+ ++it;
+ }
+
+ uncontrolledFinishTime.clear();
+}
+
+void QParallelAnimationGroupPrivate::connectUncontrolledAnimations()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ foreach (QAbstractAnimation *animation, animations) {
+ if (animation->duration() == -1 || animation->iterationCount() < 0) {
+ uncontrolledFinishTime[animation] = -1;
+ QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+ }
+ }
+}
+
+bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
+{
+ return uncontrolledFinishTime.value(anim, -1) >= 0;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_D(QParallelAnimationGroup);
+ //we need to update the direction of the current animation
+ if (state() != Stopped) {
+ foreach(QAbstractAnimation *anim, d->animations) {
+ anim->setDirection(direction);
+ }
+ } else {
+ if (direction == Forward) {
+ d->lastIteration = 0;
+ d->lastCurrentTime = 0;
+ } else {
+ // Looping backwards with iterationCount == -1 does not really work well...
+ d->lastIteration = (d->iterationCount == -1 ? 0 : d->iterationCount - 1);
+ d->lastCurrentTime = duration();
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QParallelAnimationGroup::event(QEvent *event)
+{
+ return QAnimationGroup::event(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qparallelanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h
new file mode 100644
index 0000000..48d66a3
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUP_H
+#define QPARALLELANIMATIONGROUP_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qanimationgroup.h"
+#else
+# include <QtCore/qanimationgroup.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QParallelAnimationGroupPrivate;
+class Q_CORE_EXPORT QParallelAnimationGroup : public QAnimationGroup
+{
+ Q_OBJECT
+
+public:
+ QParallelAnimationGroup(QObject *parent = 0);
+ ~QParallelAnimationGroup();
+
+ int duration() const;
+
+protected:
+ QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void updateDirection(QAbstractAnimation::Direction direction);
+
+private:
+ Q_DISABLE_COPY(QParallelAnimationGroup)
+ Q_DECLARE_PRIVATE(QParallelAnimationGroup)
+ Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished())
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPARALLELANIMATIONGROUP
diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h
new file mode 100644
index 0000000..8a4dc1b
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPARALLELANIMATIONGROUP_P_H
+#define QPARALLELANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qparallelanimationgroup.h"
+#include "qanimationgroup_p.h"
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QParallelAnimationGroupPrivate : public QAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QParallelAnimationGroup)
+public:
+ QParallelAnimationGroupPrivate()
+ : lastIteration(0), lastCurrentTime(0)
+ {
+ }
+
+ QHash<QAbstractAnimation*, int> uncontrolledFinishTime;
+ int lastIteration;
+ int lastCurrentTime;
+
+ bool isUncontrolledAnimationFinished(QAbstractAnimation *anim) const;
+ void connectUncontrolledAnimations();
+ void disconnectUncontrolledAnimations();
+
+ // private slot
+ void _q_uncontrolledAnimationFinished();
+};
+
+QT_END_NAMESPACE
+
+#endif //QPARALLELANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
new file mode 100644
index 0000000..30ea92c
--- /dev/null
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QPauseAnimation
+ \brief The QPauseAnimation class provides a pause for QSequentialAnimationGroup.
+ \since 4.5
+ \ingroup animation
+ \preliminary
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qpauseanimation.h"
+#include "qabstractanimation_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class QPauseAnimationPrivate : public QAbstractAnimationPrivate
+{
+public:
+ QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(0)
+ {
+ }
+
+ int duration;
+};
+
+/*!
+ Constructs a QPauseAnimation.
+ \a parent is passed to QObject's constructor.
+ The default duration is 0.
+*/
+
+QPauseAnimation::QPauseAnimation(QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent)
+{
+}
+
+/*!
+ Constructs a QPauseAnimation.
+ \a msecs is the duration of the pause.
+ \a parent is passed to QObject's constructor.
+*/
+
+QPauseAnimation::QPauseAnimation(int msecs, QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent)
+{
+ setDuration(msecs);
+}
+
+/*!
+ Destroys the pause animation.
+*/
+QPauseAnimation::~QPauseAnimation()
+{
+}
+
+/*!
+ \property QPauseAnimation::duration
+ \brief the duration of the pause.
+
+ The duration of the pause. The duration should not be negative.
+*/
+int QPauseAnimation::duration() const
+{
+ Q_D(const QPauseAnimation);
+ return d->duration;
+}
+
+void QPauseAnimation::setDuration(int msecs)
+{
+ if (msecs < 0) {
+ qWarning("QPauseAnimation::setDuration: cannot set a negative duration");
+ return;
+ }
+ Q_D(QPauseAnimation);
+ d->duration = msecs;
+}
+
+/*!
+ \reimp
+ */
+bool QPauseAnimation::event(QEvent *e)
+{
+ return QAbstractAnimation::event(e);
+}
+
+/*!
+ \reimp
+ */
+void QPauseAnimation::updateCurrentTime(int msecs)
+{
+ Q_UNUSED(msecs);
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qpauseanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h
new file mode 100644
index 0000000..595f2d0
--- /dev/null
+++ b/src/corelib/animation/qpauseanimation.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAUSEANIMATION_P_H
+#define QPAUSEANIMATION_P_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qanimationgroup.h"
+#else
+# include <QtCore/qanimationgroup.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPauseAnimationPrivate;
+
+class Q_CORE_EXPORT QPauseAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(int duration READ duration WRITE setDuration)
+public:
+ QPauseAnimation(QObject *parent = 0);
+ QPauseAnimation(int msecs, QObject *parent = 0);
+ ~QPauseAnimation();
+
+ int duration() const;
+ void setDuration(int msecs);
+
+protected:
+ bool event(QEvent *e);
+ void updateCurrentTime(int msecs);
+
+private:
+ Q_DISABLE_COPY(QPauseAnimation)
+ Q_DECLARE_PRIVATE(QPauseAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPAUSEANIMATION_P_H
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
new file mode 100644
index 0000000..adf3527
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QPropertyAnimation
+ \brief The QPropertyAnimation class animates properties for QObject(and QWidget)
+ \ingroup animation
+ \preliminary
+
+ This class is part of {The Animation Framework}. You can use QPropertyAnimation
+ by itself as a simple animation class, or as part of more complex
+ animations through QAnimationGroup.
+
+ The most common way to use QPropertyAnimation is to construct an instance
+ of it by passing a pointer to a QObject or a QWidget, and the name of the
+ property you would like to animate to QPropertyAnimation's constructor.
+
+ The start value of the animation is optional. If you do not set any start
+ value, the animation will operate on the target's current property value
+ at the point when the animation was started. You can call setStartValue()
+ to set the start value, and setEndValue() to set the target value for
+ the animated property.
+
+ Animations can operate on QObjects and QWidgets. You can choose to assign a
+ target object by either calling setTargetObject() or by passing a QObject
+ pointer to QPropertyAnimation's constructor.
+
+ \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qpropertyanimation.h"
+#include "qanimationgroup.h"
+#include <QtCore/qdebug.h>
+
+#include "qpropertyanimation_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
+typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
+Q_GLOBAL_STATIC(QPropertyAnimationHash, _q_runningAnimations);
+Q_GLOBAL_STATIC_WITH_ARGS(QMutex, guardHashLock, (QMutex::Recursive) )
+
+void QPropertyAnimationPrivate::updateMetaProperty()
+{
+ if (!target || propertyName.isEmpty())
+ return;
+
+ if (hasMetaProperty == 0 && !property.isValid()) {
+ const QMetaObject *mo = target->metaObject();
+ propertyIndex = mo->indexOfProperty(propertyName);
+ if (propertyIndex != -1) {
+ hasMetaProperty = 1;
+ property = mo->property(propertyIndex);
+ propertyType = property.userType();
+ } else {
+ hasMetaProperty = 2;
+ }
+ }
+
+ if (property.isValid())
+ convertValues(propertyType);
+}
+
+void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue)
+{
+ if (!target || state == QAbstractAnimation::Stopped)
+ return;
+
+ if (hasMetaProperty == 1) {
+ if (newValue.userType() == propertyType) {
+ //no conversion is needed, we directly call the QObject::qt_metacall
+ void *data = const_cast<void*>(newValue.constData());
+ target->qt_metacall(QMetaObject::WriteProperty, propertyIndex, &data);
+ } else {
+ property.write(target, newValue);
+ }
+ } else {
+ target->setProperty(propertyName.constData(), newValue);
+ }
+}
+
+/*!
+ Construct a QPropertyAnimation object. \a parent is passed to QObject's
+ constructor.
+*/
+QPropertyAnimation::QPropertyAnimation(QObject *parent)
+ : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
+{
+}
+
+/*!
+ Construct a QPropertyAnimation object. \a parent is passed to QObject's
+ constructor. The animation changes the property \a propertyName on \a
+ target. The default duration is 250ms.
+
+ \sa targetObject, propertyName
+*/
+QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent)
+ : QVariantAnimation(*new QPropertyAnimationPrivate, parent)
+{
+ setTargetObject(target);
+ setPropertyName(propertyName);
+}
+
+/*!
+ Destroys the QPropertyAnimation instance.
+ */
+QPropertyAnimation::~QPropertyAnimation()
+{
+ stop();
+}
+
+/*!
+ \property QPropertyAnimation::targetObject
+ \brief the target QObject for this animation.
+
+ This property defines the target QObject for this animation.
+ */
+QObject *QPropertyAnimation::targetObject() const
+{
+ Q_D(const QPropertyAnimation);
+ return d->target;
+}
+void QPropertyAnimation::setTargetObject(QObject *target)
+{
+ Q_D(QPropertyAnimation);
+ if (d->target == target)
+ return;
+
+ d->target = target;
+ d->hasMetaProperty = 0;
+ d->updateMetaProperty();
+}
+
+/*!
+ \property QPropertyAnimation::propertyName
+ \brief the target property name for this animation
+
+ This property defines the target property name for this animation. The
+ property name is required for the animation to operate.
+ */
+QByteArray QPropertyAnimation::propertyName() const
+{
+ Q_D(const QPropertyAnimation);
+ return d->propertyName;
+}
+void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
+{
+ Q_D(QPropertyAnimation);
+ d->propertyName = propertyName;
+ d->hasMetaProperty = 0;
+ d->updateMetaProperty();
+}
+
+
+/*!
+ \reimp
+ */
+bool QPropertyAnimation::event(QEvent *event)
+{
+ return QVariantAnimation::event(event);
+}
+
+/*!
+ This virtual function is called by QVariantAnimation whenever the current value
+ changes. \a value is the new, updated value. It updates the current value
+ of the property on the target object.
+
+ \sa currentValue, currentTime
+ */
+void QPropertyAnimation::updateCurrentValue(const QVariant &value)
+{
+ Q_D(QPropertyAnimation);
+ d->updateProperty(value);
+}
+
+/*!
+ \reimp
+*/
+void QPropertyAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QPropertyAnimation);
+ QVariantAnimation::updateState(oldState, newState);
+ QMutexLocker locker(guardHashLock());
+ QPropertyAnimationHash * hash = _q_runningAnimations();
+ QPropertyAnimationPair key(d->target, d->propertyName);
+ if (newState == Running) {
+ d->updateMetaProperty();
+ QPropertyAnimation *oldAnim = hash->value(key, 0);
+ if (oldAnim) {
+ //we try to stop the top level group
+ QAbstractAnimation *current = oldAnim;
+ while(current->group() && current->state() != Stopped) current = current->group();
+ current->stop();
+ }
+ hash->insert(key, this);
+ // Initialize start value
+ if (d->target && !d->defaultStartValue.isValid() && (d->atBeginning() || d->atEnd())) {
+ d->setDefaultStartValue(d->target->property(d->propertyName.constData()));
+ }
+ } else if (hash->value(key) == this) {
+ hash->remove(key);
+ }
+
+}
+
+#include "moc_qpropertyanimation.cpp"
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h
new file mode 100644
index 0000000..e5d5305
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROPERTYANIMATION_H
+#define QPROPERTYANIMATION_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qvariantanimation.h"
+#else
+# include <QtCore/qvariantanimation.h>
+#endif
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPropertyAnimationPrivate;
+class Q_CORE_EXPORT QPropertyAnimation : public QVariantAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName)
+ Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject)
+
+public:
+ QPropertyAnimation(QObject *parent = 0);
+ QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0);
+ ~QPropertyAnimation();
+
+ QObject *targetObject() const;
+ void setTargetObject(QObject *target);
+
+ QByteArray propertyName() const;
+ void setPropertyName(const QByteArray &propertyName);
+
+protected:
+ bool event(QEvent *event);
+
+ void updateCurrentValue(const QVariant &value);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+private:
+ Q_DISABLE_COPY(QPropertyAnimation)
+ Q_DECLARE_PRIVATE(QPropertyAnimation)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPROPERTYANIMATION_H
diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h
new file mode 100644
index 0000000..ed3666d
--- /dev/null
+++ b/src/corelib/animation/qpropertyanimation_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROPERTYANIMATION_P_H
+#define QPROPERTYANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qpropertyanimation.h"
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qpointer.h>
+
+#include "qvariantanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPropertyAnimationPrivate : public QVariantAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QPropertyAnimation)
+public:
+ QPropertyAnimationPrivate()
+ : target(0), propertyType(0), propertyIndex(0), hasMetaProperty(false)
+ {
+ }
+
+
+ QPointer<QObject> target;
+
+ //for the QProperty
+ QMetaProperty property;
+ int propertyType;
+ int propertyIndex;
+
+ int hasMetaProperty;
+ QByteArray propertyName;
+ void updateProperty(const QVariant &);
+ void updateMetaProperty();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp
new file mode 100644
index 0000000..879532c
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup.cpp
@@ -0,0 +1,572 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QSequentialAnimationGroup
+ \brief The QSequentialAnimationGroup class provides a sequential group of animations.
+ \since 4.5
+ \ingroup animation
+ \preliminary
+
+ The first animation in the group is started first, and when it finishes, the next animation
+ is started, and so on. The animation group finishes when the last animation has finished.
+
+ At each moment there is at most one animation that is active in the group, called currentAnimation.
+ An empty group has no current animation.
+
+ You can call addPause() or insertPause() to add a pause to a sequential animation group.
+*/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qsequentialanimationgroup.h"
+#include "qsequentialanimationgroup_p.h"
+
+#include "qpauseanimation.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+
+
+bool QSequentialAnimationGroupPrivate::atEnd() const
+{
+ // we try to detect if we're at the end of the group
+ //this is true if the following conditions are true:
+ // 1. we're in the last loop
+ // 2. the direction is forward
+ // 3. the current animation is the last one
+ // 4. the current animation has reached its end
+ const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
+ return (currentIteration == iterationCount - 1
+ && direction == QAbstractAnimation::Forward
+ && currentAnimation == animations.last()
+ && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex));
+}
+
+int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) const
+{
+ QAbstractAnimation *anim = animations.at(index);
+ int ret = anim->totalDuration();
+ if (ret == -1 && actualDuration.size() > index)
+ ret = actualDuration.at(index); //we can try the actual duration there
+ return ret;
+}
+
+QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForTime(int msecs) const
+{
+ Q_Q(const QSequentialAnimationGroup);
+ Q_ASSERT(!animations.isEmpty());
+
+ AnimationIndex ret;
+ int duration = 0;
+
+ // in case duration is -1, currentLoop will always be 0
+ ret.timeOffset = currentIteration * q->duration();
+
+ for (int i = 0; i < animations.size(); ++i) {
+ duration = animationActualTotalDuration(i);
+
+ // 'animation' is the current animation if one of these reasons is true:
+ // 1. it's duration is undefined
+ // 2. it ends after msecs
+ // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
+ // 4. it ends exactly in msecs and the direction is backwards
+ if (duration == -1 || msecs < (ret.timeOffset + duration)
+ || (msecs == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) {
+ ret.index = i;
+ return ret;
+ }
+
+ // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
+ ret.timeOffset += duration;
+ }
+
+ // this can only happen when one of those conditions is true:
+ // 1. the duration of the group is undefined and we passed its actual duration
+ // 2. there are only 0-duration animations in the group
+ ret.timeOffset -= duration;
+ ret.index = animations.size() - 1;
+ return ret;
+}
+
+void QSequentialAnimationGroupPrivate::restart()
+{
+ // restarting the group by making the first/last animation the current one
+ if (direction == QAbstractAnimation::Forward) {
+ lastIteration = 0;
+ if (currentAnimationIndex == 0)
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(0);
+ } else { // direction == QAbstractAnimation::Backward
+ lastIteration = iterationCount - 1;
+ int index = animations.size() - 1;
+ if (currentAnimationIndex == index)
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(index);
+ }
+}
+
+/*!
+ \internal
+ This manages advancing the execution of a group running forwards (time has gone forward),
+ which is the same behaviour for rewinding the execution of a group running backwards
+ (time has gone backward).
+*/
+void QSequentialAnimationGroupPrivate::advanceForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (lastIteration < currentIteration) {
+ // we need to fast forward to the end
+ for (int i = currentAnimationIndex; i < animations.size(); ++i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(animationActualTotalDuration(i));
+ }
+ // this will make sure the current animation is reset to the beginning
+ if (animations.size() == 1)
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(0, true);
+ }
+
+ // and now we need to fast forward from the current position to
+ for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG,
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(animationActualTotalDuration(i));
+ }
+ // setting the new current animation will happen later
+}
+
+/*!
+ \internal
+ This manages rewinding the execution of a group running forwards (time has gone forward),
+ which is the same behaviour for advancing the execution of a group running backwards
+ (time has gone backward).
+*/
+void QSequentialAnimationGroupPrivate::rewindForwards(const AnimationIndex &newAnimationIndex)
+{
+ if (lastIteration > currentIteration) {
+ // we need to fast rewind to the beginning
+ for (int i = currentAnimationIndex; i >= 0 ; --i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(0);
+ }
+ // this will make sure the current animation is reset to the end
+ if (animations.size() == 1)
+ // we need to force activation because setCurrentAnimation will have no effect
+ activateCurrentAnimation();
+ else
+ setCurrentAnimation(animations.count() - 1, true);
+ }
+
+ // and now we need to fast rewind from the current position to
+ for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) {
+ QAbstractAnimation *anim = animations.at(i);
+ setCurrentAnimation(i, true);
+ anim->setCurrentTime(0);
+ }
+ // setting the new current animation will happen later
+}
+
+/*!
+ \fn QSequentialAnimationGroup::currentAnimationChanged(QAbstractAnimation *current)
+
+ QSequentialAnimationGroup emits this signal when currentAnimation
+ has been changed. \a current is the current animation.
+
+ \sa currentAnimation()
+*/
+
+
+/*!
+ Constructs a QSequentialAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QSequentialAnimationGroup::QSequentialAnimationGroup(QObject *parent)
+ : QAnimationGroup(*new QSequentialAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QSequentialAnimationGroup::QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd,
+ QObject *parent)
+ : QAnimationGroup(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QSequentialAnimationGroup::~QSequentialAnimationGroup()
+{
+}
+
+/*!
+ Adds a pause of \a msecs to this animation group.
+ The pause is considered as a special type of animation, thus count() will be
+ increased by one.
+ \sa insertPauseAt(), QAnimationGroup::addAnimation()
+*/
+QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs)
+{
+ QPauseAnimation *pause = new QPauseAnimation(msecs);
+ addAnimation(pause);
+ return pause;
+}
+
+/*!
+ Inserts a pause of \a msecs milliseconds at \a index in this animation
+ group.
+
+ \sa addPause(), QAnimationGroup::insertAnimationAt()
+*/
+QPauseAnimation *QSequentialAnimationGroup::insertPauseAt(int index, int msecs)
+{
+ Q_D(const QSequentialAnimationGroup);
+
+ if (index < 0 || index > d->animations.size()) {
+ qWarning("QSequentialAnimationGroup::insertPauseAt: index is out of bounds");
+ return 0;
+ }
+
+ QPauseAnimation *pause = new QPauseAnimation(msecs);
+ insertAnimationAt(index, pause);
+ return pause;
+}
+
+
+/*!
+ \property QSequentialAnimationGroup::currentAnimation
+ Returns the animation in the current time.
+
+ \sa currentAnimationChanged()
+*/
+QAbstractAnimation *QSequentialAnimationGroup::currentAnimation() const
+{
+ Q_D(const QSequentialAnimationGroup);
+ return d->currentAnimation;
+}
+
+/*!
+ \reimp
+*/
+int QSequentialAnimationGroup::duration() const
+{
+ Q_D(const QSequentialAnimationGroup);
+ int ret = 0;
+
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int currentDuration = animation->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret += currentDuration;
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateCurrentTime(int msecs)
+{
+ Q_D(QSequentialAnimationGroup);
+ if (!d->currentAnimation)
+ return;
+
+ const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForTime(msecs);
+
+ // remove unneeded animations from actualDuration list
+ while (newAnimationIndex.index < d->actualDuration.size())
+ d->actualDuration.removeLast();
+
+ // newAnimationIndex.index is the new current animation
+ if (d->lastIteration < d->currentIteration
+ || (d->lastIteration == d->currentIteration && d->currentAnimationIndex < newAnimationIndex.index)) {
+ // advancing with forward direction is the same as rewinding with backwards direction
+ d->advanceForwards(newAnimationIndex);
+ } else if (d->lastIteration > d->currentIteration
+ || (d->lastIteration == d->currentIteration && d->currentAnimationIndex > newAnimationIndex.index)) {
+ // rewinding with forward direction is the same as advancing with backwards direction
+ d->rewindForwards(newAnimationIndex);
+ }
+
+ d->setCurrentAnimation(newAnimationIndex.index);
+
+ const int newCurrentTime = msecs - newAnimationIndex.timeOffset;
+
+ if (d->currentAnimation) {
+ d->currentAnimation->setCurrentTime(newCurrentTime);
+ if (d->atEnd()) {
+ //we make sure that we don't exceed the duration here
+ d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime;
+ stop();
+ }
+ } else {
+ //the only case where currentAnimation could be null
+ //is when all animations have been removed
+ Q_ASSERT(d->animations.isEmpty());
+ d->currentTime = 0;
+ stop();
+ }
+
+ d->lastIteration = d->currentIteration;
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_D(QSequentialAnimationGroup);
+ QAnimationGroup::updateState(oldState, newState);
+
+ if (!d->currentAnimation)
+ return;
+
+ switch (newState) {
+ case Stopped:
+ d->currentAnimation->stop();
+ break;
+ case Paused:
+ if (oldState == d->currentAnimation->state()
+ && oldState == QSequentialAnimationGroup::Running) {
+ d->currentAnimation->pause();
+ }
+ else
+ d->restart();
+ break;
+ case Running:
+ if (oldState == d->currentAnimation->state()
+ && oldState == QSequentialAnimationGroup::Paused)
+ d->currentAnimation->start();
+ else
+ d->restart();
+ break;
+ }
+}
+
+/*!
+ \reimp
+*/
+void QSequentialAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_D(QSequentialAnimationGroup);
+ // we need to update the direction of the current animation
+ if (state() != Stopped && d->currentAnimation)
+ d->currentAnimation->setDirection(direction);
+}
+
+/*!
+ \reimp
+*/
+bool QSequentialAnimationGroup::event(QEvent *event)
+{
+ return QAnimationGroup::event(event);
+}
+
+void QSequentialAnimationGroupPrivate::setCurrentAnimation(int index, bool intermediate)
+{
+ Q_Q(QSequentialAnimationGroup);
+
+ index = qMin(index, animations.count() - 1);
+
+ if (index == -1) {
+ Q_ASSERT(animations.isEmpty());
+ currentAnimationIndex = -1;
+ currentAnimation = 0;
+ return;
+ }
+
+ // need these two checks below because this func can be called after the current animation
+ // has been removed
+ if (index == currentAnimationIndex && animations.at(index) == currentAnimation)
+ return;
+
+ // stop the old current animation
+ if (currentAnimation)
+ currentAnimation->stop();
+
+ currentAnimation = animations.at(index);
+ currentAnimationIndex = index;
+
+ emit q->currentAnimationChanged(currentAnimation);
+
+ activateCurrentAnimation(intermediate);
+}
+
+void QSequentialAnimationGroupPrivate::activateCurrentAnimation(bool intermediate)
+{
+ Q_Q(QSequentialAnimationGroup);
+
+ if (!currentAnimation)
+ return;
+
+ if (state == QSequentialAnimationGroup::Stopped)
+ return;
+
+ currentAnimation->stop();
+
+ // we ensure the direction is consistent with the group's direction
+ currentAnimation->setDirection(direction);
+
+ // connects to the finish signal of uncontrolled animations
+ if (currentAnimation->totalDuration() == -1)
+ QObject::connect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+
+ currentAnimation->start();
+ if (!intermediate && state == QSequentialAnimationGroup::Paused)
+ currentAnimation->pause();
+}
+
+void QSequentialAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
+{
+ Q_Q(QSequentialAnimationGroup);
+ Q_ASSERT(qobject_cast<QAbstractAnimation *>(q->sender()) == currentAnimation);
+
+ // we trust the duration returned by the animation
+ while (actualDuration.size() < (currentAnimationIndex + 1))
+ actualDuration.append(-1);
+ actualDuration[currentAnimationIndex] = currentAnimation->currentTime();
+
+ QObject::disconnect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
+
+ if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last())
+ || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) {
+ // we don't handle looping of a group with undefined duration
+ q->stop();
+ } else if (direction == QAbstractAnimation::Forward) {
+ // set the current animation to be the next one
+ setCurrentAnimation(currentAnimationIndex + 1);
+ } else {
+ // set the current animation to be the previous one
+ setCurrentAnimation(currentAnimationIndex - 1);
+ }
+}
+
+/*!
+ \internal
+ This method is called whenever an animation is added to
+ the group at index \a index.
+ Note: We only support insertion after the current animation
+*/
+void QSequentialAnimationGroupPrivate::animationInsertedAt(int index)
+{
+ if (currentAnimation == 0)
+ setCurrentAnimation(0); // initialize the current animation
+
+ if (currentAnimationIndex == index
+ && currentAnimation->currentTime() == 0 && currentAnimation->currentIteration() == 0) {
+ //in this case we simply insert an animation before the current one has actually started
+ setCurrentAnimation(index);
+ }
+
+ //we update currentAnimationIndex in case it has changed (the animation pointer is still valid)
+ currentAnimationIndex = animations.indexOf(currentAnimation);
+
+ if (index < currentAnimationIndex || currentIteration != 0) {
+ qWarning("QSequentialGroup::insertAnimationAt only supports to add animations after the current one.");
+ return; //we're not affected because it is added after the current one
+ }
+}
+
+/*!
+ \internal
+ This method is called whenever an animation is removed from
+ the group at index \a index. The animation is no more listed when this
+ method is called.
+*/
+void QSequentialAnimationGroupPrivate::animationRemovedAt(int index)
+{
+ Q_Q(QSequentialAnimationGroup);
+ QAnimationGroupPrivate::animationRemovedAt(index);
+
+ Q_ASSERT(currentAnimation); // currentAnimation should always be set
+
+ if (actualDuration.size() > index)
+ actualDuration.removeAt(index);
+
+ const int currentIndex = animations.indexOf(currentAnimation);
+ if (currentIndex == -1) {
+ //we're removing the current animation, let's update it to another one
+ if (index < animations.count())
+ setCurrentAnimation(index); //let's try to take the next one
+ else if (index > 0)
+ setCurrentAnimation(index - 1);
+ else// case all animations were removed
+ setCurrentAnimation(-1);
+ } else if (currentAnimationIndex > index) {
+ currentAnimationIndex--;
+ }
+
+ // duration of the previous animations up to the current animation
+ currentTime = 0;
+ for (int i = 0; i < currentAnimationIndex; ++i) {
+ const int current = animationActualTotalDuration(i);
+ currentTime += current;
+ }
+
+ if (currentIndex != -1) {
+ //the current animation is not the one being removed
+ //so we add its current time to the current time of this group
+ currentTime += QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
+ }
+
+ //let's also update the total current time
+ totalCurrentTime = currentTime + iterationCount * q->duration();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qsequentialanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h
new file mode 100644
index 0000000..4c52d1b
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUP_H
+#define QSEQUENTIALANIMATIONGROUP_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qanimationgroup.h"
+#else
+# include <QtCore/qanimationgroup.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QPauseAnimation;
+class QSequentialAnimationGroupPrivate;
+
+class Q_CORE_EXPORT QSequentialAnimationGroup : public QAnimationGroup
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractAnimation* currentAnimation READ currentAnimation NOTIFY currentAnimationChanged)
+
+public:
+ QSequentialAnimationGroup(QObject *parent = 0);
+ ~QSequentialAnimationGroup();
+
+ QPauseAnimation *addPause(int msecs);
+ QPauseAnimation *insertPauseAt(int index, int msecs);
+
+ QAbstractAnimation *currentAnimation() const;
+ int duration() const;
+
+Q_SIGNALS:
+ void currentAnimationChanged(QAbstractAnimation *current);
+
+protected:
+ QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+ void updateDirection(QAbstractAnimation::Direction direction);
+
+private:
+ Q_DISABLE_COPY(QSequentialAnimationGroup)
+ Q_DECLARE_PRIVATE(QSequentialAnimationGroup)
+ Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished())
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QSEQUENTIALANIMATIONGROUP_H
diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h
new file mode 100644
index 0000000..05d2a40
--- /dev/null
+++ b/src/corelib/animation/qsequentialanimationgroup_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSEQUENTIALANIMATIONGROUP_P_H
+#define QSEQUENTIALANIMATIONGROUP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsequentialanimationgroup.h"
+#include "qanimationgroup_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class QSequentialAnimationGroupPrivate : public QAnimationGroupPrivate
+{
+ Q_DECLARE_PUBLIC(QSequentialAnimationGroup)
+public:
+ QSequentialAnimationGroupPrivate()
+ : currentAnimation(0), currentAnimationIndex(-1), lastIteration(0)
+ { }
+
+
+ struct AnimationIndex
+ {
+ AnimationIndex() : index(0), timeOffset(0) {}
+ // index points to the animation at timeOffset, skipping 0 duration animations.
+ // Note that the index semantic is slightly different depending on the direction.
+ int index; // the index of the animation in timeOffset
+ int timeOffset; // time offset when the animation at index starts.
+ };
+
+ int animationActualTotalDuration(int index) const;
+ AnimationIndex indexForTime(int msecs) const;
+
+ void setCurrentAnimation(int index, bool intermediate = false);
+ void activateCurrentAnimation(bool intermediate = false);
+
+ void animationInsertedAt(int index);
+ void animationRemovedAt(int index);
+
+ bool atEnd() const;
+
+ QAbstractAnimation *currentAnimation;
+ int currentAnimationIndex;
+
+ // this is the actual duration of uncontrolled animations
+ // it helps seeking and even going forward
+ QList<int> actualDuration;
+
+ void restart();
+ int lastIteration;
+
+ // handle time changes
+ void rewindForwards(const AnimationIndex &newAnimationIndex);
+ void advanceForwards(const AnimationIndex &newAnimationIndex);
+
+ // private slot
+ void _q_uncontrolledAnimationFinished();
+};
+
+QT_END_NAMESPACE
+
+#endif //QSEQUENTIALANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
new file mode 100644
index 0000000..6b162ae
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -0,0 +1,599 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qvariantanimation.h"
+#include "qvariantanimation_p.h"
+
+#include <QtCore/QRect>
+#include <QtCore/QLineF>
+#include <QtCore/QLine>
+#include <QtCore/QReadWriteLock>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVariantAnimation
+ \ingroup animation
+ \brief The QVariantAnimation class provides an abstract base class for animations.
+ \since 4.5
+ \preliminary
+
+ This class is part of {The Animation Framework}. It serves as a base class
+ for property and item animations, with functions for shared functionality.
+
+ If you want to create an animation, you should look at QPropertyAnimation instead.
+
+ You can then set start and end values for the property by calling
+ setStartValue() and setEndValue(), and finally call start() to
+ start the animation. When control goes back to the event loop, QVariantAnimation
+ will interpolate the property of the target object and emit the valueChanged
+ signal. To react to a change in the current value you have to reimplement the
+ updateCurrentValue virtual method.
+
+ There are two ways to affect how QVariantAnimation interpolates the values.
+ You can set an easing curve by calling setEasingCurve(), and configure the
+ duration by calling setDuration(). You can change how the QVariants are
+ interpolated by creating a subclass of QVariantAnimation, and reimplementing the
+ virtual interpolated() function.
+
+
+ \sa QPropertyAnimation, {The Animation Framework}
+*/
+
+/*!
+ \fn void QVariantAnimation::valueChanged(const QVariant &value)
+
+ QVariantAnimation emits this signal whenever the current \a value changes.
+
+ \sa currentValue, startValue, endValue
+*/
+
+static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2)
+{
+ return p1.first < p2.first;
+}
+
+template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress)
+{
+ QRect ret;
+ ret.setCoords(_q_interpolate(f.left(), t.left(), progress),
+ _q_interpolate(f.top(), t.top(), progress),
+ _q_interpolate(f.right(), t.right(), progress),
+ _q_interpolate(f.bottom(), t.bottom(), progress));
+ return ret;
+}
+
+template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress)
+{
+ qreal x1, y1, w1, h1;
+ f.getRect(&x1, &y1, &w1, &h1);
+ qreal x2, y2, w2, h2;
+ t.getRect(&x2, &y2, &w2, &h2);
+ return QRectF( _q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress),
+ _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress));
+}
+
+template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress)
+{
+ return QLine( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
+}
+
+template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress)
+{
+ return QLineF( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
+}
+
+void QVariantAnimationPrivate::convertValues(int t)
+{
+ //this ensures that all the keyValues are of type t
+ for (int i = 0; i < keyValues.count(); ++i) {
+ QVariantAnimation::KeyValue &pair = keyValues[i];
+ if (pair.second.userType() != t)
+ pair.second.convert(static_cast<QVariant::Type>(t));
+ }
+ currentInterval.start.first = 2; // this will force the refresh
+ interpolator = 0; // if the type changed we need to update the interpolator
+}
+
+/*!
+ \fn void QVariantAnimation::updateCurrentValue(const QVariant &value) = 0;
+ This pure virtual function is called when the animated value is changed.
+ \a value is the new value.
+*/
+
+void QVariantAnimationPrivate::updateCurrentValue()
+{
+ Q_Q(QVariantAnimation);
+ const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration)));
+
+ if (progress < currentInterval.start.first || progress > currentInterval.end.first) {
+ //let's update currentInterval
+ QVariantAnimation::KeyValues::const_iterator itStart = qLowerBound(keyValues.constBegin(), keyValues.constEnd(), qMakePair(progress, QVariant()), animationValueLessThan);
+ QVariantAnimation::KeyValues::const_iterator itEnd = itStart;
+
+ // If we are at the end we should continue to use the last keyValues in case of extrapolation (progress > 1.0).
+ // This is because the easing function can return a value slightly outside the range [0, 1]
+ if (itStart != keyValues.constEnd()) {
+
+ //this can't happen because we always prepend the default start value there
+ if (itStart == keyValues.begin()) {
+ ++itEnd;
+ if (itEnd == keyValues.constEnd())
+ return; //there is no upper bound
+ } else {
+ --itStart;
+ }
+
+ //update all the values of the currentInterval
+ currentInterval.start = *itStart;
+ currentInterval.end = *itEnd;
+ }
+ }
+
+ const qreal startProgress = currentInterval.start.first,
+ endProgress = currentInterval.end.first;
+ const qreal localProgress = (progress - startProgress) / (endProgress - startProgress);
+
+ bool changed = false;
+ {
+ //we do that here in a limited scope so that ret is dereferenced and frees memory
+ //and the call to updateCurrentValue can recreate QVariant of the same type (for ex. in
+ //QGraphicsItem::setPos
+ QVariant ret = q->interpolated(currentInterval.start.second,
+ currentInterval.end.second,
+ localProgress);
+ if (currentValue != ret) {
+ changed = true;
+ qSwap(currentValue, ret);
+ }
+ }
+
+ if (changed) {
+ //the value has changed
+ q->updateCurrentValue(currentValue);
+#ifndef QT_EXPERIMENTAL_SOLUTION
+ if (connectedSignals & changedSignalMask)
+#endif
+ emit q->valueChanged(currentValue);
+ }
+}
+
+
+QVariant QVariantAnimationPrivate::valueAt(qreal step) const
+{
+ QVariantAnimation::KeyValues::const_iterator result =
+ qBinaryFind(keyValues.begin(), keyValues.end(), qMakePair(step, QVariant()), animationValueLessThan);
+ if (result != keyValues.constEnd())
+ return result->second;
+
+ return QVariant();
+}
+
+
+void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value)
+{
+ if (step < qreal(0.0) || step > qreal(1.0)) {
+ qWarning("QVariantAnimation::setValueAt: invalid step = %f", step);
+ return;
+ }
+
+ QVariantAnimation::KeyValue pair(step, value);
+
+ QVariantAnimation::KeyValues::iterator result = qLowerBound(keyValues.begin(), keyValues.end(), pair, animationValueLessThan);
+ if (result == keyValues.end() || result->first != step) {
+ keyValues.insert(result, pair);
+ } else {
+ if (value.isValid())
+ result->second = value; //remove the previous value
+ else if (step == 0 && !hasStartValue && defaultStartValue.isValid())
+ result->second = defaultStartValue; //we reset to the default start value
+ else
+ keyValues.erase(result); //replace the previous value
+ }
+
+ currentInterval.start.first = 2; // this will force the refresh
+ updateCurrentValue();
+}
+
+void QVariantAnimationPrivate::setDefaultStartValue(const QVariant &value)
+{
+ defaultStartValue = value;
+ if (!hasStartValue)
+ setValueAt(0, value);
+}
+
+/*!
+ Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's
+ constructor.
+*/
+QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent)
+{
+ d_func()->init();
+}
+
+/*!
+ \internal
+*/
+QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent)
+{
+ d_func()->init();
+}
+
+/*!
+ Destroys the animation.
+*/
+QVariantAnimation::~QVariantAnimation()
+{
+}
+
+/*!
+ \property QVariantAnimation::easingCurve
+ \brief the easing curve of the animation
+
+ This property defines the easing curve of the animation. By default, a
+ linear easing curve is used, resulting in linear interpolation of the
+ end property. For many animations, it's useful to try different easing
+ curves, including QEasingCurve::InCirc, which provides a circular entry curve,
+ and QEasingCurve::InOutElastic, which provides an elastic effect on the values
+ of the interpolated property.
+
+ The easing curve is used with the interpolator, the interpolated() virtual
+ function, the animation's duration, and iterationCount, to control how the
+ current value changes as the animation progresses.
+*/
+QEasingCurve QVariantAnimation::easingCurve() const
+{
+ Q_D(const QVariantAnimation);
+ return d->easing;
+}
+
+void QVariantAnimation::setEasingCurve(const QEasingCurve &easing)
+{
+ Q_D(QVariantAnimation);
+ d->easing = easing;
+ d->updateCurrentValue();
+}
+
+Q_GLOBAL_STATIC(QVector<QVariantAnimation::Interpolator>, registeredInterpolators)
+Q_GLOBAL_STATIC(QReadWriteLock, registeredInterpolatorsLock)
+
+/*!
+ \fn void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
+ \relates QVariantAnimation
+ \threadsafe
+
+ Registers a custom interpolator \a func for the template type \c{T}.
+ The interpolator has to be registered before the animation is constructed.
+ To unregister (and use the default interpolator) set \a func to 0.
+ */
+
+/*!
+ \internal
+ \typedef QVariantAnimation::Interpolator
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+ \code
+ QVariant myInterpolator(const QVariant &from, const QVariant &to, qreal progress);
+ \endcode
+
+*/
+
+/*! \internal
+ * Registers a custom interpolator \a func for the specific \a interpolationType.
+ * The interpolator has to be registered before the animation is constructed.
+ * To unregister (and use the default interpolator) set \a func to 0.
+ */
+void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType)
+{
+ // will override any existing interpolators
+ QWriteLocker locker(registeredInterpolatorsLock());
+ if (int(interpolationType) >= registeredInterpolators()->count())
+ registeredInterpolators()->resize(int(interpolationType) + 1);
+ registeredInterpolators()->replace(interpolationType, func);
+}
+
+
+template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
+{
+ return reinterpret_cast<QVariantAnimation::Interpolator>(func);
+}
+
+static QVariantAnimation::Interpolator getInterpolator(int interpolationType)
+{
+ QReadLocker locker(registeredInterpolatorsLock());
+ QVariantAnimation::Interpolator ret = 0;
+ if (interpolationType < registeredInterpolators()->count()) {
+ ret = registeredInterpolators()->at(interpolationType);
+ if (ret) return ret;
+ }
+
+ switch(interpolationType)
+ {
+ case QMetaType::Int:
+ return castToInterpolator(_q_interpolateVariant<int>);
+ case QMetaType::Double:
+ return castToInterpolator(_q_interpolateVariant<double>);
+ case QMetaType::Float:
+ return castToInterpolator(_q_interpolateVariant<float>);
+ case QMetaType::QLine:
+ return castToInterpolator(_q_interpolateVariant<QLine>);
+ case QMetaType::QLineF:
+ return castToInterpolator(_q_interpolateVariant<QLineF>);
+ case QMetaType::QPoint:
+ return castToInterpolator(_q_interpolateVariant<QPoint>);
+ case QMetaType::QPointF:
+ return castToInterpolator(_q_interpolateVariant<QPointF>);
+ case QMetaType::QSize:
+ return castToInterpolator(_q_interpolateVariant<QSize>);
+ case QMetaType::QSizeF:
+ return castToInterpolator(_q_interpolateVariant<QSizeF>);
+ case QMetaType::QRect:
+ return castToInterpolator(_q_interpolateVariant<QRect>);
+ case QMetaType::QRectF:
+ return castToInterpolator(_q_interpolateVariant<QRectF>);
+ default:
+ return 0; //this type is not handled
+ }
+}
+
+/*!
+ \property QVariantAnimation::duration
+ \brief the duration of the animation
+
+ This property describes the duration of the animation. The default
+ duration is 250 milliseconds.
+
+ \sa QAbstractAnimation::duration()
+ */
+int QVariantAnimation::duration() const
+{
+ Q_D(const QVariantAnimation);
+ return d->duration;
+}
+
+void QVariantAnimation::setDuration(int msecs)
+{
+ Q_D(QVariantAnimation);
+ if (msecs < 0) {
+ qWarning("QVariantAnimation::setDuration: cannot set a negative duration");
+ return;
+ }
+ if (d->duration == msecs)
+ return;
+ d->duration = msecs;
+ d->updateCurrentValue();
+}
+
+/*!
+ \property QVariantAnimation::startValue
+ \brief the optional start value of the animation
+
+ This property describes the optional start value of the animation. If
+ omitted, or if a null QVariant is assigned as the start value, the
+ animation will use the current position of the end when the animation
+ is started.
+
+ \sa endValue
+*/
+QVariant QVariantAnimation::startValue() const
+{
+ return keyValueAt(0);
+}
+
+void QVariantAnimation::setStartValue(const QVariant &value)
+{
+ setKeyValueAt(0, value);
+}
+
+/*!
+ \property QVariantAnimation::endValue
+ \brief the end value of the animation
+
+ This property describes the end value of the animation.
+
+ \sa startValue
+ */
+QVariant QVariantAnimation::endValue() const
+{
+ return keyValueAt(1);
+}
+
+void QVariantAnimation::setEndValue(const QVariant &value)
+{
+ setKeyValueAt(1, value);
+}
+
+
+/*!
+ Returns the key frame value for the given \a step. The given \a step
+ must be in the range 0 to 1. If there is no KeyValue for \a step,
+ it returns an invalid QVariant.
+
+ \sa keyValues(), setKeyValueAt()
+*/
+QVariant QVariantAnimation::keyValueAt(qreal step) const
+{
+ Q_D(const QVariantAnimation);
+ if (step == 0 && !d->hasStartValue)
+ return QVariant(); //special case where we don't have an explicit startValue
+
+ return d->valueAt(step);
+}
+
+/*!
+ \typedef QVariantAnimation::KeyValue
+
+ This is a typedef for QPair<qreal, QVariant>.
+*/
+/*!
+ \typedef QVariantAnimation::KeyValues
+
+ This is a typedef for QVector<KeyValue>
+*/
+
+/*!
+ Creates a key frame at the given \a step with the given \a value.
+ The given \a step must be in the range 0 to 1.
+
+ \sa setKeyValues(), keyValueAt()
+*/
+void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value)
+{
+ Q_D(QVariantAnimation);
+ if (step == 0)
+ d->hasStartValue = value.isValid();
+ d->setValueAt(step, value);
+}
+
+/*!
+ Returns the key frames of this animation.
+
+ \sa keyValueAt(), setKeyValues()
+*/
+QVariantAnimation::KeyValues QVariantAnimation::keyValues() const
+{
+ Q_D(const QVariantAnimation);
+ QVariantAnimation::KeyValues ret = d->keyValues;
+ //in case we added the default start value, we remove it
+ if (!d->hasStartValue && !ret.isEmpty() && ret.at(0).first == 0)
+ ret.remove(0);
+ return ret;
+}
+
+/*!
+ Replaces the current set of key frames with the given \a keyValues.
+ the step of the key frames must be in the range 0 to 1.
+
+ \sa keyValues(), keyValueAt()
+*/
+void QVariantAnimation::setKeyValues(const KeyValues &keyValues)
+{
+ Q_D(QVariantAnimation);
+ d->keyValues = keyValues;
+ qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan);
+ d->currentInterval.start.first = 2; // this will force the refresh
+ d->hasStartValue = !d->keyValues.isEmpty() && d->keyValues.at(0).first == 0;
+}
+
+/*!
+ \property QVariantAnimation::currentValue
+ \brief the current value of the animation
+
+ This property describes the current value; an interpolation between the
+ start value and the end value, using the current time for progress.
+
+ QVariantAnimation calls the virtual updateCurrentValue() function when the
+ current value changes. This is particularily useful for subclasses that
+ need to track updates.
+
+ \sa startValue, endValue
+ */
+QVariant QVariantAnimation::currentValue() const
+{
+ Q_D(const QVariantAnimation);
+ if (!d->currentValue.isValid())
+ const_cast<QVariantAnimationPrivate*>(d)->updateCurrentValue();
+ return d->currentValue;
+}
+
+/*!
+ \reimp
+ */
+bool QVariantAnimation::event(QEvent *event)
+{
+ return QAbstractAnimation::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QVariantAnimation::updateState(QAbstractAnimation::State oldState,
+ QAbstractAnimation::State newState)
+{
+ Q_UNUSED(oldState);
+ Q_UNUSED(newState);
+ Q_D(QVariantAnimation);
+ d->currentValue = QVariant(); // this will force the refresh
+}
+
+/*!
+ This virtual function returns the linear interpolation between variants \a
+ from and \a to, at \a progress, usually a value between 0 and 1. You can reimplement
+ this function in a subclass of QVariantAnimation to provide your own interpolation
+ algorithm. Note that in order for the interpolation to work with a QEasingCurve
+ that return a value smaller than 0 or larger than 1 (such as QEasingCurve::InBack)
+ you should make sure that it can extrapolate. If the semantic of the datatype
+ does not allow extrapolation this function should handle that gracefully.
+
+ \sa QEasingCurve
+ */
+QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
+{
+ Q_D(const QVariantAnimation);
+ if (d->interpolator == 0) {
+ if (from.userType() == to.userType())
+ d->interpolator = getInterpolator(from.userType());
+ if (d->interpolator == 0) //no interpolator found
+ return QVariant();
+ }
+
+ return d->interpolator(from.constData(), to.constData(), progress);
+}
+
+/*!
+ \reimp
+ */
+void QVariantAnimation::updateCurrentTime(int msecs)
+{
+ Q_D(QVariantAnimation);
+ Q_UNUSED(msecs);
+ d->updateCurrentValue();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qvariantanimation.cpp"
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h
new file mode 100644
index 0000000..7ce597f
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATION_H
+#define QANIMATION_H
+
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qabstractanimation.h"
+# include "qeasingcurve.h"
+#else
+# include <QtCore/qeasingcurve.h>
+# include <QtCore/qabstractanimation.h>
+#endif
+#include <QtCore/qlist.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qpair.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QVariantAnimationPrivate;
+class Q_CORE_EXPORT QVariantAnimation : public QAbstractAnimation
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant startValue READ startValue WRITE setStartValue)
+ Q_PROPERTY(QVariant endValue READ endValue WRITE setEndValue)
+ Q_PROPERTY(QVariant currentValue READ currentValue NOTIFY currentValueChanged)
+ Q_PROPERTY(int duration READ duration WRITE setDuration)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
+
+public:
+ typedef QPair<qreal, QVariant> KeyValue;
+ typedef QVector<KeyValue> KeyValues;
+
+ QVariantAnimation(QObject *parent = 0);
+ ~QVariantAnimation();
+
+ QVariant startValue() const;
+ void setStartValue(const QVariant &value);
+
+ QVariant endValue() const;
+ void setEndValue(const QVariant &value);
+
+ QVariant keyValueAt(qreal step) const;
+ void setKeyValueAt(qreal step, const QVariant &value);
+
+ KeyValues keyValues() const;
+ void setKeyValues(const KeyValues &values);
+
+ QVariant currentValue() const;
+
+ int duration() const;
+ void setDuration(int msecs);
+
+ QEasingCurve easingCurve() const;
+ void setEasingCurve(const QEasingCurve &easing);
+
+ typedef QVariant (*Interpolator)(const void *from, const void *to, qreal progress);
+
+Q_SIGNALS:
+ void valueChanged(const QVariant &value);
+
+protected:
+ QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0);
+ bool event(QEvent *event);
+
+ void updateCurrentTime(int msecs);
+ void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState);
+
+ virtual void updateCurrentValue(const QVariant &value) = 0;
+ virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const;
+
+private:
+ template <typename T> friend void qRegisterAnimationInterpolator(QVariant (*func)(const T &, const T &, qreal));
+ static void registerInterpolator(Interpolator func, int interpolationType);
+
+ Q_DISABLE_COPY(QVariantAnimation)
+ Q_DECLARE_PRIVATE(QVariantAnimation)
+};
+
+template <typename T>
+static void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) {
+ QVariantAnimation::registerInterpolator(reinterpret_cast<QVariantAnimation::Interpolator>(func), qMetaTypeId<T>());
+}
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QANIMATION_H
diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h
new file mode 100644
index 0000000..e468ac9
--- /dev/null
+++ b/src/corelib/animation/qvariantanimation_p.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATION_P_H
+#define QANIMATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QIODevice. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qvariantanimation.h"
+#if defined(QT_EXPERIMENTAL_SOLUTION)
+# include "qeasingcurve.h"
+#else
+# include <QtCore/qeasingcurve.h>
+#endif
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvector.h>
+
+#include "qabstractanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_CORE_EXPORT QVariantAnimationPrivate : public QAbstractAnimationPrivate
+{
+ Q_DECLARE_PUBLIC(QVariantAnimation)
+public:
+
+ QVariantAnimationPrivate() : duration(250), hasStartValue(false)
+ {
+ }
+
+ void init()
+ {
+ //we keep the mask so that we emit valueChanged only when needed (for performance reasons)
+ changedSignalMask = (1 << q_func()->metaObject()->indexOfSignal("valueChanged(QVariant)"));
+ currentInterval.start.first = currentInterval.end.first = 2; //will force the initial refresh
+ interpolator = 0;
+ }
+
+ static QVariantAnimationPrivate *get(QVariantAnimation *q)
+ {
+ return q->d_func();
+ }
+
+
+ //some helper functions
+ bool atBeginning() const
+ {
+ return currentTime == 0;
+ }
+
+ bool atEnd() const
+ {
+ return currentTime == duration && currentIteration == (iterationCount - 1);
+ }
+
+ void setDefaultStartValue(const QVariant &value);
+
+ int duration;
+ QEasingCurve easing;
+
+ QVariantAnimation::KeyValues keyValues;
+ QVariant currentValue;
+ QVariant defaultStartValue;
+ bool hasStartValue;
+
+ //this is used to keep track of the KeyValue interval in which we currently are
+ struct
+ {
+ QVariantAnimation::KeyValue start, end;
+ } currentInterval;
+
+ mutable QVariantAnimation::Interpolator interpolator;
+
+ quint32 changedSignalMask;
+
+ void updateCurrentValue();
+ void setValueAt(qreal, const QVariant &);
+ QVariant valueAt(qreal step) const;
+ void convertValues(int t);
+};
+
+//this should make the interpolation faster
+template<typename T> inline T _q_interpolate(const T &f, const T &t, qreal progress)
+{
+ return T(f + (t - f) * progress);
+}
+
+template<typename T > inline QVariant _q_interpolateVariant(const T &from, const T &to, qreal progress)
+{
+ return _q_interpolate(from, to, progress);
+}
+
+
+QT_END_NAMESPACE
+
+#endif //QANIMATION_P_H
diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h
index 7584b84..af76903 100644
--- a/src/corelib/arch/qatomic_bootstrap.h
+++ b/src/corelib/arch/qatomic_bootstrap.h
@@ -92,6 +92,20 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValu
return false;
}
+template <typename T>
+Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue)
+{
+ T *currentValue = _q_value;
+ _q_value = newValue;
+ return currentValue;
+}
+
+template <typename T>
+Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue)
+{
+ return testAndSetOrdered(expectedValue, newValue);
+}
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro
index f99d57f..db51d43 100644
--- a/src/corelib/corelib.pro
+++ b/src/corelib/corelib.pro
@@ -5,6 +5,7 @@ DEFINES += QT_BUILD_CORE_LIB QT_NO_USING_NAMESPACE
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x67000000
include(../qbase.pri)
+include(animation/animation.pri)
include(arch/arch.pri)
include(concurrent/concurrent.pri)
include(global/global.pri)
@@ -14,6 +15,7 @@ include(io/io.pri)
include(plugin/plugin.pri)
include(kernel/kernel.pri)
include(codecs/codecs.pri)
+include(statemachine/statemachine.pri)
include(xml/xml.pri)
mac|darwin:LIBS += -framework ApplicationServices
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index f058b36..517efe3 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -128,6 +128,22 @@ namespace QT_NAMESPACE {}
#endif /* __cplusplus */
+/**
+ * For animation framework to work seamlessly as a solution
+ */
+#if 0
+# define QT_EXPERIMENTAL_BEGIN_NAMESPACE namespace QtExperimental {
+# define QT_EXPERIMENTAL_END_NAMESPACE }
+# define QT_EXPERIMENTAL_USE_NAMESPACE using namespace QtExperimental;
+# define QT_EXPERIMENTAL_PREPEND_NAMESPACE(name) QtExperimental::name
+namespace QtExperimental {}
+#else
+# define QT_EXPERIMENTAL_BEGIN_NAMESPACE
+# define QT_EXPERIMENTAL_END_NAMESPACE
+# define QT_EXPERIMENTAL_USE_NAMESPACE
+# define QT_EXPERIMENTAL_PREPEND_NAMESPACE(name) name
+#endif
+
#if defined(Q_OS_MAC) && !defined(Q_CC_INTEL)
#define QT_BEGIN_HEADER extern "C++" {
#define QT_END_HEADER }
@@ -1132,6 +1148,11 @@ class QDataStream;
# else
# define Q_SVG_EXPORT Q_DECL_IMPORT
# endif
+# if defined(QT_BUILD_DECLARATIVE_LIB)
+# define Q_DECLARATIVE_EXPORT Q_DECL_EXPORT
+# else
+# define Q_DECLARATIVE_EXPORT Q_DECL_IMPORT
+# endif
# if defined(QT_BUILD_OPENGL_LIB)
# define Q_OPENGL_EXPORT Q_DECL_EXPORT
# else
@@ -1174,6 +1195,7 @@ class QDataStream;
# define Q_SQL_EXPORT Q_DECL_IMPORT
# define Q_NETWORK_EXPORT Q_DECL_IMPORT
# define Q_SVG_EXPORT Q_DECL_IMPORT
+# define Q_DECLARATIVE_EXPORT Q_DECL_IMPORT
# define Q_CANVAS_EXPORT Q_DECL_IMPORT
# define Q_OPENGL_EXPORT Q_DECL_IMPORT
# define Q_XML_EXPORT Q_DECL_IMPORT
@@ -1200,6 +1222,7 @@ class QDataStream;
# define Q_SQL_EXPORT Q_DECL_EXPORT
# define Q_NETWORK_EXPORT Q_DECL_EXPORT
# define Q_SVG_EXPORT Q_DECL_EXPORT
+# define Q_DECLARATIVE_EXPORT Q_DECL_EXPORT
# define Q_OPENGL_EXPORT Q_DECL_EXPORT
# define Q_XML_EXPORT Q_DECL_EXPORT
# define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT
@@ -1212,6 +1235,7 @@ class QDataStream;
# define Q_SQL_EXPORT
# define Q_NETWORK_EXPORT
# define Q_SVG_EXPORT
+# define Q_DECLARATIVE_EXPORT
# define Q_OPENGL_EXPORT
# define Q_XML_EXPORT
# define Q_XMLPATTERNS_EXPORT
@@ -2246,6 +2270,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
#define QT_MODULE_TEST 0x04000
#define QT_MODULE_DBUS 0x08000
#define QT_MODULE_SCRIPTTOOLS 0x10000
+#define QT_MODULE_DECLARATIVE 0x20000
/* Qt editions */
#define QT_EDITION_CONSOLE (QT_MODULE_CORE \
@@ -2273,6 +2298,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
| QT_MODULE_QT3SUPPORTLIGHT \
| QT_MODULE_QT3SUPPORT \
| QT_MODULE_SVG \
+ | QT_MODULE_DECLARATIVE \
| QT_MODULE_GRAPHICSVIEW \
| QT_MODULE_HELP \
| QT_MODULE_TEST \
@@ -2335,6 +2361,9 @@ QT_LICENSED_MODULE(Qt3Support)
#if (QT_EDITION & QT_MODULE_SVG)
QT_LICENSED_MODULE(Svg)
#endif
+#if (QT_EDITION & QT_MODULE_DECLARATIVE)
+QT_LICENSED_MODULE(Declarative)
+#endif
#if (QT_EDITION & QT_MODULE_ACTIVEQT)
QT_LICENSED_MODULE(ActiveQt)
#endif
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index d90ecae..3988289 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -12,7 +12,7 @@ HEADERS += \
kernel/qcoreevent.h \
kernel/qmetaobject.h \
kernel/qmetatype.h \
- kernel/qmimedata.h \
+ kernel/qmimedata.h \
kernel/qobject.h \
kernel/qobjectdefs.h \
kernel/qsignalmapper.h \
@@ -27,12 +27,13 @@ HEADERS += \
kernel/qvariant_p.h \
kernel/qmetaobject_p.h \
kernel/qobject_p.h \
- kernel/qcoreglobaldata_p.h \
- kernel/qsharedmemory.h \
+ kernel/qcoreglobaldata_p.h \
+ kernel/qsharedmemory.h \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
kernel/qsystemsemaphore_p.h \
- kernel/qfunctions_p.h
+ kernel/qfunctions_p.h \
+ kernel/qmetaobjectbuilder_p.h
SOURCES += \
kernel/qabstracteventdispatcher.cpp \
@@ -43,7 +44,7 @@ SOURCES += \
kernel/qcoreevent.cpp \
kernel/qmetaobject.cpp \
kernel/qmetatype.cpp \
- kernel/qmimedata.cpp \
+ kernel/qmimedata.cpp \
kernel/qobject.cpp \
kernel/qobjectcleanuphandler.cpp \
kernel/qsignalmapper.cpp \
@@ -51,9 +52,10 @@ SOURCES += \
kernel/qtimer.cpp \
kernel/qtranslator.cpp \
kernel/qvariant.cpp \
- kernel/qcoreglobaldata.cpp \
- kernel/qsharedmemory.cpp \
- kernel/qsystemsemaphore.cpp
+ kernel/qcoreglobaldata.cpp \
+ kernel/qsharedmemory.cpp \
+ kernel/qsystemsemaphore.cpp \
+ kernel/qmetaobjectbuilder.cpp
win32 {
SOURCES += \
diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp
index fd0e105..a23c137 100644
--- a/src/corelib/kernel/qabstractitemmodel.cpp
+++ b/src/corelib/kernel/qabstractitemmodel.cpp
@@ -467,6 +467,21 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel()
return qEmptyModel();
}
+const QHash<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames()
+{
+ static QHash<int,QByteArray> roleNames;
+ if (roleNames.isEmpty()) {
+ roleNames[Qt::DisplayRole] = "Display";
+ roleNames[Qt::DecorationRole] = "Decoration";
+ roleNames[Qt::EditRole] = "Edit";
+ roleNames[Qt::ToolTipRole] = "ToolTip";
+ roleNames[Qt::StatusTipRole] = "StatusTip";
+ roleNames[Qt::WhatsThisRole] = "WhatsThis";
+ }
+
+ return roleNames;
+}
+
void QAbstractItemModelPrivate::removePersistentIndexData(QPersistentModelIndexData *data)
{
if (data->index.isValid()) {
@@ -1832,6 +1847,22 @@ QSize QAbstractItemModel::span(const QModelIndex &) const
}
/*!
+*/
+void QAbstractItemModel::setRoleNames(const QHash<int,QByteArray> &roleNames)
+{
+ Q_D(QAbstractItemModel);
+ d->roleNames = roleNames;
+}
+
+/*!
+*/
+const QHash<int,QByteArray> &QAbstractItemModel::roleNames() const
+{
+ Q_D(const QAbstractItemModel);
+ return d->roleNames;
+}
+
+/*!
Called to let the model know that it should submit whatever it has cached
to the permanent storage. Typically used for row editing.
diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h
index b062768..00cd817 100644
--- a/src/corelib/kernel/qabstractitemmodel.h
+++ b/src/corelib/kernel/qabstractitemmodel.h
@@ -220,6 +220,9 @@ public:
Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
virtual QSize span(const QModelIndex &index) const;
+ void setRoleNames(const QHash<int,QByteArray> &roleNames);
+ const QHash<int,QByteArray> &roleNames() const;
+
#ifdef Q_NO_USING_KEYWORD
inline QObject *parent() const { return QObject::parent(); }
#else
diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h
index df1a6ce..10d3793 100644
--- a/src/corelib/kernel/qabstractitemmodel_p.h
+++ b/src/corelib/kernel/qabstractitemmodel_p.h
@@ -78,7 +78,7 @@ class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QAbstractItemModel)
public:
- QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1) {}
+ QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1), roleNames(defaultRoleNames()) {}
void removePersistentIndexData(QPersistentModelIndexData *data);
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void rowsInserted(const QModelIndex &parent, int first, int last);
@@ -143,6 +143,9 @@ public:
} persistent;
Qt::DropActions supportedDragActions;
+
+ QHash<int,QByteArray> roleNames;
+ static const QHash<int,QByteArray> &defaultRoleNames();
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index fa472e6..5e76976 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -44,6 +44,7 @@
#include <QtCore/qnamespace.h>
#include <QtCore/qbytearray.h>
+#include <QtCore/qobjectdefs.h>
QT_BEGIN_HEADER
@@ -54,7 +55,9 @@ QT_MODULE(Core)
class QEventPrivate;
class Q_CORE_EXPORT QEvent // event base class
{
+ Q_GADGET
QDOC_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+ Q_ENUMS(Type)
public:
enum Type {
/*
@@ -266,7 +269,11 @@ public:
CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window
MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear
- // 512 reserved for Qt Jambi's MetaCall event
+ Signal = 191,
+ StateFinished = 192,
+ Bound = 193,
+
+ // 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
User = 1000, // first user event id
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index b65f956..35ccde1 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -159,7 +159,8 @@ enum PropertyFlags {
ResolveEditable = 0x00080000,
User = 0x00100000,
ResolveUser = 0x00200000,
- Notify = 0x00400000
+ Notify = 0x00400000,
+ Dynamic = 0x00800000
};
enum MethodFlags {
@@ -179,6 +180,10 @@ enum MethodFlags {
MethodScriptable = 0x40
};
+enum MetaObjectFlags {
+ DynamicMetaObject = 0x01
+};
+
struct QMetaObjectPrivate
{
int revision;
@@ -188,6 +193,7 @@ struct QMetaObjectPrivate
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
+ int flags;
};
static inline const QMetaObjectPrivate *priv(const uint* data)
@@ -271,6 +277,17 @@ int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
}
/*!
+ \internal
+*/
+int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
+{
+ if (QMetaObject *mo = object->d_ptr->metaObject)
+ return static_cast<QAbstractDynamicMetaObject*>(mo)->metaCall(cl, idx, argv);
+ else
+ return object->qt_metacall(cl, idx, argv);
+}
+
+/*!
\fn const char *QMetaObject::className() const
Returns the class name.
@@ -690,6 +707,14 @@ int QMetaObject::indexOfProperty(const char *name) const
}
m = m->d.superdata;
}
+
+ if (i == -1 && priv(this->d.data)->revision >= 3 && (priv(this->d.data)->flags & DynamicMetaObject)){
+ QAbstractDynamicMetaObject *me =
+ const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(this));
+
+ i = me->createProperty(name, 0);
+ }
+
return i;
}
@@ -1320,6 +1345,16 @@ int QMetaMethod::attributes() const
}
/*!
+ Returns this method's index.
+*/
+int QMetaMethod::methodIndex() const
+{
+ if (!mobj)
+ return -1;
+ return ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
+}
+
+/*!
Returns the access specification of this method (private,
protected, or public).
@@ -1519,7 +1554,7 @@ bool QMetaMethod::invoke(QObject *object,
// recompute the methodIndex by reversing the arithmetic in QMetaObject::property()
int methodIndex = ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
if (connectionType == Qt::DirectConnection) {
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
} else {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
@@ -2029,6 +2064,16 @@ int QMetaProperty::userType() const
}
/*!
+ Returns this property's index.
+*/
+int QMetaProperty::propertyIndex() const
+{
+ if (!mobj)
+ return -1;
+ return ((handle - priv(mobj->d.data)->propertyData) / 3) + mobj->propertyOffset();
+}
+
+/*!
Returns true if the property's type is an enumeration value that
is used as a flag; otherwise returns false.
@@ -2133,9 +2178,8 @@ QVariant QMetaProperty::read(const QObject *object) const
value = QVariant(t, (void*)0);
argv[0] = value.data();
}
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::ReadProperty,
- idx + mobj->propertyOffset(),
- argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty,
+ idx + mobj->propertyOffset(), argv);
if (argv[1] == 0)
// "value" was changed
return value;
@@ -2200,7 +2244,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
argv[0] = &v;
else
argv[0] = v.data();
- object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
return true;
}
@@ -2217,7 +2261,7 @@ bool QMetaProperty::reset(QObject *object) const
if (!object || !mobj || !isResettable())
return false;
void *argv[] = { 0 };
- object->qt_metacall(QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
return true;
}
@@ -2329,8 +2373,8 @@ bool QMetaProperty::isDesignable(const QObject *object) const
bool b = flags & Designable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyDesignable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyDesignable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
@@ -2355,8 +2399,8 @@ bool QMetaProperty::isScriptable(const QObject *object) const
bool b = flags & Scriptable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyScriptable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyScriptable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2379,8 +2423,8 @@ bool QMetaProperty::isStored(const QObject *object) const
bool b = flags & Stored;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyStored,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyStored,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2406,13 +2450,24 @@ bool QMetaProperty::isUser(const QObject *object) const
bool b = flags & User;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyUser,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyUser,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
/*!
+ \internal
+*/
+bool QMetaProperty::isDynamic() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Dynamic;
+}
+
+/*!
\obsolete
Returns true if the property is editable for the given \a object;
@@ -2432,8 +2487,8 @@ bool QMetaProperty::isEditable(const QObject *object) const
bool b = flags & Editable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyEditable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyEditable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 18c488a..26e8b53 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -69,6 +69,7 @@ public:
MethodType methodType() const;
enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
int attributes() const;
+ int methodIndex() const;
inline const QMetaObject *enclosingMetaObject() const { return mobj; }
@@ -178,6 +179,7 @@ public:
const char *typeName() const;
QVariant::Type type() const;
int userType() const;
+ int propertyIndex() const;
bool isReadable() const;
bool isWritable() const;
@@ -187,6 +189,7 @@ public:
bool isStored(const QObject *obj = 0) const;
bool isEditable(const QObject *obj = 0) const;
bool isUser(const QObject *obj = 0) const;
+ bool isDynamic() const;
bool isFlagType() const;
bool isEnumType() const;
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
new file mode 100644
index 0000000..43d001f
--- /dev/null
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -0,0 +1,2438 @@
+/****************************************************************************
+**
+** This file is part of the $PACKAGE_NAME$.
+**
+** Copyright (C) $THISYEAR$ $COMPANY_NAME$.
+**
+** $QT_EXTENDED_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qmetaobjectbuilder_p.h"
+#include <QDebug>
+
+/*!
+ \class QMetaObjectBuilder
+ \brief The QMetaObjectBuilder class supports the building of QMetaObject objects at runtime.
+
+ See the QDynamicMetaObject class documentation for an example
+ of using this class.
+
+ \sa QDynamicMetaObject, QDynamicObject
+*/
+
+/*!
+ \enum QMetaObjectBuilder::AddMember
+ This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject()
+
+ \value ClassName Add the class name.
+ \value SuperClass Add the super class.
+ \value Methods Add methods that aren't signals or slots.
+ \value Signals Add signals.
+ \value Slots Add slots.
+ \value Constructors Add constructors.
+ \value Properties Add properties.
+ \value Enumerators Add enumerators.
+ \value ClassInfos Add items of class information.
+ \value RelatedMetaObjects Add related meta objects.
+ \value StaticMetacall Add the static metacall function.
+ \value PublicMethods Add public methods (ignored for signals).
+ \value ProtectedMethods Add protected methods (ignored for signals).
+ \value PrivateMethods All private methods (ignored for signals).
+ \value AllMembers Add all members.
+ \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function.
+*/
+
+// copied from moc's generator.cpp
+uint qvariant_nameToType(const char* name)
+{
+ if (!name)
+ return 0;
+
+ if (strcmp(name, "QVariant") == 0)
+ return 0xffffffff;
+ if (strcmp(name, "QCString") == 0)
+ return QMetaType::QByteArray;
+ if (strcmp(name, "Q_LLONG") == 0)
+ return QMetaType::LongLong;
+ if (strcmp(name, "Q_ULLONG") == 0)
+ return QMetaType::ULongLong;
+ if (strcmp(name, "QIconSet") == 0)
+ return QMetaType::QIcon;
+
+ uint tp = QMetaType::type(name);
+ return tp < QMetaType::User ? tp : 0;
+}
+
+/*
+ Returns true if the type is a QVariant types.
+*/
+bool isVariantType(const char* type)
+{
+ return qvariant_nameToType(type) != 0;
+}
+
+// copied from qmetaobject.cpp
+// do not touch without touching the moc as well
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ Notify = 0x00400000,
+ Dynamic = 0x00800000
+};
+
+enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodConstructor = 0x0c,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+};
+
+static inline const QMetaObjectPrivate *priv(const uint* data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+// end of copied lines from qmetaobject.cpp
+
+class QMetaMethodBuilderPrivate
+{
+public:
+ QMetaMethodBuilderPrivate
+ (QMetaMethod::MethodType _methodType,
+ const QByteArray& _signature,
+ const QByteArray& _returnType = QByteArray(),
+ QMetaMethod::Access _access = QMetaMethod::Public)
+ : signature(QMetaObject::normalizedSignature(_signature.constData())),
+ returnType(QMetaObject::normalizedType(_returnType)),
+ attributes(((int)_access) | (((int)_methodType) << 2))
+ {
+ }
+
+ QByteArray signature;
+ QByteArray returnType;
+ QList<QByteArray> parameterNames;
+ QByteArray tag;
+ int attributes;
+
+ QMetaMethod::MethodType methodType() const
+ {
+ return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2);
+ }
+
+ QMetaMethod::Access access() const
+ {
+ return (QMetaMethod::Access)(attributes & AccessMask);
+ }
+
+ void setAccess(QMetaMethod::Access value)
+ {
+ attributes = ((attributes & ~AccessMask) | (int)value);
+ }
+};
+
+class QMetaPropertyBuilderPrivate
+{
+public:
+ QMetaPropertyBuilderPrivate
+ (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1)
+ : name(_name),
+ type(QMetaObject::normalizedType(_type.constData())),
+ flags(Readable | Writable), notifySignal(-1)
+ {
+ if (notifierIdx >= 0) {
+ flags |= Notify;
+ notifySignal = notifierIdx;
+ }
+ }
+
+ QByteArray name;
+ QByteArray type;
+ int flags;
+ int notifySignal;
+
+ bool flag(int f) const
+ {
+ return ((flags & f) != 0);
+ }
+
+ void setFlag(int f, bool value)
+ {
+ if (value)
+ flags |= f;
+ else
+ flags &= ~f;
+ }
+};
+
+class QMetaEnumBuilderPrivate
+{
+public:
+ QMetaEnumBuilderPrivate(const QByteArray& _name)
+ : name(_name), isFlag(false)
+ {
+ }
+
+ QByteArray name;
+ bool isFlag;
+ QList<QByteArray> keys;
+ QList<int> values;
+};
+
+class QMetaObjectBuilderPrivate
+{
+public:
+ QMetaObjectBuilderPrivate()
+ : flags(0)
+ {
+ superClass = &QObject::staticMetaObject;
+ staticMetacallFunction = 0;
+ }
+
+ QByteArray className;
+ const QMetaObject *superClass;
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction;
+ QList<QMetaMethodBuilderPrivate> methods;
+ QList<QMetaMethodBuilderPrivate> constructors;
+ QList<QMetaPropertyBuilderPrivate> properties;
+ QList<QByteArray> classInfoNames;
+ QList<QByteArray> classInfoValues;
+ QList<QMetaEnumBuilderPrivate> enumerators;
+ QList<const QMetaObject *> relatedMetaObjects;
+ int flags;
+};
+
+/*!
+ Constructs a new QMetaObjectBuilder.
+*/
+QMetaObjectBuilder::QMetaObjectBuilder()
+{
+ d = new QMetaObjectBuilderPrivate();
+}
+
+/*!
+ Constructs a new QMetaObjectBuilder which is a copy of the
+ meta object information in \a prototype. Note: the super class
+ contents for \a prototype are not copied, only the immediate
+ class that is defined by \a prototype.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+
+ \sa addMetaObject()
+*/
+QMetaObjectBuilder::QMetaObjectBuilder
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ d = new QMetaObjectBuilderPrivate();
+ addMetaObject(prototype, members);
+}
+
+/*!
+ Destroys this meta object builder.
+*/
+QMetaObjectBuilder::~QMetaObjectBuilder()
+{
+ delete d;
+}
+
+/*!
+ Returns the name of the class being constructed by this
+ meta object builder. The default value is an empty QByteArray.
+
+ \sa setClassName(), superClass()
+*/
+QByteArray QMetaObjectBuilder::className() const
+{
+ return d->className;
+}
+
+/*!
+ Sets the \a name of the class being constructed by this
+ meta object builder.
+
+ \sa className(), setSuperClass()
+*/
+void QMetaObjectBuilder::setClassName(const QByteArray& name)
+{
+ d->className = name;
+}
+
+/*!
+ Returns the superclass meta object of the class being constructed
+ by this meta object builder. The default value is the meta object
+ for QObject.
+
+ \sa setSuperClass(), className()
+*/
+const QMetaObject *QMetaObjectBuilder::superClass() const
+{
+ return d->superClass;
+}
+
+/*!
+ Sets the superclass meta object of the class being constructed
+ by this meta object builder to \a meta. The \a meta parameter
+ must not be null.
+
+ \sa superClass(), setClassName()
+*/
+void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta)
+{
+ Q_ASSERT(meta);
+ d->superClass = meta;
+}
+
+/*!
+ Returns the flags of the class being constructed by this meta object
+ builder.
+
+ \sa setFlags()
+*/
+QMetaObjectBuilder::MetaObjectFlags QMetaObjectBuilder::flags() const
+{
+ return (QMetaObjectBuilder::MetaObjectFlags)d->flags;
+}
+
+/*!
+ Sets the \a flags of the class being constructed by this meta object
+ builder.
+
+ \sa flags()
+*/
+void QMetaObjectBuilder::setFlags(MetaObjectFlags flags)
+{
+ d->flags = flags;
+}
+
+/*!
+ Returns the number of methods in this class, excluding the number
+ of methods in the base class. These include signals and slots
+ as well as normal member functions.
+
+ \sa addMethod(), method(), removeMethod(), indexOfMethod()
+*/
+int QMetaObjectBuilder::methodCount() const
+{
+ return d->methods.size();
+}
+
+/*!
+ Returns the number of constructors in this class.
+
+ \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor()
+*/
+int QMetaObjectBuilder::constructorCount() const
+{
+ return d->constructors.size();
+}
+
+/*!
+ Returns the number of properties in this class, excluding the number
+ of properties in the base class.
+
+ \sa addProperty(), property(), removeProperty(), indexOfProperty()
+*/
+int QMetaObjectBuilder::propertyCount() const
+{
+ return d->properties.size();
+}
+
+/*!
+ Returns the number of enumerators in this class, excluding the
+ number of enumerators in the base class.
+
+ \sa addEnumerator(), enumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+int QMetaObjectBuilder::enumeratorCount() const
+{
+ return d->enumerators.size();
+}
+
+/*!
+ Returns the number of items of class information in this class,
+ exclusing the number of items of class information in the base class.
+
+ \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::classInfoCount() const
+{
+ return d->classInfoNames.size();
+}
+
+/*!
+ Returns the number of related meta objects that are associated
+ with this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa addRelatedMetaObject(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+int QMetaObjectBuilder::relatedMetaObjectCount() const
+{
+ return d->relatedMetaObjects.size();
+}
+
+/*!
+ Adds a new public method to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the method. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class with the specified
+ \a signature and \a returnType. Returns an object that can be
+ used to adjust the other attributes of the method. The \a signature
+ and \a returnType will be normalized before they are added to
+ the class. If \a returnType is empty, then it indicates that
+ the method has \c{void} as its return type.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod
+ (const QByteArray& signature, const QByteArray& returnType)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Method, signature, returnType));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class that has the same information as
+ \a prototype. This is used to clone the methods of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the method.
+
+ This function will detect if \a prototype is an ordinary method,
+ signal, slot, or constructor and act accordingly.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype)
+{
+ QMetaMethodBuilder method;
+ if (prototype.methodType() == QMetaMethod::Method)
+ method = addMethod(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Signal)
+ method = addSignal(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Slot)
+ method = addSlot(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Constructor)
+ method = addConstructor(prototype.signature());
+ method.setReturnType(prototype.typeName());
+ method.setParameterNames(prototype.parameterNames());
+ method.setTag(prototype.tag());
+ method.setAccess(prototype.access());
+ method.setAttributes(prototype.attributes());
+ return method;
+}
+
+/*!
+ Adds a new public slot to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the slot. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSignal(), indexOfSlot()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new signal to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the signal. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSlot(), indexOfSignal()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new constructor to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the constructor. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature)
+{
+ int index = d->constructors.size();
+ d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature));
+ return QMetaMethodBuilder(this, -(index + 1));
+}
+
+/*!
+ Adds a new constructor to this class that has the same information as
+ \a prototype. This is used to clone the constructors of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the constructor.
+
+ This function requires that \a prototype be a constructor.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype)
+{
+ Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor);
+ QMetaMethodBuilder ctor = addConstructor(prototype.signature());
+ ctor.setReturnType(prototype.typeName());
+ ctor.setParameterNames(prototype.parameterNames());
+ ctor.setTag(prototype.tag());
+ ctor.setAccess(prototype.access());
+ ctor.setAttributes(prototype.attributes());
+ return ctor;
+}
+
+/*!
+ Adds a new readable/writable property to this class with the specified
+ \a name and \a type. Returns an object that can be used to adjust
+ the other attributes of the property. The \a type will be
+ normalized before it is added to the class.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty
+ (const QByteArray& name, const QByteArray& type, int notifierId)
+{
+ int index = d->properties.size();
+ d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId));
+ return QMetaPropertyBuilder(this, index);
+}
+
+/*!
+ Adds a new property to this class that has the same information as
+ \a prototype. This is used to clone the properties of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the property.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype)
+{
+ QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName());
+ property.setReadable(prototype.isReadable());
+ property.setWritable(prototype.isWritable());
+ property.setResettable(prototype.isResettable());
+ property.setDesignable(prototype.isDesignable());
+ property.setScriptable(prototype.isScriptable());
+ property.setStored(prototype.isStored());
+ property.setEditable(prototype.isEditable());
+ property.setUser(prototype.isUser());
+ property.setStdCppSet(prototype.hasStdCppSet());
+ property.setEnumOrFlag(prototype.isEnumType());
+ if (prototype.hasNotifySignal()) {
+ // Find an existing method for the notify signal, or add a new one.
+ QMetaMethod method = prototype.notifySignal();
+ int index = indexOfMethod(method.signature());
+ if (index == -1)
+ index = addMethod(method).index();
+ d->properties[property._index].notifySignal = index;
+ d->properties[property._index].setFlag(Notify, true);
+ }
+ return property;
+}
+
+/*!
+ Adds a new enumerator to this class with the specified
+ \a name. Returns an object that can be used to adjust
+ the other attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name)
+{
+ int index = d->enumerators.size();
+ d->enumerators.append(QMetaEnumBuilderPrivate(name));
+ return QMetaEnumBuilder(this, index);
+}
+
+/*!
+ Adds a new enumerator to this class that has the same information as
+ \a prototype. This is used to clone the enumerators of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
+{
+ QMetaEnumBuilder en = addEnumerator(prototype.name());
+ en.setIsFlag(prototype.isFlag());
+ int count = prototype.keyCount();
+ for (int index = 0; index < count; ++index)
+ en.addKey(prototype.key(index), prototype.value(index));
+ return en;
+}
+
+/*!
+ Adds \a name and \a value as an item of class information to this class.
+ Returns the index of the new item of class information.
+
+ \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value)
+{
+ int index = d->classInfoNames.size();
+ d->classInfoNames += name;
+ d->classInfoValues += value;
+ return index;
+}
+
+/*!
+ Adds \a meta to this class as a related meta object. Returns
+ the index of the new related meta object entry.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta)
+{
+ Q_ASSERT(meta);
+ int index = d->relatedMetaObjects.size();
+ d->relatedMetaObjects.append(meta);
+ return index;
+}
+
+/*!
+ Adds the contents of \a prototype to this meta object builder.
+ This function is useful for cloning the contents of an existing QMetaObject.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+*/
+void QMetaObjectBuilder::addMetaObject
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ Q_ASSERT(prototype);
+ int index;
+
+ if ((members & ClassName) != 0)
+ d->className = prototype->className();
+
+ if ((members & SuperClass) != 0)
+ d->superClass = prototype->superClass();
+
+ if ((members & (Methods | Signals | Slots)) != 0) {
+ for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) {
+ QMetaMethod method = prototype->method(index);
+ if (method.methodType() != QMetaMethod::Signal) {
+ if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0)
+ continue;
+ }
+ if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Signal &&
+ (members & Signals) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Slot &&
+ (members & Slots) != 0) {
+ addMethod(method);
+ }
+ }
+ }
+
+ if ((members & Constructors) != 0) {
+ for (index = 0; index < prototype->constructorCount(); ++index)
+ addConstructor(prototype->constructor(index));
+ }
+
+ if ((members & Properties) != 0) {
+ for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index)
+ addProperty(prototype->property(index));
+ }
+
+ if ((members & Enumerators) != 0) {
+ for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index)
+ addEnumerator(prototype->enumerator(index));
+ }
+
+ if ((members & ClassInfos) != 0) {
+ for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) {
+ QMetaClassInfo ci = prototype->classInfo(index);
+ addClassInfo(ci.name(), ci.value());
+ }
+ }
+
+ if ((members & RelatedMetaObjects) != 0) {
+ const QMetaObject **objects;
+ if (priv(prototype->d.data)->revision < 2) {
+ objects = (const QMetaObject **)(prototype->d.extradata);
+ } else {
+ const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra)
+ objects = extra->objects;
+ else
+ objects = 0;
+ }
+ if (objects) {
+ while (*objects != 0) {
+ addRelatedMetaObject(*objects);
+ ++objects;
+ }
+ }
+ }
+
+ if ((members & StaticMetacall) != 0) {
+ if (priv(prototype->d.data)->revision >= 2) {
+ const QMetaObjectExtraData *extra =
+ (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra && extra->static_metacall)
+ setStaticMetacallFunction(extra->static_metacall);
+ }
+ }
+}
+
+/*!
+ Returns the method at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::method(int index) const
+{
+ if (index >= 0 && index < d->methods.size())
+ return QMetaMethodBuilder(this, index);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the constructor at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const
+{
+ if (index >= 0 && index < d->constructors.size())
+ return QMetaMethodBuilder(this, -(index + 1));
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the property at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const
+{
+ if (index >= 0 && index < d->properties.size())
+ return QMetaPropertyBuilder(this, index);
+ else
+ return QMetaPropertyBuilder();
+}
+
+/*!
+ Returns the enumerator at \a index in this class.
+
+ \sa enumeratorCount(), addEnumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const
+{
+ if (index >= 0 && index < d->enumerators.size())
+ return QMetaEnumBuilder(this, index);
+ else
+ return QMetaEnumBuilder();
+}
+
+/*!
+ Returns the related meta object at \a index in this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+ return d->relatedMetaObjects[index];
+ else
+ return 0;
+}
+
+/*!
+ Returns the name of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoName(int index) const
+{
+ if (index >= 0 && index < d->classInfoNames.size())
+ return d->classInfoNames[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoValue(int index) const
+{
+ if (index >= 0 && index < d->classInfoValues.size())
+ return d->classInfoValues[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Removes the method at \a index from this class. The indices of
+ all following methods will be adjusted downwards by 1. If the
+ method is registered as a notify signal on a property, then the
+ notify signal will be removed from the property.
+
+ \sa methodCount(), addMethod(), method(), indexOfMethod()
+*/
+void QMetaObjectBuilder::removeMethod(int index)
+{
+ if (index >= 0 && index < d->methods.size()) {
+ d->methods.removeAt(index);
+ for (int prop = 0; prop < d->properties.size(); ++prop) {
+ // Adjust the indices of property notify signal references.
+ if (d->properties[prop].notifySignal == index)
+ d->properties[prop].notifySignal = -1;
+ else if (d->properties[prop].notifySignal > index)
+ (d->properties[prop].notifySignal)--;
+ }
+ }
+}
+
+/*!
+ Removes the constructor at \a index from this class. The indices of
+ all following constructors will be adjusted downwards by 1.
+
+ \sa constructorCount(), addConstructor(), constructor()
+ \sa indexOfConstructor()
+*/
+void QMetaObjectBuilder::removeConstructor(int index)
+{
+ if (index >= 0 && index < d->constructors.size())
+ d->constructors.removeAt(index);
+}
+
+/*!
+ Removes the property at \a index from this class. The indices of
+ all following properties will be adjusted downwards by 1.
+
+ \sa propertyCount(), addProperty(), property(), indexOfProperty()
+*/
+void QMetaObjectBuilder::removeProperty(int index)
+{
+ if (index >= 0 && index < d->properties.size())
+ d->properties.removeAt(index);
+}
+
+/*!
+ Removes the enumerator at \a index from this class. The indices of
+ all following enumerators will be adjusted downwards by 1.
+
+ \sa enumertorCount(), addEnumerator(), enumerator()
+ \sa indexOfEnumerator()
+*/
+void QMetaObjectBuilder::removeEnumerator(int index)
+{
+ if (index >= 0 && index < d->enumerators.size())
+ d->enumerators.removeAt(index);
+}
+
+/*!
+ Removes the item of class information at \a index from this class.
+ The indices of all following items will be adjusted downwards by 1.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue()
+ \sa indexOfClassInfo()
+*/
+void QMetaObjectBuilder::removeClassInfo(int index)
+{
+ if (index >= 0 && index < d->classInfoNames.size()) {
+ d->classInfoNames.removeAt(index);
+ d->classInfoValues.removeAt(index);
+ }
+}
+
+/*!
+ Removes the related meta object at \a index from this class.
+ The indices of all following related meta objects will be adjusted
+ downwards by 1.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa relatedMetaObject()
+*/
+void QMetaObjectBuilder::removeRelatedMetaObject(int index)
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+ d->relatedMetaObjects.removeAt(index);
+}
+
+/*!
+ Finds a method with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa method(), methodCount(), addMethod(), removeMethod()
+*/
+int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a signal with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSlot()
+*/
+int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Signal)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a slot with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSignal()
+*/
+int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Slot)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a constructor with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa constructor(), constructorCount(), addConstructor(), removeConstructor()
+*/
+int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->constructors.size(); ++index) {
+ if (sig == d->constructors[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a property with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa property(), propertyCount(), addProperty(), removeProperty()
+*/
+int QMetaObjectBuilder::indexOfProperty(const QByteArray& name)
+{
+ for (int index = 0; index < d->properties.size(); ++index) {
+ if (name == d->properties[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an enumerator with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator()
+*/
+int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name)
+{
+ for (int index = 0; index < d->enumerators.size(); ++index) {
+ if (name == d->enumerators[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an item of class information with the specified \a name and
+ returns its index; otherwise returns -1.
+
+ \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo()
+ \sa removeClassInfo()
+*/
+int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name)
+{
+ for (int index = 0; index < d->classInfoNames.size(); ++index) {
+ if (name == d->classInfoNames[index])
+ return index;
+ }
+ return -1;
+}
+
+// Align on a specific type boundary.
+#define ALIGN(size,type) \
+ (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1)
+
+// Build a string into a QMetaObject representation. Returns the
+// position in the string table where the string was placed.
+static int buildString
+ (char *buf, char *str, int *offset, const QByteArray& value, int empty)
+{
+ if (value.size() == 0 && empty >= 0)
+ return empty;
+ if (buf) {
+ memcpy(str + *offset, value.constData(), value.size());
+ str[*offset + value.size()] = '\0';
+ }
+ int posn = *offset;
+ *offset += value.size() + 1;
+ return posn;
+}
+
+// Build the parameter array string for a method.
+static QByteArray buildParameterNames
+ (const QByteArray& signature, const QList<QByteArray>& parameterNames)
+{
+ // If the parameter name list is specified, then concatenate them.
+ if (!parameterNames.isEmpty()) {
+ QByteArray names;
+ bool first = true;
+ foreach (QByteArray name, parameterNames) {
+ if (first)
+ first = false;
+ else
+ names += (char)',';
+ names += name;
+ }
+ return names;
+ }
+
+ // Count commas in the signature, excluding those inside template arguments.
+ int index = signature.indexOf('(');
+ if (index < 0)
+ return QByteArray();
+ ++index;
+ if (index >= signature.size())
+ return QByteArray();
+ if (signature[index] == ')')
+ return QByteArray();
+ int count = 1;
+ int brackets = 0;
+ while (index < signature.size() && signature[index] != ',') {
+ char ch = signature[index++];
+ if (ch == '<')
+ ++brackets;
+ else if (ch == '>')
+ --brackets;
+ else if (ch == ',' && brackets <= 0)
+ ++count;
+ }
+ return QByteArray(count - 1, ',');
+}
+
+// Build a QMetaObject in "buf" based on the information in "d".
+// If "buf" is null, then return the number of bytes needed to
+// build the QMetaObject.
+static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf)
+{
+ int size = 0;
+ int dataIndex;
+ int enumIndex;
+ int index;
+ bool hasNotifySignals = false;
+
+ // Create the main QMetaObject structure at the start of the buffer.
+ QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf);
+ size += sizeof(QMetaObject);
+ ALIGN(size, int);
+ if (buf) {
+ meta->d.superdata = d->superClass;
+ meta->d.extradata = 0;
+ }
+
+ // Populate the QMetaObjectPrivate structure.
+ QMetaObjectPrivate *pmeta
+ = reinterpret_cast<QMetaObjectPrivate *>(buf + size);
+ dataIndex = 13; // Number of fields in the QMetaObjectPrivate.
+ for (index = 0; index < d->properties.size(); ++index) {
+ if (d->properties[index].notifySignal != -1) {
+ hasNotifySignals = true;
+ break;
+ }
+ }
+ if (buf) {
+ pmeta->revision = 3;
+ pmeta->flags = d->flags;
+ pmeta->className = 0; // Class name is always the first string.
+
+ pmeta->classInfoCount = d->classInfoNames.size();
+ pmeta->classInfoData = dataIndex;
+ dataIndex += 2 * d->classInfoNames.size();
+
+ pmeta->methodCount = d->methods.size();
+ pmeta->methodData = dataIndex;
+ dataIndex += 5 * d->methods.size();
+
+ pmeta->propertyCount = d->properties.size();
+ pmeta->propertyData = dataIndex;
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+
+ pmeta->enumeratorCount = d->enumerators.size();
+ pmeta->enumeratorData = dataIndex;
+ dataIndex += 4 * d->enumerators.size();
+
+ pmeta->constructorCount = d->constructors.size();
+ pmeta->constructorData = dataIndex;
+ dataIndex += 5 * d->constructors.size();
+ } else {
+ dataIndex += 2 * d->classInfoNames.size();
+ dataIndex += 5 * d->methods.size();
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+ dataIndex += 4 * d->enumerators.size();
+ dataIndex += 5 * d->constructors.size();
+ }
+
+ // Allocate space for the enumerator key names and values.
+ enumIndex = dataIndex;
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ dataIndex += 2 * enumerator->keys.size();
+ }
+
+ // Zero terminator at the end of the data offset table.
+ ++dataIndex;
+
+ // Find the start of the data and string tables.
+ int *data = reinterpret_cast<int *>(pmeta);
+ size += dataIndex * sizeof(int);
+ char *str = reinterpret_cast<char *>(buf + size);
+ if (buf) {
+ meta->d.stringdata = str;
+ meta->d.data = reinterpret_cast<uint *>(data);
+ }
+
+ // Reset the current data position to just past the QMetaObjectPrivate.
+ dataIndex = 13;
+
+ // Add the class name to the string table.
+ int offset = 0;
+ buildString(buf, str, &offset, d->className, -1);
+
+ // Add a common empty string, which is used to indicate "void"
+ // method returns, empty tag strings, etc.
+ int empty = buildString(buf, str, &offset, QByteArray(), -1);
+
+ // Output the class infos,
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ int name = buildString(buf, str, &offset, d->classInfoNames[index], empty);
+ int value = buildString(buf, str, &offset, d->classInfoValues[index], empty);
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = value;
+ }
+ dataIndex += 2;
+ }
+
+ // Output the methods in the class.
+ for (index = 0; index < d->methods.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // Output the properties in the class.
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ int name = buildString(buf, str, &offset, prop->name, empty);
+ int type = buildString(buf, str, &offset, prop->type, empty);
+ int flags = prop->flags;
+
+ if (!isVariantType(prop->type)) {
+ flags |= EnumOrFlag;
+ } else {
+ flags |= qvariant_nameToType(prop->type) << 24;
+ }
+
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = type;
+ data[dataIndex + 2] = flags;
+ }
+ dataIndex += 3;
+ }
+ if (hasNotifySignals) {
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ if (buf) {
+ if (prop->notifySignal != -1)
+ data[dataIndex] = prop->notifySignal;
+ else
+ data[dataIndex] = 0;
+ }
+ ++dataIndex;
+ }
+ }
+
+ // Output the enumerators in the class.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ int name = buildString(buf, str, &offset, enumerator->name, empty);
+ int isFlag = (int)(enumerator->isFlag);
+ int count = enumerator->keys.size();
+ int enumOffset = enumIndex;
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = isFlag;
+ data[dataIndex + 2] = count;
+ data[dataIndex + 3] = enumOffset;
+ }
+ for (int key = 0; key < count; ++key) {
+ int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty);
+ if (buf) {
+ data[enumOffset++] = keyIndex;
+ data[enumOffset++] = enumerator->values[key];
+ }
+ }
+ dataIndex += 4;
+ enumIndex += 2 * count;
+ }
+
+ // Output the constructors in the class.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // One more empty string to act as a terminator.
+ buildString(buf, str, &offset, QByteArray(), -1);
+ size += offset;
+
+ // Output the zero terminator in the data array.
+ if (buf)
+ data[enumIndex] = 0;
+
+ // Create the extradata block if we need one.
+ if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) {
+ ALIGN(size, QMetaObject **);
+ ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction);
+ QMetaObjectExtraData *extra =
+ reinterpret_cast<QMetaObjectExtraData *>(buf + size);
+ size += sizeof(QMetaObjectExtraData);
+ ALIGN(size, QMetaObject *);
+ const QMetaObject **objects =
+ reinterpret_cast<const QMetaObject **>(buf + size);
+ if (buf) {
+ if (d->relatedMetaObjects.size() > 0) {
+ extra->objects = objects;
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index)
+ objects[index] = d->relatedMetaObjects[index];
+ objects[index] = 0;
+ } else {
+ extra->objects = 0;
+ }
+ extra->static_metacall = d->staticMetacallFunction;
+ meta->d.extradata = reinterpret_cast<void *>(extra);
+ }
+ if (d->relatedMetaObjects.size() > 0)
+ size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1);
+ }
+
+ // Align the final size and return it.
+ ALIGN(size, void *);
+ return size;
+}
+
+/*!
+ Converts this meta object builder into a concrete QMetaObject.
+ The return value should be deallocated using qFree() once it
+ is no longer needed.
+
+ The returned meta object is a snapshot of the state of the
+ QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder
+ will not be reflected in previous meta objects returned by
+ this method.
+*/
+QMetaObject *QMetaObjectBuilder::toMetaObject() const
+{
+ int size = buildMetaObject(d, 0);
+ char *buf = reinterpret_cast<char *>(qMalloc(size));
+ buildMetaObject(d, buf);
+ return reinterpret_cast<QMetaObject *>(buf);
+}
+
+/*!
+ \typedef QMetaObjectBuilder::StaticMetacallFunction
+
+ Typedef for static metacall functions. The three parameters are
+ the call type value, the constructor index, and the
+ array of parameters.
+*/
+
+/*!
+ Returns the static metacall function to use to construct objects
+ of this class. The default value is null.
+
+ \sa setStaticMetacallFunction()
+*/
+QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const
+{
+ return d->staticMetacallFunction;
+}
+
+/*!
+ Sets the static metacall function to use to construct objects
+ of this class to \a value. The default value is null.
+
+ \sa staticMetacallFunction()
+*/
+void QMetaObjectBuilder::setStaticMetacallFunction
+ (QMetaObjectBuilder::StaticMetacallFunction value)
+{
+ d->staticMetacallFunction = value;
+}
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ Serializes the contents of the meta object builder onto \a stream.
+
+ \sa deserialize()
+*/
+void QMetaObjectBuilder::serialize(QDataStream& stream) const
+{
+ int index;
+
+ // Write the class and super class names.
+ stream << d->className;
+ if (d->superClass)
+ stream << QByteArray(d->superClass->className());
+ else
+ stream << QByteArray();
+
+ // Write the counts for each type of class member.
+ stream << d->classInfoNames.size();
+ stream << d->methods.size();
+ stream << d->properties.size();
+ stream << d->enumerators.size();
+ stream << d->constructors.size();
+ stream << d->relatedMetaObjects.size();
+
+ // Write the items of class information.
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ stream << d->classInfoNames[index];
+ stream << d->classInfoValues[index];
+ }
+
+ // Write the methods.
+ for (index = 0; index < d->methods.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the properties.
+ for (index = 0; index < d->properties.size(); ++index) {
+ const QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream << property->name;
+ stream << property->type;
+ stream << property->flags;
+ stream << property->notifySignal;
+ }
+
+ // Write the enumerators.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream << enumerator->name;
+ stream << enumerator->isFlag;
+ stream << enumerator->keys;
+ stream << enumerator->values;
+ }
+
+ // Write the constructors.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the related meta objects.
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index) {
+ const QMetaObject *meta = d->relatedMetaObjects[index];
+ stream << QByteArray(meta->className());
+ }
+
+ // Add an extra empty QByteArray for additional data in future versions.
+ // This should help maintain backwards compatibility, allowing older
+ // versions to read newer data.
+ stream << QByteArray();
+}
+
+// Resolve a class name using the name reference map.
+static const QMetaObject *resolveClassName
+ (const QMap<QByteArray, const QMetaObject *>& references,
+ const QByteArray& name)
+{
+ if (name == QByteArray("QObject"))
+ return &QObject::staticMetaObject;
+ else
+ return references.value(name, 0);
+}
+
+/*!
+ Deserializes a meta object builder from \a stream into
+ this meta object builder.
+
+ The \a references parameter specifies a mapping from class names
+ to QMetaObject instances for resolving the super class name and
+ related meta objects in the object that is deserialized.
+ The meta object for QObject is implicitly added to \a references
+ and does not need to be supplied.
+
+ The QDataStream::status() value on \a stream will be set to
+ QDataStream::ReadCorruptData if the input data is corrupt.
+ The status will be set to QDataStream::ReadPastEnd if the
+ input was exhausted before the full meta object was read.
+
+ \sa serialize()
+*/
+void QMetaObjectBuilder::deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references)
+{
+ QByteArray name;
+ const QMetaObject *cl;
+ int index;
+
+ // Clear all members in the builder to their default states.
+ d->className.clear();
+ d->superClass = &QObject::staticMetaObject;
+ d->classInfoNames.clear();
+ d->classInfoValues.clear();
+ d->methods.clear();
+ d->properties.clear();
+ d->enumerators.clear();
+ d->constructors.clear();
+ d->relatedMetaObjects.clear();
+ d->staticMetacallFunction = 0;
+
+ // Read the class and super class names.
+ stream >> d->className;
+ stream >> name;
+ if (name.isEmpty()) {
+ d->superClass = 0;
+ } else if ((cl = resolveClassName(references, name)) != 0) {
+ d->superClass = cl;
+ } else {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the counts for each type of class member.
+ int classInfoCount, methodCount, propertyCount;
+ int enumeratorCount, constructorCount, relatedMetaObjectCount;
+ stream >> classInfoCount;
+ stream >> methodCount;
+ stream >> propertyCount;
+ stream >> enumeratorCount;
+ stream >> constructorCount;
+ stream >> relatedMetaObjectCount;
+ if (classInfoCount < 0 || methodCount < 0 ||
+ propertyCount < 0 || enumeratorCount < 0 ||
+ constructorCount < 0 || relatedMetaObjectCount < 0) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the items of class information.
+ for (index = 0; index < classInfoCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray value;
+ stream >> name;
+ stream >> value;
+ addClassInfo(name, value);
+ }
+
+ // Read the member methods.
+ for (index = 0; index < methodCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addMethod(name);
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() == QMetaMethod::Constructor) {
+ // Cannot add a constructor in this set of methods.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the properties.
+ for (index = 0; index < propertyCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray type;
+ stream >> name;
+ stream >> type;
+ addProperty(name, type);
+ QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream >> property->flags;
+ stream >> property->notifySignal;
+ if (property->notifySignal < -1 ||
+ property->notifySignal >= d->methods.size()) {
+ // Notify signal method index is out of range.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ if (property->notifySignal >= 0 &&
+ d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) {
+ // Notify signal method index does not refer to a signal.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the enumerators.
+ for (index = 0; index < enumeratorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addEnumerator(name);
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream >> enumerator->isFlag;
+ stream >> enumerator->keys;
+ stream >> enumerator->values;
+ if (enumerator->keys.size() != enumerator->values.size()) {
+ // Mismatch between number of keys and number of values.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the constructor methods.
+ for (index = 0; index < constructorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addConstructor(name);
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() != QMetaMethod::Constructor) {
+ // The type must be Constructor.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the related meta objects.
+ for (index = 0; index < relatedMetaObjectCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ cl = resolveClassName(references, name);
+ if (!cl) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ addRelatedMetaObject(cl);
+ }
+
+ // Read the extra data block, which is reserved for future use.
+ stream >> name;
+}
+
+#endif // !QT_NO_DATASTREAM
+
+/*!
+ \class QMetaMethodBuilder
+ \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder.
+*/
+
+QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const
+{
+ // Positive indices indicate methods, negative indices indicate constructors.
+ if (_mobj && _index >= 0 && _index < _mobj->d->methods.size())
+ return &(_mobj->d->methods[_index]);
+ else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size())
+ return &(_mobj->d->constructors[(-_index) - 1]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaMethodBuilder::QMetaMethodBuilder()
+ \internal
+*/
+
+/*!
+ Returns the index of this method within its QMetaObjectBuilder.
+*/
+int QMetaMethodBuilder::index() const
+{
+ if (_index >= 0)
+ return _index; // Method, signal, or slot
+ else
+ return (-_index) - 1; // Constructor
+}
+
+/*!
+ Returns the type of this method (signal, slot, method, or constructor).
+*/
+QMetaMethod::MethodType QMetaMethodBuilder::methodType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->methodType();
+ else
+ return QMetaMethod::Method;
+}
+
+/*!
+ Returns the signature of this method.
+
+ \sa parameterNames(), returnType()
+*/
+QByteArray QMetaMethodBuilder::signature() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->signature;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the return type for this method; empty if the method's
+ return type is \c{void}.
+
+ \sa setReturnType(), signature()
+*/
+QByteArray QMetaMethodBuilder::returnType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->returnType;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the return type for this method to \a value. If \a value
+ is empty, then the method's return type is \c{void}. The \a value
+ will be normalized before it is added to the method.
+
+ \sa returnType(), signature()
+*/
+void QMetaMethodBuilder::setReturnType(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->returnType = QMetaObject::normalizedType(value);
+}
+
+/*!
+ Returns the list of parameter names for this method.
+
+ \sa setParameterNames()
+*/
+QList<QByteArray> QMetaMethodBuilder::parameterNames() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->parameterNames;
+ else
+ return QList<QByteArray>();
+}
+
+/*!
+ Sets the list of parameter names for this method to \a value.
+
+ \sa parameterNames()
+*/
+void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->parameterNames = value;
+}
+
+/*!
+ Returns the tag associated with this method.
+
+ \sa setTag()
+*/
+QByteArray QMetaMethodBuilder::tag() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->tag;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the tag associated with this method to \a value.
+
+ \sa setTag()
+*/
+void QMetaMethodBuilder::setTag(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->tag = value;
+}
+
+/*!
+ Returns the access specification of this method (private, protected,
+ or public). The default value is QMetaMethod::Public for methods,
+ slots, and constructors. The default value is QMetaMethod::Protected
+ for signals.
+
+ \sa setAccess()
+*/
+QMetaMethod::Access QMetaMethodBuilder::access() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->access();
+ else
+ return QMetaMethod::Public;
+}
+
+/*!
+ Sets the access specification of this method (private, protected,
+ or public) to \a value. If the method is a signal, this function
+ will be ignored.
+
+ \sa access()
+*/
+void QMetaMethodBuilder::setAccess(QMetaMethod::Access value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d && d->methodType() != QMetaMethod::Signal)
+ d->setAccess(value);
+}
+
+/*!
+ Returns the additional attributes for this method.
+
+ \sa setAttributes()
+*/
+int QMetaMethodBuilder::attributes() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return (d->attributes >> 4);
+ else
+ return 0;
+}
+
+/*!
+ Sets the additional attributes for this method to \a value.
+
+ \sa attributes()
+*/
+void QMetaMethodBuilder::setAttributes(int value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->attributes = ((d->attributes & 0x0f) | (value << 4));
+}
+
+/*!
+ \class QMetaPropertyBuilder
+ \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder.
+*/
+
+QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->properties.size())
+ return &(_mobj->d->properties[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaPropertyBuilder::QMetaPropertyBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaPropertyBuilder::index() const
+
+ Returns the index of this property within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name associated with this property.
+
+ \sa type()
+*/
+QByteArray QMetaPropertyBuilder::name() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the type associated with this property.
+
+ \sa name()
+*/
+QByteArray QMetaPropertyBuilder::type() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->type;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this property has a notify signal; false otherwise.
+
+ \sa notifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+bool QMetaPropertyBuilder::hasNotifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Notify);
+ else
+ return false;
+}
+
+/*!
+ Returns the notify signal associated with this property.
+
+ \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d && d->notifySignal >= 0)
+ return QMetaMethodBuilder(_mobj, d->notifySignal);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Sets the notify signal associated with this property to \a value.
+
+ \sa hasNotifySignal(), notifySignal(), removeNotifySignal()
+*/
+void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ if (value._mobj) {
+ d->notifySignal = value._index;
+ d->setFlag(Notify, true);
+ } else {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+ }
+}
+
+/*!
+ Removes the notify signal from this property.
+
+ \sa hasNotifySignal(), notifySignal(), setNotifySignal()
+*/
+void QMetaPropertyBuilder::removeNotifySignal()
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+}
+
+/*!
+ Returns true if this property is readable; otherwise returns false.
+ The default value is true.
+
+ \sa setReadable(), isWritable()
+*/
+bool QMetaPropertyBuilder::isReadable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Readable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is writable; otherwise returns false.
+ The default value is true.
+
+ \sa setWritable(), isReadable()
+*/
+bool QMetaPropertyBuilder::isWritable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Writable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property can be reset to a default value; otherwise
+ returns false. The default value is false.
+
+ \sa setResettable()
+*/
+bool QMetaPropertyBuilder::isResettable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Resettable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designable; otherwise returns false.
+ This default value is false.
+
+ \sa setDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isDesignable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Designable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is scriptable; otherwise returns false.
+ This default value is false.
+
+ \sa setScriptable(), isDesignable(), isStored()
+*/
+bool QMetaPropertyBuilder::isScriptable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Scriptable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is stored; otherwise returns false.
+ This default value is false.
+
+ \sa setStored(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isStored() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Stored);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is editable; otherwise returns false.
+ This default value is false.
+
+ \sa setEditable(), isDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isEditable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Editable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designated as the \c USER
+ property, i.e., the one that the user can edit or that is
+ significant in some other way. Otherwise it returns
+ false. This default value is false.
+
+ \sa setUser(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isUser() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(User);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a C++ setter function that
+ follows Qt's standard "name" / "setName" pattern. Designer and uic
+ query hasStdCppSet() in order to avoid expensive
+ QObject::setProperty() calls. All properties in Qt [should] follow
+ this pattern. The default value is false.
+
+ \sa setStdCppSet()
+*/
+bool QMetaPropertyBuilder::hasStdCppSet() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(StdCppSet);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is an enumerator or flag type;
+ otherwise returns false. This default value is false.
+
+ \sa setEnumOrFlag()
+*/
+bool QMetaPropertyBuilder::isEnumOrFlag() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(EnumOrFlag);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has the dynamic flag set;
+ otherwise returns false. The default value is false.
+
+ \sa setDynamic()
+*/
+bool QMetaPropertyBuilder::isDynamic() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Dynamic);
+ else
+ return false;
+}
+
+/*!
+ Sets this property to readable if \a value is true.
+
+ \sa isReadable(), setWritable()
+*/
+void QMetaPropertyBuilder::setReadable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Readable, value);
+}
+
+/*!
+ Sets this property to writable if \a value is true.
+
+ \sa isWritable(), setReadable()
+*/
+void QMetaPropertyBuilder::setWritable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Writable, value);
+}
+
+/*!
+ Sets this property to resettable if \a value is true.
+
+ \sa isResettable()
+*/
+void QMetaPropertyBuilder::setResettable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Resettable, value);
+}
+
+/*!
+ Sets this property to designable if \a value is true.
+
+ \sa isDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setDesignable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Designable, value);
+}
+
+/*!
+ Sets this property to scriptable if \a value is true.
+
+ \sa isScriptable(), setDesignable(), setStored()
+*/
+void QMetaPropertyBuilder::setScriptable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Scriptable, value);
+}
+
+/*!
+ Sets this property to storable if \a value is true.
+
+ \sa isStored(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setStored(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Stored, value);
+}
+
+/*!
+ Sets this property to editable if \a value is true.
+
+ \sa isEditable(), setDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setEditable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Editable, value);
+}
+
+/*!
+ Sets the \c USER flag on this property to \a value.
+
+ \sa isUser(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setUser(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(User, value);
+}
+
+/*!
+ Sets the C++ setter flag on this property to \a value, which is
+ true if the property has a C++ setter function that follows Qt's
+ standard "name" / "setName" pattern.
+
+ \sa hasStdCppSet()
+*/
+void QMetaPropertyBuilder::setStdCppSet(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(StdCppSet, value);
+}
+
+/*!
+ Sets this property to be of an enumerator or flag type if
+ \a value is true.
+
+ \sa isEnumOrFlag()
+*/
+void QMetaPropertyBuilder::setEnumOrFlag(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(EnumOrFlag, value);
+}
+
+/*!
+ Sets this property to have the dynamic flag if \a value is
+ true.
+
+ \sa isDynamic()
+*/
+void QMetaPropertyBuilder::setDynamic(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Dynamic, value);
+}
+
+/*!
+ \class QMetaEnumBuilder
+ \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
+*/
+
+QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size())
+ return &(_mobj->d->enumerators[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaEnumBuilder::QMetaEnumBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaEnumBuilder::index() const
+
+ Returns the index of this enumerator within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name of the enumerator (without the scope).
+*/
+QByteArray QMetaEnumBuilder::name() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this enumerator is used as a flag; otherwise returns
+ false.
+
+ \sa setIsFlag()
+*/
+bool QMetaEnumBuilder::isFlag() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->isFlag;
+ else
+ return false;
+}
+
+/*!
+ Sets this enumerator to be used as a flag if \a value is true.
+
+ \sa isFlag()
+*/
+void QMetaEnumBuilder::setIsFlag(bool value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->isFlag = value;
+}
+
+/*!
+ Returns the number of keys.
+
+ \sa key(), addKey()
+*/
+int QMetaEnumBuilder::keyCount() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->keys.size();
+ else
+ return 0;
+}
+
+/*!
+ Returns the key with the given \a index, or an empty QByteArray
+ if no such key exists.
+
+ \sa keyCount(), addKey(), value()
+*/
+QByteArray QMetaEnumBuilder::key(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->keys[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value with the given \a index; or returns -1 if there
+ is no such value.
+
+ \sa keyCount(), addKey(), key()
+*/
+int QMetaEnumBuilder::value(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->values[index];
+ else
+ return -1;
+}
+
+/*!
+ Adds a new key called \a name to this enumerator, associated
+ with \a value. Returns the index of the new key.
+
+ \sa keyCount(), key(), value(), removeKey()
+*/
+int QMetaEnumBuilder::addKey(const QByteArray& name, int value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d) {
+ int index = d->keys.size();
+ d->keys += name;
+ d->values += value;
+ return index;
+ } else {
+ return -1;
+ }
+}
+
+/*!
+ Removes the key at \a index from this enumerator.
+
+ \sa addKey()
+*/
+void QMetaEnumBuilder::removeKey(int index)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size()) {
+ d->keys.removeAt(index);
+ d->values.removeAt(index);
+ }
+}
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
new file mode 100644
index 0000000..dc95745
--- /dev/null
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** This file is part of the $PACKAGE_NAME$.
+**
+** Copyright (C) $THISYEAR$ $COMPANY_NAME$.
+**
+** $QT_EXTENDED_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMETAOBJECTBUILDER_H
+#define QMETAOBJECTBUILDER_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmap.h>
+
+class QMetaObjectBuilderPrivate;
+class QMetaMethodBuilder;
+class QMetaMethodBuilderPrivate;
+class QMetaPropertyBuilder;
+class QMetaPropertyBuilderPrivate;
+class QMetaEnumBuilder;
+class QMetaEnumBuilderPrivate;
+
+class Q_CORE_EXPORT QMetaObjectBuilder
+{
+public:
+ enum AddMember
+ {
+ ClassName = 0x00000001,
+ SuperClass = 0x00000002,
+ Methods = 0x00000004,
+ Signals = 0x00000008,
+ Slots = 0x00000010,
+ Constructors = 0x00000020,
+ Properties = 0x00000040,
+ Enumerators = 0x00000080,
+ ClassInfos = 0x00000100,
+ RelatedMetaObjects = 0x00000200,
+ StaticMetacall = 0x00000400,
+ PublicMethods = 0x00000800,
+ ProtectedMethods = 0x00001000,
+ PrivateMethods = 0x00002000,
+ AllMembers = 0x7FFFFFFF,
+ AllPrimaryMembers = 0x7FFFFBFC
+ };
+ Q_DECLARE_FLAGS(AddMembers, AddMember)
+
+ enum MetaObjectFlag {
+ DynamicMetaObject = 0x01
+ };
+ Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag)
+
+ QMetaObjectBuilder();
+ explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+ virtual ~QMetaObjectBuilder();
+
+ QByteArray className() const;
+ void setClassName(const QByteArray& name);
+
+ const QMetaObject *superClass() const;
+ void setSuperClass(const QMetaObject *meta);
+
+ MetaObjectFlags flags() const;
+ void setFlags(MetaObjectFlags);
+
+ int methodCount() const;
+ int constructorCount() const;
+ int propertyCount() const;
+ int enumeratorCount() const;
+ int classInfoCount() const;
+ int relatedMetaObjectCount() const;
+
+ QMetaMethodBuilder addMethod(const QByteArray& signature);
+ QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType);
+ QMetaMethodBuilder addMethod(const QMetaMethod& prototype);
+
+ QMetaMethodBuilder addSlot(const QByteArray& signature);
+ QMetaMethodBuilder addSignal(const QByteArray& signature);
+
+ QMetaMethodBuilder addConstructor(const QByteArray& signature);
+ QMetaMethodBuilder addConstructor(const QMetaMethod& prototype);
+
+ QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1);
+ QMetaPropertyBuilder addProperty(const QMetaProperty& prototype);
+
+ QMetaEnumBuilder addEnumerator(const QByteArray& name);
+ QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype);
+
+ int addClassInfo(const QByteArray& name, const QByteArray& value);
+
+ int addRelatedMetaObject(const QMetaObject *meta);
+
+ void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+
+ QMetaMethodBuilder method(int index) const;
+ QMetaMethodBuilder constructor(int index) const;
+ QMetaPropertyBuilder property(int index) const;
+ QMetaEnumBuilder enumerator(int index) const;
+ const QMetaObject *relatedMetaObject(int index) const;
+
+ QByteArray classInfoName(int index) const;
+ QByteArray classInfoValue(int index) const;
+
+ void removeMethod(int index);
+ void removeConstructor(int index);
+ void removeProperty(int index);
+ void removeEnumerator(int index);
+ void removeClassInfo(int index);
+ void removeRelatedMetaObject(int index);
+
+ int indexOfMethod(const QByteArray& signature);
+ int indexOfSignal(const QByteArray& signature);
+ int indexOfSlot(const QByteArray& signature);
+ int indexOfConstructor(const QByteArray& signature);
+ int indexOfProperty(const QByteArray& name);
+ int indexOfEnumerator(const QByteArray& name);
+ int indexOfClassInfo(const QByteArray& name);
+
+ typedef int (*StaticMetacallFunction)(QMetaObject::Call, int, void **);
+
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const;
+ void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value);
+
+ QMetaObject *toMetaObject() const;
+
+#ifndef QT_NO_DATASTREAM
+ void serialize(QDataStream& stream) const;
+ void deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references);
+#endif
+
+private:
+ Q_DISABLE_COPY(QMetaObjectBuilder);
+
+ QMetaObjectBuilderPrivate *d;
+
+ friend class QMetaMethodBuilder;
+ friend class QMetaPropertyBuilder;
+ friend class QMetaEnumBuilder;
+};
+
+class Q_CORE_EXPORT QMetaMethodBuilder
+{
+public:
+ QMetaMethodBuilder() : _mobj(0), _index(0) {}
+
+ int index() const;
+
+ QMetaMethod::MethodType methodType() const;
+ QByteArray signature() const;
+
+ QByteArray returnType() const;
+ void setReturnType(const QByteArray& value);
+
+ QList<QByteArray> parameterNames() const;
+ void setParameterNames(const QList<QByteArray>& value);
+
+ QByteArray tag() const;
+ void setTag(const QByteArray& value);
+
+ QMetaMethod::Access access() const;
+ void setAccess(QMetaMethod::Access value);
+
+ int attributes() const;
+ void setAttributes(int value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+ friend class QMetaPropertyBuilder;
+
+ QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaMethodBuilderPrivate *d_func() const;
+};
+
+class Q_CORE_EXPORT QMetaPropertyBuilder
+{
+public:
+ QMetaPropertyBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+ QByteArray type() const;
+
+ bool hasNotifySignal() const;
+ QMetaMethodBuilder notifySignal() const;
+ void setNotifySignal(const QMetaMethodBuilder& value);
+ void removeNotifySignal();
+
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isResettable() const;
+ bool isDesignable() const;
+ bool isScriptable() const;
+ bool isStored() const;
+ bool isEditable() const;
+ bool isUser() const;
+ bool hasStdCppSet() const;
+ bool isEnumOrFlag() const;
+ bool isDynamic() const;
+
+ void setReadable(bool value);
+ void setWritable(bool value);
+ void setResettable(bool value);
+ void setDesignable(bool value);
+ void setScriptable(bool value);
+ void setStored(bool value);
+ void setEditable(bool value);
+ void setUser(bool value);
+ void setStdCppSet(bool value);
+ void setEnumOrFlag(bool value);
+ void setDynamic(bool value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaPropertyBuilderPrivate *d_func() const;
+};
+
+class Q_CORE_EXPORT QMetaEnumBuilder
+{
+public:
+ QMetaEnumBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+
+ bool isFlag() const;
+ void setIsFlag(bool value);
+
+ int keyCount() const;
+ QByteArray key(int index) const;
+ int value(int index) const;
+
+ int addKey(const QByteArray& name, int value);
+ void removeKey(int index);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaEnumBuilderPrivate *d_func() const;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags)
+
+#endif
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 05015c0..638c7d1 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -120,10 +120,12 @@ QObjectPrivate::QObjectPrivate(int version)
inEventHandler = false;
inThreadChangeEvent = false;
deleteWatch = 0;
+ metaObject = 0;
}
QObjectPrivate::~QObjectPrivate()
{
+ delete static_cast<QAbstractDynamicMetaObject*>(metaObject);
if (deleteWatch)
*deleteWatch = 1;
#ifndef QT_NO_USERDATA
@@ -486,7 +488,7 @@ QMetaCallEvent::~QMetaCallEvent()
*/
int QMetaCallEvent::placeMetaCall(QObject *object)
{
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, id_, args_);
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, id_, args_);
}
/*!
@@ -3105,10 +3107,10 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
}
#if defined(QT_NO_EXCEPTIONS)
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
try {
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
} catch (...) {
locker.relock();
@@ -3813,6 +3815,7 @@ void qDeleteInEventHandler(QObject *o)
delete o;
}
+
QT_END_NAMESPACE
#include "moc_qobject.cpp"
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index dbec0a6..b6bdfb3 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -108,6 +108,7 @@ public:
uint inThreadChangeEvent : 1;
uint unused : 23;
int postedEvents;
+ QMetaObject *metaObject; // assert dynamic
};
@@ -378,6 +379,9 @@ inline QList<T> qFindChildren(const QObject *o, const QRegExp &re)
#endif // Q_MOC_RUN
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
template <class T> inline T qobject_cast_helper(QObject *object, T)
{ return static_cast<T>(((T)0)->staticMetaObject.cast(object)); }
@@ -394,6 +398,8 @@ inline T qobject_cast(const QObject *object)
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return IId; } \
template <> inline IFace *qobject_cast_helper<IFace *>(QObject *object, IFace *) \
{ return (IFace *)(object ? object->qt_metacast(IId) : 0); } \
template <> inline IFace *qobject_cast_helper<IFace *>(const QObject *object, IFace *) \
@@ -457,8 +463,13 @@ inline T qobject_cast(const QObject *object)
}
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return IId; } \
template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \
template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index b324334..31b1593 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -220,6 +220,14 @@ private:
void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
+
+struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QMetaObject
+{
+ virtual ~QAbstractDynamicMetaObject() {}
+ virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; }
+ virtual int createProperty(const char *, const char *) { return -1; }
+};
+
QT_END_NAMESPACE
#endif // QOBJECT_P_H
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 3a22323..98cc108 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -77,6 +77,7 @@ class QString;
#endif
#define Q_CLASSINFO(name, value)
#define Q_INTERFACES(x)
+#define Q_CAST_INTERFACES(x)
#define Q_PROPERTY(text)
#define Q_OVERRIDE(text)
#define Q_ENUMS(x)
@@ -169,6 +170,7 @@ private:
#define Q_SIGNALS Q_SIGNALS
#define Q_CLASSINFO(name, value) Q_CLASSINFO(name, value)
#define Q_INTERFACES(x) Q_INTERFACES(x)
+#define Q_CAST_INTERFACES(x) Q_CAST_INTERFACES(x)
#define Q_PROPERTY(text) Q_PROPERTY(text)
#define Q_OVERRIDE(text) Q_OVERRIDE(text)
#define Q_ENUMS(x) Q_ENUMS(x)
@@ -428,6 +430,7 @@ struct Q_CORE_EXPORT QMetaObject
};
int static_metacall(Call, int, void **) const;
+ static int metacall(QObject *, Call, int, void **);
#ifdef QT3_SUPPORT
QT3_SUPPORT const char *superClassName() const;
@@ -439,6 +442,7 @@ struct Q_CORE_EXPORT QMetaObject
const uint *data;
const void *extradata;
} d;
+
};
struct QMetaObjectExtraData
diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h
index 033b760..727a390 100644
--- a/src/corelib/kernel/qvariant_p.h
+++ b/src/corelib/kernel/qvariant_p.h
@@ -91,36 +91,13 @@ inline T *v_cast(QVariant::Private *d, T * = 0)
#endif
-
-//a simple template that avoids to allocate 2 memory chunks when creating a QVariant
-template <class T> class QVariantPrivateSharedEx : public QVariant::PrivateShared
-{
-public:
- QVariantPrivateSharedEx() : QVariant::PrivateShared(&m_t) { }
- QVariantPrivateSharedEx(const T&t) : QVariant::PrivateShared(&m_t), m_t(t) { }
-
-private:
- T m_t;
-};
-
// constructs a new variant if copy is 0, otherwise copy-constructs
template <class T>
-inline void v_construct(QVariant::Private *x, const T &t)
-{
- if (sizeof(T) > sizeof(QVariant::Private::Data)) {
- x->data.shared = new QVariantPrivateSharedEx<T>(t);
- x->is_shared = true;
- } else {
- new (&x->data.ptr) T(t);
- }
-}
-
-template <class T>
inline void v_construct(QVariant::Private *x, const void *copy, T * = 0)
{
if (sizeof(T) > sizeof(QVariant::Private::Data)) {
- x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy))
- : new QVariantPrivateSharedEx<T>;
+ x->data.shared = copy ? new QVariant::PrivateShared(new T(*static_cast<const T *>(copy)))
+ : new QVariant::PrivateShared(new T);
x->is_shared = true;
} else {
if (copy)
@@ -134,15 +111,12 @@ inline void v_construct(QVariant::Private *x, const void *copy, T * = 0)
template <class T>
inline void v_clear(QVariant::Private *d, T* = 0)
{
-
if (sizeof(T) > sizeof(QVariant::Private::Data)) {
- //now we need to cast
- //because QVariant::PrivateShared doesn't have a virtual destructor
- delete static_cast<QVariantPrivateSharedEx<T>*>(d->data.shared);
+ delete v_cast<T>(d);
+ delete d->data.shared;
} else {
v_cast<T>(d)->~T();
}
-
}
QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp
new file mode 100644
index 0000000..68a7fdc
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractstate.h"
+#include "qabstractstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractState
+
+ \brief The QAbstractState class is the base class of states of a QStateMachine.
+
+ \ingroup statemachine
+
+ The QAbstractState class is the abstract base class of states that are part
+ of a QStateMachine. It defines the interface that all state objects have in
+ common. QAbstractState is part of \l{The State Machine Framework}.
+
+ The parentState() function returns the state's parent state.
+
+ \section1 Subclassing
+
+ The onEntry() function is called when the state is entered; reimplement this
+ function to perform custom processing when the state is entered.
+
+ The onExit() function is called when the state is exited; reimplement this
+ function to perform custom processing when the state is exited.
+*/
+
+QAbstractStatePrivate::QAbstractStatePrivate()
+{
+}
+
+QAbstractStatePrivate *QAbstractStatePrivate::get(QAbstractState *q)
+{
+ return q->d_func();
+}
+
+const QAbstractStatePrivate *QAbstractStatePrivate::get(const QAbstractState *q)
+{
+ return q->d_func();
+}
+
+QStateMachine *QAbstractStatePrivate::machine() const
+{
+ Q_Q(const QAbstractState);
+ QObject *par = q->parent();
+ while (par != 0) {
+ if (QStateMachine *mach = qobject_cast<QStateMachine*>(par))
+ return mach;
+ par = par->parent();
+ }
+ return 0;
+}
+
+void QAbstractStatePrivate::callOnEntry()
+{
+ Q_Q(QAbstractState);
+ q->onEntry();
+}
+
+void QAbstractStatePrivate::callOnExit()
+{
+ Q_Q(QAbstractState);
+ q->onExit();
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QAbstractState::QAbstractState(QState *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ *new QAbstractStatePrivate,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(new QAbstractStatePrivate)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ \internal
+*/
+QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ dd,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(&dd)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ Destroys this state.
+*/
+QAbstractState::~QAbstractState()
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ delete d_ptr;
+#endif
+}
+
+/*!
+ Returns this state's parent state, or 0 if the state has no parent state.
+*/
+QState *QAbstractState::parentState() const
+{
+ return qobject_cast<QState*>(parent());
+}
+
+/*!
+ \fn QAbstractState::onExit()
+
+ This function is called when the state is exited. Reimplement this function
+ to perform custom processing when the state is exited.
+*/
+
+/*!
+ \fn QAbstractState::onEntry()
+
+ This function is called when the state is entered. Reimplement this function
+ to perform custom processing when the state is entered.
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractState::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h
new file mode 100644
index 0000000..cbf7ab5
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSTATE_H
+#define QABSTRACTSTATE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QState;
+
+class QAbstractStatePrivate;
+class Q_CORE_EXPORT QAbstractState : public QObject
+{
+ Q_OBJECT
+public:
+ ~QAbstractState();
+
+ QState *parentState() const;
+
+protected:
+ QAbstractState(QState *parent = 0);
+
+ virtual void onEntry() = 0;
+ virtual void onExit() = 0;
+
+ bool event(QEvent *e);
+
+protected:
+#ifdef QT_STATEMACHINE_SOLUTION
+ QAbstractStatePrivate *d_ptr;
+#endif
+ QAbstractState(QAbstractStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractState)
+ Q_DECLARE_PRIVATE(QAbstractState)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h
new file mode 100644
index 0000000..631d0b4
--- /dev/null
+++ b/src/corelib/statemachine/qabstractstate_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSTATE_P_H
+#define QABSTRACTSTATE_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.
+//
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <private/qobject_p.h>
+#endif
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractTransition;
+class QHistoryState;
+class QStateMachine;
+
+class QAbstractState;
+class Q_CORE_EXPORT QAbstractStatePrivate
+#ifndef QT_STATEMACHINE_SOLUTION
+ : public QObjectPrivate
+#endif
+{
+ Q_DECLARE_PUBLIC(QAbstractState)
+
+public:
+ QAbstractStatePrivate();
+
+ static QAbstractStatePrivate *get(QAbstractState *q);
+ static const QAbstractStatePrivate *get(const QAbstractState *q);
+
+ QStateMachine *machine() const;
+
+ void callOnEntry();
+ void callOnExit();
+
+#ifdef QT_STATEMACHINE_SOLUTION
+ QAbstractState *q_ptr;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
new file mode 100644
index 0000000..d9ca154
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qabstractstate.h"
+#include "qstate.h"
+#include "qstatemachine.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractTransition
+
+ \brief The QAbstractTransition class is the base class of transitions between QAbstractState objects.
+
+ \ingroup statemachine
+
+ The QAbstractTransition class is the abstract base class of transitions
+ between states (QAbstractState objects) of a
+ QStateMachine. QAbstractTransition is part of \l{The State Machine
+ Framework}.
+
+ The QTransition class provides a default (action-based) implementation of
+ the QAbstractTransition interface.
+
+ The sourceState() function returns the source of the transition. The
+ targetStates() function returns the targets of the transition.
+
+ \section1 Subclassing
+
+ The eventTest() function is called by the state machine to determine whether
+ an event should trigger the transition. In your reimplementation you
+ typically check the event type and cast the event object to the proper type,
+ and check that one or more properties of the event meet your criteria.
+
+ The onTransition() function is called when the transition is triggered;
+ reimplement this function to perform custom processing for the transition.
+*/
+
+/*!
+ \property QAbstractTransition::source
+
+ \brief the source state (parent) of this transition
+*/
+
+/*!
+ \property QAbstractTransition::target
+
+ \brief the target state of this transition
+*/
+
+/*!
+ \property QAbstractTransition::targets
+
+ \brief the target states of this transition
+
+ If multiple states are specified, all must be descendants of the same
+ parallel group state.
+*/
+
+QAbstractTransitionPrivate::QAbstractTransitionPrivate()
+{
+}
+
+QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition *q)
+{
+ return q->d_func();
+}
+
+const QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(const QAbstractTransition *q)
+{
+ return q->d_func();
+}
+
+QStateMachine *QAbstractTransitionPrivate::machine() const
+{
+ Q_Q(const QAbstractTransition);
+ QObject *par = q->parent();
+ while (par != 0) {
+ if (QStateMachine *mach = qobject_cast<QStateMachine*>(par))
+ return mach;
+ par = par->parent();
+ }
+ return 0;
+}
+
+bool QAbstractTransitionPrivate::callEventTest(QEvent *e) const
+{
+ Q_Q(const QAbstractTransition);
+ return q->eventTest(e);
+}
+
+void QAbstractTransitionPrivate::callOnTransition()
+{
+ Q_Q(QAbstractTransition);
+ q->onTransition();
+}
+
+QState *QAbstractTransitionPrivate::sourceState() const
+{
+ Q_Q(const QAbstractTransition);
+ return qobject_cast<QState*>(q->parent());
+}
+
+/*!
+ Constructs a new QAbstractTransition object with the given \a sourceState.
+*/
+QAbstractTransition::QAbstractTransition(QState *sourceState)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ *new QAbstractTransitionPrivate,
+#endif
+ sourceState)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(new QAbstractTransitionPrivate)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ Constructs a new QAbstractTransition object with the given \a targets and \a
+ sourceState.
+*/
+QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets,
+ QState *sourceState)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ *new QAbstractTransitionPrivate,
+#endif
+ sourceState)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(new QAbstractTransitionPrivate)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+ Q_D(QAbstractTransition);
+ d->targetStates = targets;
+}
+
+/*!
+ \internal
+*/
+QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
+ QState *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ dd,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(&dd)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ \internal
+*/
+QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
+ const QList<QAbstractState*> &targets,
+ QState *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ dd,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(&dd)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+ Q_D(QAbstractTransition);
+ d->targetStates = targets;
+}
+
+/*!
+ Destroys this transition.
+*/
+QAbstractTransition::~QAbstractTransition()
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ delete d_ptr;
+#endif
+}
+
+/*!
+ Returns the source state of this transition, or 0 if this transition has no
+ source state.
+*/
+QState *QAbstractTransition::sourceState() const
+{
+ Q_D(const QAbstractTransition);
+ return d->sourceState();
+}
+
+/*!
+ Returns the target state of this transition, or 0 if the transition has no
+ target.
+*/
+QAbstractState *QAbstractTransition::targetState() const
+{
+ Q_D(const QAbstractTransition);
+ if (d->targetStates.isEmpty())
+ return 0;
+ return d->targetStates.first();
+}
+
+/*!
+ Sets the \a target state of this transition.
+*/
+void QAbstractTransition::setTargetState(QAbstractState* target)
+{
+ Q_D(QAbstractTransition);
+ if (!target)
+ d->targetStates.clear();
+ else
+ d->targetStates = QList<QAbstractState*>() << target;
+}
+
+/*!
+ Returns the target states of this transition, or an empty list if this
+ transition has no target states.
+*/
+QList<QAbstractState*> QAbstractTransition::targetStates() const
+{
+ Q_D(const QAbstractTransition);
+ return d->targetStates;
+}
+
+/*!
+ Sets the target states of this transition to be the given \a targets.
+*/
+void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
+{
+ Q_D(QAbstractTransition);
+ d->targetStates = targets;
+}
+
+/*!
+ \fn QAbstractTransition::eventTest(QEvent *event) const
+
+ This function is called to determine whether the given \a event should cause
+ this transition to trigger. Reimplement this function and return true if the
+ event should trigger the transition, otherwise return false.
+*/
+
+/*!
+ \fn QAbstractTransition::onTransition()
+
+ This function is called when the transition is triggered. Reimplement this
+ function to perform custom processing when the transition is triggered.
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractTransition::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h
new file mode 100644
index 0000000..4cf7fae
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTTRANSITION_H
+#define QABSTRACTTRANSITION_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEvent;
+class QAbstractState;
+class QState;
+
+class QAbstractTransitionPrivate;
+class Q_CORE_EXPORT QAbstractTransition : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QState* source READ sourceState)
+ Q_PROPERTY(QAbstractState* target READ targetState WRITE setTargetState)
+ Q_PROPERTY(QList<QAbstractState*> targets READ targetStates WRITE setTargetStates)
+public:
+ QAbstractTransition(QState *sourceState = 0);
+ QAbstractTransition(const QList<QAbstractState*> &targets, QState *sourceState = 0);
+ virtual ~QAbstractTransition();
+
+ QState *sourceState() const;
+ QAbstractState *targetState() const;
+ void setTargetState(QAbstractState* target);
+ QList<QAbstractState*> targetStates() const;
+ void setTargetStates(const QList<QAbstractState*> &targets);
+
+protected:
+ virtual bool eventTest(QEvent *event) const = 0;
+
+ virtual void onTransition() = 0;
+
+ bool event(QEvent *e);
+
+protected:
+#ifdef QT_STATEMACHINE_SOLUTION
+ QAbstractTransitionPrivate *d_ptr;
+#endif
+ QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent);
+ QAbstractTransition(QAbstractTransitionPrivate &dd,
+ const QList<QAbstractState*> &targets, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractTransition)
+ Q_DECLARE_PRIVATE(QAbstractTransition)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h
new file mode 100644
index 0000000..796af11
--- /dev/null
+++ b/src/corelib/statemachine/qabstracttransition_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTTRANSITION_P_H
+#define QABSTRACTTRANSITION_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.
+//
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <private/qobject_p.h>
+#endif
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractState;
+class QState;
+class QStateMachine;
+
+class QAbstractTransition;
+class Q_CORE_EXPORT QAbstractTransitionPrivate
+#ifndef QT_STATEMACHINE_SOLUTION
+ : public QObjectPrivate
+#endif
+{
+ Q_DECLARE_PUBLIC(QAbstractTransition)
+public:
+ QAbstractTransitionPrivate();
+
+ static QAbstractTransitionPrivate *get(QAbstractTransition *q);
+ static const QAbstractTransitionPrivate *get(const QAbstractTransition *q);
+
+ bool callEventTest(QEvent *e) const;
+ void callOnTransition();
+ QState *sourceState() const;
+ QStateMachine *machine() const;
+
+ QList<QAbstractState*> targetStates;
+
+#ifdef QT_STATEMACHINE_SOLUTION
+ QAbstractTransition *q_ptr;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qactionstate.cpp b/src/corelib/statemachine/qactionstate.cpp
new file mode 100644
index 0000000..312465e
--- /dev/null
+++ b/src/corelib/statemachine/qactionstate.cpp
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qactionstate.h"
+#include "qactionstate_p.h"
+#include "qstateaction.h"
+#include "qstateaction_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QActionState
+
+ \brief The QActionState class provides an action-based state.
+
+ \ingroup statemachine
+
+ QActionState executes \l{QStateAction}{state actions} when the state is
+ entered and exited. QActionState is part of \l{The State Machine Framework}.
+
+ You can add actions to a state with the addEntryAction() and addExitAction()
+ functions. The state executes the actions when the state is entered and
+ exited, respectively.
+
+ Built-in actions are provided for setting properties and invoking methods of
+ QObjects. The setPropertyOnEntry() and setPropertyOnExit() functions are
+ used for defining property assignments that should be performed when a state
+ is entered and exited, respectively.
+
+ \code
+ QLabel label;
+ QStateMachine machine;
+ QState *s1 = new QState();
+ s1->setPropertyOnEntry(&label, "text", "Entered state s1");
+ machine.addState(s1);
+ \endcode
+
+ The invokeMethodOnEntry() and invokeMethodOnExit() functions are used for
+ defining method invocations that should be performed when a state is entered
+ and exited, respectively.
+
+ \code
+ QState *s2 = new QState();
+ s2->invokeMethodOnEntry(&label, "showMaximized");
+ machine.addState(s2);
+ \endcode
+
+ \sa QStateAction
+*/
+
+/*!
+ \enum QActionState::RestorePolicy
+
+ This enum specifies the restore policy type for a state. The restore policy takes effect when
+ the machine enters a state which has entry actions of the type QStateSetPropertyAction. If the
+ restore policy of the state is set to RestoreProperties, the state machine will save the
+ value of the property before the QStateSetPropertyAction is executed.
+
+ Later, when the machine either enters a state which has its restore policy set to
+ DoNotRestoreProperties or when it enters a state which does not set a value for the given
+ property, the property will automatically be restored to its initial value. The state machine
+ will only detect which properties are being set if they are being set using a
+ QStateSetPropertyAction object set as entry action on a state.
+
+ Special rules apply when using QAnimationState. If a QAnimationState registers that a property
+ should be restored before entering the target state of its QStateFinishedTransition, it will
+ restore this property using a QPropertyAnimation.
+
+ Only one initial value will be saved for any given property. If a value for a property has
+ already been saved by the state machine, it will not be overwritten until the property has been
+ successfully restored. Once the property has been restored, the state machine will clear the
+ initial value until it enters a new state which sets the property and which has RestoreProperties
+ as its restore policy.
+
+ \value GlobalRestorePolicy The restore policy for the state should be retrieved using
+ QStateMachine::globalRestorePolicy()
+ \value DoNotRestoreProperties The state machine should not save the initial values of properties
+ set in the state and restore them later.
+ \value RestoreProperties The state machine should save the initial values of properties
+ set in the state and restore them later.
+
+
+ \sa setRestorePolicy(), restorePolicy(), addEntryAction(), setPropertyOnEntry()
+*/
+
+QActionStatePrivate::QActionStatePrivate()
+ : restorePolicy(QActionState::GlobalRestorePolicy)
+{
+}
+
+QActionStatePrivate::~QActionStatePrivate()
+{
+}
+
+QActionStatePrivate *QActionStatePrivate::get(QActionState *q)
+{
+ return q->d_func();
+}
+
+const QActionStatePrivate *QActionStatePrivate::get(const QActionState *q)
+{
+ return q->d_func();
+}
+
+QList<QStateAction*> QActionStatePrivate::entryActions() const
+{
+ QList<QStateAction*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QStateAction *act = qobject_cast<QStateAction*>(*it);
+ if (act && (QStateActionPrivate::get(act)->when == QStateActionPrivate::ExecuteOnEntry))
+ result.append(act);
+ }
+ return result;
+}
+
+QList<QStateAction*> QActionStatePrivate::exitActions() const
+{
+ QList<QStateAction*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QStateAction *act = qobject_cast<QStateAction*>(*it);
+ if (act && (QStateActionPrivate::get(act)->when == QStateActionPrivate::ExecuteOnExit))
+ result.append(act);
+ }
+ return result;
+}
+
+/*!
+ Constructs a new action state with the given \a parent state.
+*/
+QActionState::QActionState(QState *parent)
+ : QAbstractState(*new QActionStatePrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QActionState::QActionState(QActionStatePrivate &dd,
+ QState *parent)
+ : QAbstractState(dd, parent)
+{
+}
+
+/*!
+ Destroys this action state.
+*/
+QActionState::~QActionState()
+{
+}
+
+/*!
+ Instructs this state to set the property with the given \a name of the given
+ \a object to the given \a value when the state is entered. This function
+ will create a QStateSetPropertyAction object and add it to the entry actions
+ of the state. If there is already an existing action associated with the
+ property, the value of that action is updated.
+
+ \sa setPropertyOnExit(), invokeMethodOnEntry(), addEntryAction()
+*/
+void QActionState::setPropertyOnEntry(QObject *object, const char *name,
+ const QVariant &value)
+{
+ Q_D(QActionState);
+ QList<QStateAction*> actions = d->entryActions();
+ for (int i=0; i<actions.size(); ++i) {
+ QStateAction *action = actions.at(i);
+ if (QStateSetPropertyAction *spa = qobject_cast<QStateSetPropertyAction*>(action)) {
+ if (spa->targetObject() == object && spa->propertyName() == name) {
+ QStateSetPropertyActionPrivate::get(spa)->value = value;
+ return;
+ }
+ }
+ }
+
+ addEntryAction(new QStateSetPropertyAction(object, name, value));
+}
+
+/*!
+ Instructs this state to set the property with the given \a name of the given
+ \a object to the given \a value when the state is exited. This function will
+ create a QStateSetPropertyAction object and add it to the exit actions of
+ the state. If there is already an existing action associated with the
+ property, the value of that action is updated.
+
+ \sa setPropertyOnEntry(), invokeMethodOnExit(), addExitAction()
+*/
+void QActionState::setPropertyOnExit(QObject *object, const char *name,
+ const QVariant &value)
+{
+ Q_D(QActionState);
+ QList<QStateAction*> actions = d->exitActions();
+ for (int i=0; i<actions.size(); ++i) {
+ QStateAction *action = actions.at(i);
+ if (QStateSetPropertyAction *spa = qobject_cast<QStateSetPropertyAction*>(action)) {
+ if (spa->targetObject() == object && spa->propertyName() == name) {
+ QStateSetPropertyActionPrivate::get(spa)->value = value;
+ return;
+ }
+ }
+ }
+
+ addExitAction(new QStateSetPropertyAction(object, name, value));
+}
+
+/*!
+ Instructs this state to invoke the given \a method of the given \a object
+ with the given \a arguments when the state is entered. This function will
+ create a QStateInvokeMethodAction object and add it to the entry actions of
+ the state.
+
+ \sa invokeMethodOnExit(), setPropertyOnEntry(), addEntryAction()
+*/
+void QActionState::invokeMethodOnEntry(QObject *object, const char *method,
+ const QList<QVariant> &arguments)
+{
+ addEntryAction(new QStateInvokeMethodAction(object, method, arguments));
+}
+
+/*!
+ Instructs this state to invoke the given \a method of the given \a object
+ with the given \a arguments when the state is exited. This function will
+ create a QStateInvokeMethodAction object and add it to the exit actions of
+ the state.
+
+ \sa invokeMethodOnEntry(), setPropertyOnExit(), addExitAction()
+*/
+void QActionState::invokeMethodOnExit(QObject *object, const char *method,
+ const QList<QVariant> &arguments)
+{
+ addExitAction(new QStateInvokeMethodAction(object, method, arguments));
+}
+
+/*!
+ Adds the given \a action to this state. The action will be executed when
+ this state is entered. The state takes ownership of the action.
+
+ \sa addExitAction(), removeEntryAction()
+*/
+void QActionState::addEntryAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QActionState::addEntryAction: cannot add null action");
+ return;
+ }
+ action->setParent(this);
+ QStateActionPrivate::get(action)->when = QStateActionPrivate::ExecuteOnEntry;
+}
+
+/*!
+ Adds the given \a action to this state. The action will be executed when
+ this state is exited. The state takes ownership of the action.
+
+ \sa addEntryAction(), removeExitAction()
+*/
+void QActionState::addExitAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QActionState::addExitAction: cannot add null action");
+ return;
+ }
+ action->setParent(this);
+ QStateActionPrivate::get(action)->when = QStateActionPrivate::ExecuteOnExit;
+}
+
+/*!
+ Removes the given entry \a action from this state. The state releases
+ ownership of the action.
+
+ \sa addEntryAction()
+*/
+void QActionState::removeEntryAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QActionState::removeEntryAction: cannot remove null action");
+ return;
+ }
+ if (action->parent() == this)
+ action->setParent(0);
+}
+
+/*!
+ Removes the given exit \a action from this state. The state releases
+ ownership of the action.
+
+ \sa addExitAction()
+*/
+void QActionState::removeExitAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QActionState::removeExitAction: cannot remove null action");
+ return;
+ }
+ if (action->parent() == this)
+ action->setParent(0);
+}
+
+/*!
+ Returns this state's entry actions.
+
+ \sa addEntryAction(), exitActions()
+*/
+QList<QStateAction*> QActionState::entryActions() const
+{
+ Q_D(const QActionState);
+ return d->entryActions();
+}
+
+/*!
+ Returns this state's exit actions.
+
+ \sa addExitAction(), entryActions()
+*/
+QList<QStateAction*> QActionState::exitActions() const
+{
+ Q_D(const QActionState);
+ return d->exitActions();
+}
+
+/*!
+ Sets the restore policy of this state to \a restorePolicy.
+
+ The default restore policy is QActionState::GlobalRestorePolicy.
+*/
+void QActionState::setRestorePolicy(RestorePolicy restorePolicy)
+{
+ Q_D(QActionState);
+ d->restorePolicy = restorePolicy;
+}
+
+/*!
+ Returns the restore policy for this state.
+*/
+QActionState::RestorePolicy QActionState::restorePolicy() const
+{
+ Q_D(const QActionState);
+ return d->restorePolicy;
+}
+
+/*!
+ \reimp
+*/
+void QActionState::onEntry()
+{
+ Q_D(QActionState);
+ QList<QStateAction*> actions = d->entryActions();
+ for (int i = 0; i < actions.size(); ++i)
+ QStateActionPrivate::get(actions.at(i))->callExecute();
+}
+
+/*!
+ \reimp
+*/
+void QActionState::onExit()
+{
+ Q_D(QActionState);
+ QList<QStateAction*> actions = d->exitActions();
+ for (int i = 0; i < actions.size(); ++i)
+ QStateActionPrivate::get(actions.at(i))->callExecute();
+}
+
+/*!
+ \reimp
+*/
+bool QActionState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qactionstate.h b/src/corelib/statemachine/qactionstate.h
new file mode 100644
index 0000000..2af9d4a
--- /dev/null
+++ b/src/corelib/statemachine/qactionstate.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACTIONSTATE_H
+#define QACTIONSTATE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qabstractstate.h>
+#else
+#include "qabstractstate.h"
+#endif
+
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QStateAction;
+
+class QActionStatePrivate;
+class Q_CORE_EXPORT QActionState : public QAbstractState
+{
+ Q_OBJECT
+public:
+ enum RestorePolicy {
+ GlobalRestorePolicy,
+ DoNotRestoreProperties,
+ RestoreProperties
+ };
+
+ QActionState(QState *parent = 0);
+ ~QActionState();
+
+ void setPropertyOnEntry(QObject *object, const char *name,
+ const QVariant &value);
+ void setPropertyOnExit(QObject *object, const char *name,
+ const QVariant &value);
+ void invokeMethodOnEntry(QObject *object, const char *method,
+ const QList<QVariant> &args = QList<QVariant>());
+ void invokeMethodOnExit(QObject *object, const char *method,
+ const QList<QVariant> &args = QList<QVariant>());
+
+ void addEntryAction(QStateAction *action);
+ void addExitAction(QStateAction *action);
+
+ void removeEntryAction(QStateAction *action);
+ void removeExitAction(QStateAction *action);
+
+ QList<QStateAction*> entryActions() const;
+ QList<QStateAction*> exitActions() const;
+
+ void setRestorePolicy(RestorePolicy restorePolicy);
+ RestorePolicy restorePolicy() const;
+
+protected:
+ void onEntry();
+ void onExit();
+
+ bool event(QEvent *e);
+
+protected:
+ QActionState(QActionStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QActionState)
+ Q_DECLARE_PRIVATE(QActionState)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qactionstate_p.h b/src/corelib/statemachine/qactionstate_p.h
new file mode 100644
index 0000000..69343f8
--- /dev/null
+++ b/src/corelib/statemachine/qactionstate_p.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACTIONSTATE_P_H
+#define QACTIONSTATE_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 "qabstractstate_p.h"
+#include "qactionstate.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStateAction;
+
+class QActionState;
+class Q_CORE_EXPORT QActionStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QActionState)
+
+public:
+ QActionStatePrivate();
+ ~QActionStatePrivate();
+
+ static QActionStatePrivate *get(QActionState *q);
+ static const QActionStatePrivate *get(const QActionState *q);
+
+ QList<QStateAction*> entryActions() const;
+ QList<QStateAction*> exitActions() const;
+
+ QActionState::RestorePolicy restorePolicy;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qanimationstate.cpp b/src/corelib/statemachine/qanimationstate.cpp
new file mode 100644
index 0000000..b963950
--- /dev/null
+++ b/src/corelib/statemachine/qanimationstate.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_ANIMATION
+
+#include "qanimationstate.h"
+#include "qparallelanimationgroup.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qstatefinishedtransition.h"
+#include "qsignaltransition.h"
+#include "qpropertyanimation.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include "qstateaction.h"
+#include "qstateaction_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qfinalstate.h"
+#include "qsignaltransition_p.h"
+#ifdef QT_STATEMACHINE_SOLUTION
+#include "qvariantanimation_p.h"
+#else
+#include "private/qvariantanimation_p.h"
+#endif
+#include "qpauseanimation.h"
+
+#include <QtCore/qhash.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qbitarray.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAnimationState
+ \brief The QAnimationState class provides a state that plays one or more animations.
+ \ingroup statemachine
+ \preliminary
+
+ QAnimationState is part of \l{The State Machine Framework}.
+
+ The addAnimation() function adds an animation to be played by the state.
+
+ When the state is entered, it will call each of the animations' start() functions.
+ When the animation is finished, a QStateFinishedEvent is posted; you can
+ use the QStateFinishedTransition class to associate a transition with this
+ event.
+
+ \code
+ QPushButton button;
+ QPropertyAnimation animation(&button, "geometry");
+ animation.setEndValue(QRect(100, 100, 400, 400));
+
+ QStateMachine machine;
+ QAnimationState *s1 = new QAnimationState(&animation, machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ s1->addFinishedTransition(s2);
+ \endcode
+
+ If the state is exited before the animation has finished, the animations will
+ be stopped, and no event is generated.
+
+ For convenience, the QState::addAnimatedTransition() functions can be used to set up the
+ animated transition between two states.
+
+ \section1 Initializing animations automatically
+ QAnimationState will try to automatically initialize any QPropertyAnimation for which no
+ specific end value has been set. It will set the animation's end value based on actions in the
+ target state of the animation state's QStateFinishedTransition.
+
+ The only actions evaluated are the entry actions of the very first states entered after the
+ animation state has finished.
+
+ QAnimationState will match its QPropertyAnimation objects with QStateSetPropertyAction objects
+ in the target states that manipulate the same property on the same object. The end values of the
+ animations will be initialized to the values set by the actions.
+
+ \code
+ QPushButton button;
+ QPropertyAnimation animation(&button, "geometry");
+
+ QStateMachine machine;
+ QAnimationState *s1 = new QAnimationState(&animation, machine.rootState());
+ QState *s2 = new QState(machine.rootState());
+ s2->setPropertyOnEntry(&button, "geometry", QRect(100, 100, 400, 400));
+
+ s1->addFinishedTransition(s2);
+ \endcode
+
+ Specifically, QAnimationState will evaluate the actions set for the target state itself, and
+ also look in following locations:
+ objects:
+ \list
+ \i If the state has children and is not parallel, actions set for its initial
+ state will be evaluated.
+ \i If the state has children and is parallel, actions set for any of its children will be
+ evaluated.
+ \endlist
+
+ Children of the target state will be evaluated recursively.
+
+ \section1 Animated restoring of properties
+
+ When a state has restore policy QActionState::RestoreProperties, any
+ property that is set in the state using the QStateSetPropertyAction will
+ potentially be restored to its original value later on. When regular,
+ unanimated transitions are used, the properties will be restored when the
+ state machine enters one or more states that do not explicitly set the
+ property.
+
+ When QAnimationState is used, it will restore the property with an
+ animation. Rather than have the state machine restore the properties as it
+ enters the target state, they will be restored by the QAnimationState in
+ parallel to the regular animations that have been added to the state.
+
+ If no animation has been added to the state, only the restore animations
+ will be played.
+
+ The animations used to restore the properties are QPropertyAnimations with
+ with the default easing curve and duration.
+
+ \sa QActionState::RestorePolicy, QPropertyAnimation, QStateSetPropertyAction,
+ QState::addAnimatedTransition()
+
+*/
+
+namespace {
+
+class AnimatingState : public QState
+{
+public:
+ AnimatingState(QState *parent)
+ : QState(parent) {}
+protected:
+ void onEntry() {}
+ void onExit() {}
+};
+
+class AnimationFinishedState : public QFinalState
+{
+public:
+ AnimationFinishedState(QState *parent)
+ : QFinalState(parent)
+ {
+ }
+
+protected:
+ void onEntry() {}
+ void onExit() {}
+};
+
+class AnimationFinishedTransition: public QSignalTransition
+{
+public:
+ AnimationFinishedTransition(QAbstractAnimation *animation,
+ QAnimationStatePrivate *animationState_d,
+ QAbstractState *target)
+ : QSignalTransition(animation, SIGNAL(finished()), QList<QAbstractState*>() << target),
+ m_animationState_d(animationState_d)
+ {
+ }
+
+ virtual bool eventTest(QEvent *) const;
+
+private:
+ QAnimationStatePrivate *m_animationState_d;
+};
+
+} // namespace
+
+class QAnimationStatePrivate : public QStatePrivate
+{
+ Q_DECLARE_PUBLIC(QAnimationState)
+
+public:
+ typedef QStateMachinePrivate::RestorableId RestorableId;
+
+ QAnimationStatePrivate();
+ void init();
+ QAbstractTransition *finishedTransition() const;
+
+ void initializeAnimation(const QList<QStateAction*> &actions, QActionState::RestorePolicy restorePolicy);
+ void initializeAnimation(const QList<QAbstractState*> &targets);
+ void initializeAnimationFromAction(QAbstractAnimation *anim,
+ QStateAction *action,
+ QActionState::RestorePolicy restorePolicy);
+
+ void restoreAnimations();
+
+ void addAnimation(QAbstractAnimation *animation, QList<QAbstractAnimation*> &list);
+ void removeAnimation(QAbstractAnimation *animation, QList<QAbstractAnimation*> &list);
+
+ QList<QAbstractAnimation *> animations;
+ QList<QAbstractAnimation *> restorationAnimations;
+ QList<QPropertyAnimation *> resetEndValues;
+ QState *animatingState;
+ QFinalState *finishedState;
+ QTimer *timer;
+
+ uint initializeAnimationFromTargetStates : 1;
+ uint initializeAnimationFromRestorableVariables : 1;
+ uint reserved : 30;
+
+ QHash<RestorableId, QVariant> pendingRestorables;
+};
+
+// implement here because it requires the definition of QAnimationStatePrivate.
+namespace {
+ bool AnimationFinishedTransition::eventTest(QEvent *e) const
+ {
+ if (!QSignalTransition::eventTest(e))
+ return false;
+
+ QList<QAbstractAnimation *> animations = m_animationState_d->animations;
+ QList<QAbstractAnimation *> restorationAnimations = m_animationState_d->restorationAnimations;
+
+ for (int i=0; i<animations.size(); ++i) {
+ if (animations.at(i)->state() != QAbstractAnimation::Stopped)
+ return false;
+ }
+
+ for (int i=0; i<restorationAnimations.size(); ++i) {
+ if (restorationAnimations.at(i)->state() != QAbstractAnimation::Stopped)
+ return false;
+ }
+
+ return true;
+ }
+}
+
+QAnimationStatePrivate::QAnimationStatePrivate()
+{
+}
+
+void QAnimationStatePrivate::init()
+{
+ Q_Q(QAnimationState);
+
+ // ### make it a configurable property, as it is highly magical
+ initializeAnimationFromTargetStates = true;
+ initializeAnimationFromRestorableVariables = true;
+
+ animatingState = new AnimatingState(q);
+ q->setInitialState(animatingState);
+ finishedState = new AnimationFinishedState(q);
+
+ timer = 0;
+}
+
+void QAnimationStatePrivate::addAnimation(QAbstractAnimation *animation,
+ QList<QAbstractAnimation*> &list)
+{
+ if (animation != 0 && !list.contains(animation)) {
+ list.append(animation);
+ AnimationFinishedTransition *transition = new AnimationFinishedTransition(animation, this, finishedState);
+ animatingState->addTransition(transition);
+ }
+}
+
+void QAnimationStatePrivate::removeAnimation(QAbstractAnimation *animation,
+ QList<QAbstractAnimation*> &list)
+{
+ if (animation != 0 && list.contains(animation)) {
+ QStatePrivate *state_d = QStatePrivate::get(animatingState);
+ QList<QAbstractTransition *> transitions = state_d->transitions();
+ Q_ASSERT(transitions.size() > 0);
+ for (int i=0; i<transitions.size(); ++i) {
+ QSignalTransition *transition = qobject_cast<QSignalTransition *>(transitions.at(i));
+
+ if (transition != 0) {
+ QSignalTransitionPrivate *transition_p = QSignalTransitionPrivate::get(transition);
+ if (transition_p->sender == animation) {
+ delete transition;
+ break;
+ }
+ }
+ }
+
+ list.removeAll(animation);
+ }
+}
+
+/*!
+ \internal
+
+ Returns a transition from this state that is triggered when this state is
+ finished, or 0 if there is no such transition.
+*/
+QAbstractTransition *QAnimationStatePrivate::finishedTransition() const
+{
+ QList<QAbstractTransition*> trans = transitions();
+ for (int i = 0; i < trans.size(); ++i) {
+ QAbstractTransition *t = trans.at(i);
+ if (QStateFinishedTransition *sft = qobject_cast<QStateFinishedTransition*>(t))
+ return sft;
+ }
+ return 0;
+}
+
+void QAnimationStatePrivate::initializeAnimationFromAction(QAbstractAnimation *abstractAnimation,
+ QStateAction *action,
+ QActionState::RestorePolicy restorePolicy)
+{
+ QAnimationGroup *group = qobject_cast<QAnimationGroup*>(abstractAnimation);
+ if (group) {
+ for (int i = 0; i < group->animationCount(); ++i) {
+ QAbstractAnimation *animationChild = group->animationAt(i);
+ initializeAnimationFromAction(animationChild, action, restorePolicy);
+ }
+ } else {
+ QPropertyAnimation *animation = qobject_cast<QPropertyAnimation *>(abstractAnimation);
+ QStateSetPropertyAction *propertyAction = qobject_cast<QStateSetPropertyAction*>(action);
+ if (propertyAction != 0
+ && animation != 0
+ && propertyAction->targetObject() == animation->targetObject()
+ && propertyAction->propertyName() == animation->propertyName()) {
+
+ if (!animation->startValue().isValid()) {
+ QByteArray propertyName = animation->propertyName();
+ QVariant currentValue = animation->targetObject()->property(propertyName);
+
+ QVariantAnimationPrivate::get(animation)->setDefaultStartValue(currentValue);
+ }
+
+ // Only change end value if it is undefined
+ if (!animation->endValue().isValid()) {
+ QStateMachinePrivate *machine_d = QStateMachinePrivate::get(machine());
+ if (restorePolicy == QActionState::RestoreProperties)
+ machine_d->registerRestorable(animation);
+
+ RestorableId id(animation->targetObject(), animation->propertyName());
+ pendingRestorables.remove(id);
+
+ animation->setEndValue(propertyAction->value());
+ resetEndValues.append(animation);
+ }
+ }
+ }
+}
+
+void QAnimationStatePrivate::initializeAnimation(const QList<QStateAction*> &actions,
+ QActionState::RestorePolicy restorePolicy)
+{
+
+ for (int i = 0; i < actions.size(); ++i) {
+ QStateAction *act = actions.at(i);
+
+ for (int j=0; j<animations.size(); ++j)
+ initializeAnimationFromAction(animations.at(j), act, restorePolicy);
+ }
+
+
+}
+
+void QAnimationStatePrivate::initializeAnimation(const QList<QAbstractState*> &targets)
+{
+ // ### consider resulting action order, and how to resolve conflicts (two actions that set the same property)
+ for (int i = 0; i < targets.size(); ++i) {
+ QActionState *s = qobject_cast<QActionState*>(targets.at(i));
+ if (s != 0) {
+ QActionState::RestorePolicy restorePolicy = s->restorePolicy();
+ if (restorePolicy == QActionState::GlobalRestorePolicy)
+ restorePolicy = machine()->globalRestorePolicy();
+ initializeAnimation(QActionStatePrivate::get(s)->entryActions(), restorePolicy);
+ }
+
+ if (QStateMachinePrivate::isParallel(s)) {
+ initializeAnimation(QStatePrivate::get(qobject_cast<QState*>(s))->childStates());
+ } else if (QStateMachinePrivate::isCompound(s)) {
+ initializeAnimation(QList<QAbstractState*>() << qobject_cast<QState*>(s)->initialState());
+ }
+ }
+}
+
+void QAnimationStatePrivate::restoreAnimations()
+{
+ QStateMachinePrivate *machine_d = QStateMachinePrivate::get(machine());
+
+ QHash<RestorableId, QVariant>::const_iterator it;
+ for (it=pendingRestorables.constBegin(); it != pendingRestorables.constEnd(); ++it) {
+ QPropertyAnimation *animation = machine_d->registeredRestorableAnimations.value(it.key());
+ if (animation == 0)
+ continue;
+
+ // ### Check if this works
+ // animation->setDirection(QAbstractAnimation::Backward);
+
+ QPropertyAnimation *clonedAnimation = new QPropertyAnimation(animation->targetObject(),
+ animation->propertyName());
+ clonedAnimation->setEasingCurve(animation->easingCurve());
+ clonedAnimation->setEndValue(it.value());
+
+ addAnimation(clonedAnimation, restorationAnimations);
+ }
+
+ pendingRestorables.clear();
+}
+
+
+/*!
+ Constructs a new QAnimationState object with the given \a animation and \a
+ parent state
+*/
+QAnimationState::QAnimationState(QAbstractAnimation *animation, QState *parent)
+ : QState(*new QAnimationStatePrivate, parent)
+{
+ Q_D(QAnimationState);
+ d->init();
+
+ if (animation != 0)
+ addAnimation(animation);
+}
+
+/*!
+ Constructs a new QAnimationState object with the given \a parent state.
+*/
+QAnimationState::QAnimationState(QState *parent)
+ : QState(*new QAnimationStatePrivate, parent)
+{
+ Q_D(QAnimationState);
+ d->init();
+}
+
+/*!
+ Destroys this QAnimationState.
+*/
+QAnimationState::~QAnimationState()
+{
+}
+
+/*!
+ Returns the number of animations added to this QAnimationState.
+*/
+int QAnimationState::animationCount() const
+{
+ Q_D(const QAnimationState);
+ return d->animations.size();
+}
+
+/*!
+ Returns the animation associated with this QAnimationState at index \a i.
+*/
+QAbstractAnimation *QAnimationState::animationAt(int i) const
+{
+ Q_D(const QAnimationState);
+ return d->animations.at(i);
+}
+
+/*!
+ Adds \a animation to this QAnimationState.
+*/
+void QAnimationState::addAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationState);
+ if (animation == 0) {
+ qWarning("QAnimationState::addAnimation: Cannot add null animation");
+ return;
+ }
+
+ d->addAnimation(animation, d->animations);
+}
+
+/*!
+ Removes \a animation from this QAnimationState.
+*/
+void QAnimationState::removeAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAnimationState);
+ d->removeAnimation(animation, d->animations);
+}
+
+/*!
+ \reimp
+*/
+void QAnimationState::onEntry()
+{
+ Q_D(QAnimationState);
+
+ {
+ QStateMachinePrivate *machine_d = QStateMachinePrivate::get(d->machine());
+ d->pendingRestorables = machine_d->registeredRestorables;
+ }
+
+ if (d->initializeAnimationFromTargetStates) {
+ if (QAbstractTransition *t = d->finishedTransition())
+ d->initializeAnimation(t->targetStates());
+ }
+
+ if (d->initializeAnimationFromRestorableVariables)
+ d->restoreAnimations();
+
+ for (int i=0; i<d->animations.size(); ++i)
+ d->animations.at(i)->start();
+
+ for (int i=0; i<d->restorationAnimations.size(); ++i)
+ d->restorationAnimations.at(i)->start();
+
+ // If there are no animations playing, we use a 0 timer to trigger the transition
+ // to the final state
+ if (d->animations.size()+d->restorationAnimations.size() == 0) {
+ if (d->timer == 0) {
+ d->timer = new QTimer(this);
+ d->timer->setInterval(0);
+ d->timer->setSingleShot(true);
+
+ d->animatingState->addTransition(d->timer, SIGNAL(timeout()), d->finishedState);
+ }
+
+ d->timer->start();
+ }
+
+}
+
+/*!
+ \reimp
+*/
+void QAnimationState::onExit()
+{
+ Q_D(QAnimationState);
+
+ for (int i=0; i<d->animations.size(); ++i) {
+ if (d->animations.at(i)->state() != QAbstractAnimation::Stopped)
+ d->animations.at(i)->stop();
+ }
+
+ QList<QAbstractAnimation *> restorationAnimations = d->restorationAnimations;
+ for (int i=0; i<restorationAnimations.size(); ++i) {
+ QAbstractAnimation *restorationAnimation = restorationAnimations.at(i);
+ if (restorationAnimation->state() != QAbstractAnimation::Stopped) {
+ restorationAnimation->stop();
+ d->removeAnimation(restorationAnimation, d->restorationAnimations);
+
+ // ###
+ delete restorationAnimation;
+ } else {
+ QPropertyAnimation *propertyAnimation = qobject_cast<QPropertyAnimation*>(restorationAnimation);
+ if (propertyAnimation != 0) {
+ QStateMachinePrivate *machine_d = QStateMachinePrivate::get(d->machine());
+ machine_d->unregisterRestorable(propertyAnimation->targetObject(),
+ propertyAnimation->propertyName());
+ }
+ }
+ }
+
+ for (int i=0; i<d->resetEndValues.size(); ++i)
+ d->resetEndValues.at(i)->setEndValue(QVariant());
+
+ if (d->timer != 0)
+ d->timer->stop();
+}
+
+/*!
+ \reimp
+*/
+bool QAnimationState::event(QEvent *e)
+{
+ return QState::event(e);
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ANIMATION
diff --git a/src/corelib/statemachine/qanimationstate.h b/src/corelib/statemachine/qanimationstate.h
new file mode 100644
index 0000000..5d11041
--- /dev/null
+++ b/src/corelib/statemachine/qanimationstate.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANIMATIONSTATE_H
+#define QANIMATIONSTATE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qstate.h>
+#else
+#include "qstate.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_ANIMATION
+
+class QAbstractAnimation;
+
+class QAnimationStatePrivate;
+class Q_CORE_EXPORT QAnimationState : public QState
+{
+ Q_OBJECT
+public:
+
+ QAnimationState(QAbstractAnimation *animation, QState *parent = 0);
+ QAnimationState(QState *parent = 0);
+ ~QAnimationState();
+
+ int animationCount() const;
+ QAbstractAnimation *animationAt(int i) const;
+ void addAnimation(QAbstractAnimation *animation);
+ void removeAnimation(QAbstractAnimation *animation);
+
+protected:
+ virtual void onEntry();
+ virtual void onExit();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QAnimationState)
+ Q_DECLARE_PRIVATE(QAnimationState)
+};
+
+#endif //QT_NO_ANIMATION
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QANIMATIONSTATE_H
diff --git a/src/corelib/statemachine/qboundevent_p.h b/src/corelib/statemachine/qboundevent_p.h
new file mode 100644
index 0000000..5f31372
--- /dev/null
+++ b/src/corelib/statemachine/qboundevent_p.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBOUNDEVENT_P_H
+#define QBOUNDEVENT_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/qcoreevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBoundEvent : public QEvent
+{
+public:
+ QBoundEvent(QObject *object, QEvent *event)
+#ifdef QT_STATEMACHINE_SOLUTION
+ : QEvent(QEvent::Type(QEvent::User-3)),
+#else
+ : QEvent(QEvent::Bound),
+#endif
+ m_object(object), m_event(event) {}
+ ~QBoundEvent() {}
+
+ inline QObject *object() const { return m_object; }
+ inline QEvent *event() const { return m_event; }
+
+private:
+ QObject *m_object;
+ QEvent *m_event;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp
new file mode 100644
index 0000000..65f0075
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qeventtransition.h"
+#include "qeventtransition_p.h"
+#include "qboundevent_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QEventTransition
+
+ \brief The QEventTransition class provides a QObject-specific transition for Qt events.
+
+ \ingroup statemachine
+
+ A QEventTransition object binds an event or transition to a particular
+ QObject. QEventTransition is part of \l{The State Machine Framework}.
+
+ Example:
+
+ \code
+ QPushButton *button = ...;
+ QState *s1 = ...;
+ QState *s2 = ...;
+ // If in s1 and the button receives an Enter event, transition to s2
+ QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter);
+ enterTransition->setTargetState(s2);
+ s1->addTransition(enterTransition);
+ // If in s2 and the button receives an Exit event, transition back to s1
+ QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave);
+ leaveTransition->setTargetState(s1);
+ s2->addTransition(leaveTransition);
+ \endcode
+
+ \section1 Subclassing
+
+ Many event classes have attributes in addition to the event type itself.
+ The testEventCondition() function can be reimplemented to check attributes
+ of an event instance in order to determine whether the transition should be
+ triggered or not.
+
+ \sa QState::addTransition()
+*/
+
+/*!
+ \property QEventTransition::object
+
+ \brief the event source that this event transition is associated with
+*/
+
+QEventTransitionPrivate::QEventTransitionPrivate()
+{
+ object = 0;
+ eventType = QEvent::None;
+ registered = false;
+}
+
+QEventTransitionPrivate *QEventTransitionPrivate::get(QEventTransition *q)
+{
+ return q->d_func();
+}
+
+void QEventTransitionPrivate::invalidate()
+{
+ Q_Q(QEventTransition);
+ if (registered) {
+ QState *source = sourceState();
+ QStatePrivate *source_d = QStatePrivate::get(source);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(source_d->machine());
+ if (mach) {
+ mach->unregisterEventTransition(q);
+ if (mach->configuration.contains(source))
+ mach->registerEventTransition(q);
+ }
+ }
+}
+
+/*!
+ Constructs a new QEventTransition object with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QState *sourceState)
+ : QTransition(*new QEventTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new QEventTransition object associated with events of the given
+ \a type for the given \a object, and with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
+ QState *sourceState)
+ : QTransition(*new QEventTransitionPrivate, sourceState)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ Constructs a new QEventTransition object associated with events of the given
+ \a type for the given \a object. The transition has the given \a targets and
+ \a sourceState.
+*/
+QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
+ const QList<QAbstractState*> &targets,
+ QState *sourceState)
+ : QTransition(*new QEventTransitionPrivate, targets, sourceState)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QState *parent)
+ : QTransition(dd, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent)
+ : QTransition(dd, parent)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, const QList<QAbstractState*> &targets,
+ QState *parent)
+ : QTransition(dd, targets, parent)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object = object;
+ d->eventType = type;
+}
+
+/*!
+ Destroys this QObject event transition.
+*/
+QEventTransition::~QEventTransition()
+{
+}
+
+/*!
+ Returns the event type that this event transition is associated with.
+*/
+QEvent::Type QEventTransition::eventType() const
+{
+ Q_D(const QEventTransition);
+ return d->eventType;
+}
+
+/*!
+ Sets the event \a type that this event transition is associated with.
+*/
+void QEventTransition::setEventType(QEvent::Type type)
+{
+ Q_D(QEventTransition);
+ if (d->eventType == type)
+ return;
+ d->eventType = type;
+ d->invalidate();
+}
+
+/*!
+ Returns the event source associated with this event transition.
+*/
+QObject *QEventTransition::eventSource() const
+{
+ Q_D(const QEventTransition);
+ return d->object;
+}
+
+/*!
+ Sets the event source associated with this event transition to be the given
+ \a object.
+*/
+void QEventTransition::setEventSource(QObject *object)
+{
+ Q_D(QEventTransition);
+ if (d->object == object)
+ return;
+ d->object = object;
+ d->invalidate();
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::eventTest(QEvent *event) const
+{
+ Q_D(const QEventTransition);
+#ifdef QT_STATEMACHINE_SOLUTION
+ if (event->type() == QEvent::Type(QEvent::User-3)) {
+#else
+ if (event->type() == QEvent::Bound) {
+#endif
+ QBoundEvent *oe = static_cast<QBoundEvent*>(event);
+ return (oe->object() == d->object)
+ && (oe->event()->type() == d->eventType)
+ && testEventCondition(oe->event());
+ }
+ return false;
+}
+
+/*!
+ Tests an instance of an event associated with this event transition and
+ returns true if the transition should be taken, otherwise returns false.
+ The type of the given \a event will be eventType().
+
+ Reimplement this function if you have custom conditions associated with
+ the transition. The default implementation always returns true.
+*/
+bool QEventTransition::testEventCondition(QEvent *event) const
+{
+ Q_UNUSED(event);
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QEventTransition::onTransition()
+{
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::event(QEvent *e)
+{
+ return QTransition::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h
new file mode 100644
index 0000000..ece79e8
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTTRANSITION_H
+#define QEVENTTRANSITION_H
+
+#include "qtransition.h"
+#include <QtCore/qcoreevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEventTransitionPrivate;
+class Q_CORE_EXPORT QEventTransition : public QTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* object READ eventSource WRITE setEventSource)
+ Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType)
+public:
+ QEventTransition(QState *sourceState = 0);
+ QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0);
+ QEventTransition(QObject *object, QEvent::Type type,
+ const QList<QAbstractState*> &targets, QState *sourceState = 0);
+ ~QEventTransition();
+
+ QObject *eventSource() const;
+ void setEventSource(QObject *object);
+
+ QEvent::Type eventType() const;
+ void setEventType(QEvent::Type type);
+
+protected:
+ virtual bool testEventCondition(QEvent *event) const; // ### name
+
+ bool eventTest(QEvent *event) const;
+ void onTransition();
+
+ bool event(QEvent *e);
+
+protected:
+ QEventTransition(QEventTransitionPrivate &dd, QState *parent);
+ QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent);
+ QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, const QList<QAbstractState*> &targets,
+ QState *parent);
+
+private:
+ Q_DISABLE_COPY(QEventTransition)
+ Q_DECLARE_PRIVATE(QEventTransition)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qeventtransition_p.h b/src/corelib/statemachine/qeventtransition_p.h
new file mode 100644
index 0000000..55ea9e6
--- /dev/null
+++ b/src/corelib/statemachine/qeventtransition_p.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEVENTTRANSITION_P_H
+#define QEVENTTRANSITION_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 "qtransition_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEventTransition;
+class Q_CORE_EXPORT QEventTransitionPrivate : public QTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QEventTransition)
+public:
+ QEventTransitionPrivate();
+
+ static QEventTransitionPrivate *get(QEventTransition *q);
+
+ void invalidate();
+
+ bool registered;
+ QObject *object;
+ QEvent::Type eventType;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp
new file mode 100644
index 0000000..c4dbcc9
--- /dev/null
+++ b/src/corelib/statemachine/qfinalstate.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qfinalstate.h"
+#include "qactionstate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFinalState
+
+ \brief The QFinalState class provides a final state.
+
+ \ingroup statemachine
+
+ A final state is used to communicate that (part of) a QStateMachine has
+ finished its work. When a final top-level state is entered, the state
+ machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In
+ general, when a final substate (a child of a QState) is entered, a
+ QStateFinishedEvent is generated for the final state's parent
+ state. QFinalState is part of \l{The State Machine Framework}.
+
+ To use a final state, you create a QFinalState object and add a transition
+ to it from another state. Example:
+
+ \code
+ QPushButton button;
+
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(&button, SIGNAL(clicked()), s2);
+ machine.addState(s1);
+ machine.addState(s2);
+
+ QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
+ machine.setInitialState(s1);
+ machine.start();
+ \endcode
+
+ \sa QStateFinishedTransition
+*/
+
+class QFinalStatePrivate : public QActionStatePrivate
+{
+ Q_DECLARE_PUBLIC(QFinalState)
+
+public:
+ QFinalStatePrivate();
+};
+
+QFinalStatePrivate::QFinalStatePrivate()
+{
+}
+
+/*!
+ Constructs a new QFinalState object with the given \a parent state.
+*/
+QFinalState::QFinalState(QState *parent)
+ : QActionState(*new QFinalStatePrivate, parent)
+{
+}
+
+/*!
+ Destroys this final state.
+*/
+QFinalState::~QFinalState()
+{
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onEntry()
+{
+ QActionState::onEntry();
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onExit()
+{
+ QActionState::onExit();
+}
+
+/*!
+ \reimp
+*/
+bool QFinalState::event(QEvent *e)
+{
+ return QActionState::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h
new file mode 100644
index 0000000..ba69c36
--- /dev/null
+++ b/src/corelib/statemachine/qfinalstate.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFINALSTATE_H
+#define QFINALSTATE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qactionstate.h>
+#else
+#include "qactionstate.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QFinalStatePrivate;
+class Q_CORE_EXPORT QFinalState : public QActionState
+{
+ Q_OBJECT
+public:
+ QFinalState(QState *parent = 0);
+ ~QFinalState();
+
+protected:
+ void onEntry();
+ void onExit();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QFinalState)
+ Q_DECLARE_PRIVATE(QFinalState)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp
new file mode 100644
index 0000000..a3da4be
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHistoryState
+
+ \brief The QHistoryState class provides a means of returning to a previously active substate.
+
+ \ingroup statemachine
+
+ A history state is a pseudo-state that represents the child state that the
+ parent state was in the last time the parent state was exited. A transition
+ with a history state as its target is in fact a transition to one of the
+ other child states of the parent state. QHistoryState is part of \l{The
+ State Machine Framework}.
+
+ Use QState::addHistoryState() to construct a history state. Use the
+ setDefaultState() function to set the state that should be entered if the
+ parent state has never been entered. Example:
+
+ \code
+ QStateMachine machine;
+
+ QState *s1 = new QState();
+ QState *s11 = new QState(s1);
+ QState *s12 = new QState(s1);
+
+ QState *s1h = s1->addHistoryState();
+ s1h->setDefaultState(s11);
+
+ machine.addState(s1);
+
+ QState *s2 = new QState();
+ machine.addState(s2);
+
+ QPushButton *button = new QPushButton();
+ // Clicking the button will cause the state machine to enter the child state
+ // that s1 was in the last time s1 was exited, or the history state's default
+ // state if s1 has never been entered.
+ s1->addTransition(button, SIGNAL(clicked()), s1h);
+ \endcode
+*/
+
+QHistoryStatePrivate::QHistoryStatePrivate()
+ : defaultState(0)
+{
+}
+
+QHistoryState *QHistoryStatePrivate::create(QState::HistoryType type,
+ QState *parent)
+{
+ return new QHistoryState(type, parent);
+}
+
+QHistoryStatePrivate *QHistoryStatePrivate::get(QHistoryState *q)
+{
+ return q->d_func();
+}
+
+const QHistoryStatePrivate *QHistoryStatePrivate::get(const QHistoryState *q)
+{
+ return q->d_func();
+}
+
+/*!
+ \internal
+
+ Constructs a new history state of the given \a type, with the given \a
+ parent state.
+*/
+QHistoryState::QHistoryState(QState::HistoryType type, QState *parent)
+ : QAbstractState(*new QHistoryStatePrivate, parent)
+{
+ Q_D(QHistoryState);
+ d->historyType = type;
+}
+
+/*!
+ Destroys this history state.
+*/
+QHistoryState::~QHistoryState()
+{
+}
+
+/*!
+ Returns this history state's default state. The default state indicates the
+ state to transition to if the parent state has never been entered before.
+*/
+QAbstractState *QHistoryState::defaultState() const
+{
+ Q_D(const QHistoryState);
+ return d->defaultState;
+}
+
+/*!
+ Sets this history state's default state to be the given \a state.
+ \a state must be a sibling of this history state.
+*/
+void QHistoryState::setDefaultState(QAbstractState *state)
+{
+ Q_D(QHistoryState);
+ if (state && state->parentState() != parentState()) {
+ qWarning("QHistoryState::setDefaultState: state %p does not belong "
+ "to this history state's group (%p)", state, parentState());
+ return;
+ }
+ d->defaultState = state;
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onEntry()
+{
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onExit()
+{
+}
+
+/*!
+ \reimp
+*/
+bool QHistoryState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h
new file mode 100644
index 0000000..a18d064
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHISTORYSTATE_H
+#define QHISTORYSTATE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qstate.h>
+#else
+#include "qstate.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QHistoryStatePrivate;
+class Q_CORE_EXPORT QHistoryState : public QAbstractState
+{
+ Q_OBJECT
+public:
+ ~QHistoryState();
+
+ QAbstractState *defaultState() const;
+ void setDefaultState(QAbstractState *state);
+
+protected:
+ void onEntry();
+ void onExit();
+
+ bool event(QEvent *e);
+
+private:
+ QHistoryState(QState::HistoryType type,
+ QState *parent = 0);
+
+private:
+ Q_DISABLE_COPY(QHistoryState)
+ Q_DECLARE_PRIVATE(QHistoryState)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qhistorystate_p.h b/src/corelib/statemachine/qhistorystate_p.h
new file mode 100644
index 0000000..1a2461b
--- /dev/null
+++ b/src/corelib/statemachine/qhistorystate_p.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHISTORYSTATE_P_H
+#define QHISTORYSTATE_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 "qabstractstate_p.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHistoryState;
+class QHistoryStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QHistoryState)
+
+public:
+ QHistoryStatePrivate();
+
+ static QHistoryState *create(QState::HistoryType type,
+ QState *parent);
+
+ static QHistoryStatePrivate *get(QHistoryState *q);
+ static const QHistoryStatePrivate *get(const QHistoryState *q);
+
+ QAbstractState *defaultState;
+ QState::HistoryType historyType;
+ QList<QAbstractState*> configuration;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h
new file mode 100644
index 0000000..50ac380
--- /dev/null
+++ b/src/corelib/statemachine/qsignalevent.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALEVENT_H
+#define QSIGNALEVENT_H
+
+#include <QtCore/qcoreevent.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class Q_CORE_EXPORT QSignalEvent : public QEvent
+{
+public:
+ QSignalEvent(const QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments);
+ ~QSignalEvent();
+
+ inline const QObject *sender() const { return m_sender; }
+ inline int signalIndex() const { return m_signalIndex; }
+ inline QList<QVariant> arguments() const { return m_arguments; }
+
+private:
+ const QObject *m_sender;
+ int m_signalIndex;
+ QList<QVariant> m_arguments;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h
new file mode 100644
index 0000000..1d4e7d7
--- /dev/null
+++ b/src/corelib/statemachine/qsignaleventgenerator_p.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALEVENTGENERATOR_P_H
+#define QSIGNALEVENTGENERATOR_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/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachine;
+
+class QSignalEventGenerator : public QObject
+{
+public:
+ QSignalEventGenerator(
+#ifdef QT_STATEMACHINE_SOLUTION
+ int signalIndex,
+#endif
+ QStateMachine *parent);
+
+ static const QMetaObject staticMetaObject;
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **argv);
+
+private:
+#ifdef QT_STATEMACHINE_SOLUTION
+ int signalIndex;
+#endif
+ Q_DISABLE_COPY(QSignalEventGenerator)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp
new file mode 100644
index 0000000..48add0d
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qsignaltransition.h"
+#include "qsignaltransition_p.h"
+#include "qsignalevent.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSignalTransition
+
+ \brief The QSignalTransition class provides a transition based on a Qt signal.
+
+ \ingroup statemachine
+
+ Typically you would use the overload of QState::addTransition() that takes a
+ sender and signal as arguments, rather than creating QSignalTransition
+ objects directly. QSignalTransition is part of \l{The State Machine
+ Framework}.
+
+ You can subclass QSignalTransition and reimplement eventTest() to make a
+ signal transition conditional; the event object passed to eventTest() will
+ be a QSignalEvent object. Example:
+
+ \code
+ class CheckedTransition : public QSignalTransition
+ {
+ public:
+ CheckedTransition(QCheckBox *check)
+ : QSignalTransition(check, SIGNAL(stateChanged(int))) {}
+ protected:
+ bool eventTest(QEvent *e) const {
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ return (se->arguments().at(0).toInt() == Qt::Checked);
+ }
+ };
+
+ ...
+
+ QCheckBox *check = new QCheckBox();
+ check->setTristate(true);
+
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ CheckedTransition *t1 = new CheckedTransition(check);
+ t1->setTargetState(s2);
+ s1->addTransition(t1);
+ \endcode
+*/
+
+/*!
+ \property QSignalTransition::object
+
+ \brief the sender object that this signal transition is associated with
+*/
+
+/*!
+ \property QSignalTransition::signal
+
+ \brief the signal that this signal transition is associated with
+*/
+
+QSignalTransitionPrivate::QSignalTransitionPrivate()
+{
+ sender = 0;
+ signalIndex = -1;
+}
+
+QSignalTransitionPrivate *QSignalTransitionPrivate::get(QSignalTransition *q)
+{
+ return q->d_func();
+}
+
+void QSignalTransitionPrivate::invalidate()
+{
+ Q_Q(QSignalTransition);
+ if (signalIndex != -1) {
+ QState *source = sourceState();
+ QStatePrivate *source_d = QStatePrivate::get(source);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(source_d->machine());
+ if (mach) {
+ mach->unregisterSignalTransition(q);
+ if (mach->configuration.contains(source))
+ mach->registerSignalTransition(q);
+ }
+ }
+}
+
+/*!
+ Constructs a new signal transition with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(QState *sourceState)
+ : QTransition(*new QSignalTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new signal transition associated with the given \a signal of
+ the given \a sender, and with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
+ QState *sourceState)
+ : QTransition(*new QSignalTransitionPrivate, sourceState)
+{
+ Q_D(QSignalTransition);
+ d->sender = sender;
+ d->signal = signal;
+}
+
+/*!
+ Constructs a new signal transition associated with the given \a signal of
+ the given \a sender. The transition has the given \a targets and \a
+ sourceState.
+*/
+QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
+ const QList<QAbstractState*> &targets,
+ QState *sourceState)
+ : QTransition(*new QSignalTransitionPrivate, targets, sourceState)
+{
+ Q_D(QSignalTransition);
+ d->sender = sender;
+ d->signal = signal;
+}
+
+/*!
+ Destroys this signal transition.
+*/
+QSignalTransition::~QSignalTransition()
+{
+}
+
+/*!
+ Returns the sender object associated with this signal transition.
+*/
+QObject *QSignalTransition::senderObject() const
+{
+ Q_D(const QSignalTransition);
+ return d->sender;
+}
+
+/*!
+ Sets the \a sender object associated with this signal transition.
+*/
+void QSignalTransition::setSenderObject(QObject *sender)
+{
+ Q_D(QSignalTransition);
+ if (sender == d->sender)
+ return;
+ d->sender = sender;
+ d->invalidate();
+}
+
+/*!
+ Returns the signal associated with this signal transition.
+*/
+QByteArray QSignalTransition::signal() const
+{
+ Q_D(const QSignalTransition);
+ return d->signal;
+}
+
+/*!
+ Sets the \a signal associated with this signal transition.
+*/
+void QSignalTransition::setSignal(const QByteArray &signal)
+{
+ Q_D(QSignalTransition);
+ if (signal == d->signal)
+ return;
+ d->signal = signal;
+ d->invalidate();
+}
+
+/*!
+ \reimp
+
+ The \a event is a QSignalEvent object. The default implementation returns
+ true if the event's sender and signal index match this transition, and
+ returns false otherwise.
+*/
+bool QSignalTransition::eventTest(QEvent *event) const
+{
+ Q_D(const QSignalTransition);
+#ifndef QT_STATEMACHINE_SOLUTION
+ if (event->type() == QEvent::Signal) {
+#else
+ if (event->type() == QEvent::Type(QEvent::User-1)) {
+#endif
+ QSignalEvent *se = static_cast<QSignalEvent*>(event);
+ Q_ASSERT(d->signalIndex != -1);
+ return (se->sender() == d->sender)
+ && (se->signalIndex() == d->signalIndex);
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QSignalTransition::onTransition()
+{
+}
+
+/*!
+ \reimp
+*/
+bool QSignalTransition::event(QEvent *e)
+{
+ return QTransition::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h
new file mode 100644
index 0000000..c090bd8
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALTRANSITION_H
+#define QSIGNALTRANSITION_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qtransition.h>
+#else
+#include "qtransition.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QSignalTransitionPrivate;
+class Q_CORE_EXPORT QSignalTransition : public QTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* object READ senderObject WRITE setSenderObject)
+ Q_PROPERTY(QByteArray signal READ signal WRITE setSignal)
+public:
+ QSignalTransition(QState *sourceState = 0);
+ QSignalTransition(QObject *sender, const char *signal,
+ QState *sourceState = 0);
+ QSignalTransition(QObject *sender, const char *signal,
+ const QList<QAbstractState*> &targets,
+ QState *sourceState = 0);
+ ~QSignalTransition();
+
+ QObject *senderObject() const;
+ void setSenderObject(QObject *sender);
+
+ QByteArray signal() const;
+ void setSignal(const QByteArray &signal);
+
+protected:
+ bool eventTest(QEvent *event) const;
+ void onTransition();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QSignalTransition)
+ Q_DECLARE_PRIVATE(QSignalTransition)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qsignaltransition_p.h b/src/corelib/statemachine/qsignaltransition_p.h
new file mode 100644
index 0000000..d200676
--- /dev/null
+++ b/src/corelib/statemachine/qsignaltransition_p.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIGNALTRANSITION_P_H
+#define QSIGNALTRANSITION_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 "qtransition_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSignalTransition;
+class QSignalTransitionPrivate : public QTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QSignalTransition)
+public:
+ QSignalTransitionPrivate();
+
+ static QSignalTransitionPrivate *get(QSignalTransition *q);
+
+ void invalidate();
+
+ QObject *sender;
+ QByteArray signal;
+ int signalIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
new file mode 100644
index 0000000..26dbd89
--- /dev/null
+++ b/src/corelib/statemachine/qstate.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qstatefinishedtransition.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#ifndef QT_NO_ANIMATION
+#include "qanimationstate.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QState
+
+ \brief The QState class provides a general-purpose state for QStateMachine.
+
+ \ingroup statemachine
+
+ QState objects can have child states, and can have transitions to other
+ states. QState is part of \l{The State Machine Framework}.
+
+ The addTransition() function adds a transition. The removeTransition()
+ function removes a transition.
+
+ \section1 States with Child States
+
+ For non-parallel state groups, the setInitialState() function must be called
+ to set the initial state. The child states are mutually exclusive states,
+ and the state machine needs to know which child state to enter when the
+ parent state is the target of a transition.
+
+ The addHistoryState() function adds a history state.
+
+ The setErrorState() sets the state's error state. The error state is the
+ state that the state machine will transition to if an error is detected when
+ attempting to enter the state (e.g. because no initial state has been set).
+*/
+
+/*!
+ \enum QState::Type
+
+ This enum specifies the type of a state.
+
+ \value Normal A normal state. If the state has no child states, it is an
+ atomic state; otherwise, the child states are mutually exclusive and an
+ initial state must be set by calling QState::setInitialState().
+
+ \value ParallelGroup The state is a parallel group state. When a parallel
+ group state is entered, all its child states are entered in parallel.
+*/
+
+/*!
+ \enum QState::HistoryType
+
+ This enum specifies the type of history that a QHistoryState records.
+
+ \value ShallowHistory Only the immediate child states of the parent state
+ are recorded. In this case a transition with the history state as its
+ target will end up in the immediate child state that the parent was in the
+ last time it was exited. This is the default.
+
+ \value DeepHistory Nested states are recorded. In this case a transition
+ with the history state as its target will end up in the most deeply nested
+ descendant state the parent was in the last time it was exited.
+*/
+
+QStatePrivate::QStatePrivate()
+ : errorState(0), isParallelGroup(false), initialState(0)
+{
+}
+
+QStatePrivate::~QStatePrivate()
+{
+}
+
+QStatePrivate *QStatePrivate::get(QState *q)
+{
+ if (!q)
+ return 0;
+ return q->d_func();
+}
+
+const QStatePrivate *QStatePrivate::get(const QState *q)
+{
+ if (!q)
+ return 0;
+ return q->d_func();
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QState::QState(QState *parent)
+ : QActionState(*new QStatePrivate, parent)
+{
+}
+
+/*!
+ Constructs a new state of the given \a type with the given \a parent state.
+*/
+QState::QState(Type type, QState *parent)
+ : QActionState(*new QStatePrivate, parent)
+{
+ Q_D(QState);
+ d->isParallelGroup = (type == ParallelGroup);
+}
+
+/*!
+ \internal
+*/
+QState::QState(QStatePrivate &dd, QState *parent)
+ : QActionState(dd, parent)
+{
+}
+
+/*!
+ Destroys this state.
+*/
+QState::~QState()
+{
+}
+
+QList<QAbstractState*> QStatePrivate::childStates() const
+{
+ QList<QAbstractState*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractState *s = qobject_cast<QAbstractState*>(*it);
+ if (!s || qobject_cast<QHistoryState*>(s))
+ continue;
+ result.append(s);
+ }
+ return result;
+}
+
+QList<QHistoryState*> QStatePrivate::historyStates() const
+{
+ QList<QHistoryState*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QHistoryState *h = qobject_cast<QHistoryState*>(*it);
+ if (h)
+ result.append(h);
+ }
+ return result;
+}
+
+QList<QAbstractTransition*> QStatePrivate::transitions() const
+{
+ QList<QAbstractTransition*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractTransition *t = qobject_cast<QAbstractTransition*>(*it);
+ if (t)
+ result.append(t);
+ }
+ return result;
+}
+
+/*!
+ Returns this state group's error state.
+
+ \sa QStateMachine::errorState(), QStateMachine::setErrorState()
+*/
+QAbstractState *QState::errorState() const
+{
+ Q_D(const QState);
+ return d->errorState;
+}
+
+/*!
+ Sets this state's error state to be the given \a state. If the error state
+ is not set, or if it is set to 0, the state will inherit its parent's error
+ state recursively.
+
+ \sa QStateMachine::setErrorState(), QStateMachine::errorState()
+*/
+void QState::setErrorState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (state != 0 && QAbstractStatePrivate::get(state)->machine() != d->machine()) {
+ qWarning("QState::setErrorState: error state cannot belong "
+ "to a different state machine");
+ return;
+ }
+
+ d->errorState = state;
+}
+
+/*!
+ Adds the given \a transition. The transition has this state as the source.
+ This state takes ownership of the transition.
+*/
+void QState::addTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::addTransition: cannot add null transition");
+ return;
+ }
+ const QList<QAbstractState*> &targets = QAbstractTransitionPrivate::get(transition)->targetStates;
+ for (int i = 0; i < targets.size(); ++i) {
+ QAbstractState *t = targets.at(i);
+ if (!t) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return;
+ }
+ if ((QAbstractStatePrivate::get(t)->machine() != d->machine())
+ && QAbstractStatePrivate::get(t)->machine() && d->machine()) {
+ qWarning("QState::addTransition: cannot add transition "
+ "to a state in a different state machine");
+ return;
+ }
+ }
+ transition->setParent(this);
+}
+
+/*!
+ Adds a transition associated with the given \a signal of the given \a sender
+ object. The transition has this state as the source, and the given \a target
+ as the target state.
+*/
+void QState::addTransition(QObject *sender, const char *signal,
+ QAbstractState *target)
+{
+ if (!sender) {
+ qWarning("QState::addTransition: sender cannot be null");
+ return;
+ }
+ if (!signal) {
+ qWarning("QState::addTransition: signal cannot be null");
+ return;
+ }
+ addTransition(new QSignalTransition(sender, signal, QList<QAbstractState*>() << target));
+}
+
+/*!
+ Adds a transition that's triggered by the finished event of this state, and
+ that has the given \a target state.
+
+ \sa QStateFinishedEvent
+*/
+void QState::addFinishedTransition(QAbstractState *target)
+{
+ addTransition(new QStateFinishedTransition(this, QList<QAbstractState*>() << target));
+}
+
+namespace {
+
+class UnconditionalTransition : public QAbstractTransition
+{
+public:
+ UnconditionalTransition(QAbstractState *target)
+ : QAbstractTransition(QList<QAbstractState*>() << target) {}
+protected:
+ void onTransition() {}
+ bool eventTest(QEvent *) const { return true; }
+};
+
+} // namespace
+
+/*!
+ Adds an unconditional transition from this state to the given \a target
+ state.
+*/
+void QState::addTransition(QAbstractState *target)
+{
+ addTransition(new UnconditionalTransition(target));
+}
+
+/*!
+ Removes the given \a transition from this state. The state releases
+ ownership of the transition.
+
+ \sa addTransition()
+*/
+void QState::removeTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::removeTransition: cannot remove null transition");
+ return;
+ }
+ if (transition->sourceState() != this) {
+ qWarning("QState::removeTransition: transition %p's source state (%p)"
+ " is different from this state (%p)",
+ transition, transition->sourceState(), this);
+ return;
+ }
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(d->machine());
+ if (mach)
+ mach->unregisterTransition(transition);
+ transition->setParent(0);
+}
+
+/*!
+ Returns the list of transitions from this state, or an empty list if there
+ are no transitions from this state.
+
+ \sa addTransition(), removeTransition()
+*/
+QList<QAbstractTransition*> QState::transitions() const
+{
+ Q_D(const QState);
+ return d->transitions();
+}
+
+/*!
+ Creates a history state of the given \a type for this state and returns the
+ new state. The history state becomes a child of this state.
+*/
+QHistoryState *QState::addHistoryState(HistoryType type)
+{
+ return QHistoryStatePrivate::create(type, this);
+}
+
+/*!
+ \reimp
+*/
+void QState::onEntry()
+{
+ QActionState::onEntry();
+}
+
+/*!
+ \reimp
+*/
+void QState::onExit()
+{
+ QActionState::onExit();
+}
+
+#ifndef QT_NO_ANIMATION
+
+/*!
+ \overload addAnimatedTransition()
+
+ Adds an animated transition from the current state to \a targetState for \a animation.
+
+ This function creates a QSignalTransition for the \a sender and \a signal, and calls
+ addAnimatedTransition() with this transition object.
+*/
+QAnimationState *QState::addAnimatedTransition(QObject *sender, const char *signal,
+ QAbstractState *targetState,
+ QAbstractAnimation *animation)
+{
+ if (!targetState) {
+ qWarning("QState::addAnimatedTransition: cannot add transition to null state");
+ return 0;
+ }
+ return addAnimatedTransition(
+ new QSignalTransition(sender, signal,
+ QList<QAbstractState*>() << targetState), animation);
+}
+
+/*!
+ Adds an animated transition from the current state.
+
+ The animated transition has an intermediate QAnimationState which plays \a
+ animation before entering the target state(s). This QAnimationState will be
+ entered when \a transition is taken by the state machine. When the animation
+ has finished playing, the transition's target state(s) will be entered.
+
+ The new QAnimationState object will become a child of this state's parent state.
+
+ \code
+ QPushButton button;
+ QPropertyAnimation animation(&button, "geometry");
+ animation.setEndValue(QRect(100, 100, 400, 400));
+
+ QStateMachine machine;
+
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+
+ QTransition *transition = new QTransition(MyEventType);
+ s1->addAnimatedTransition(transition, s2, &animation);
+ \endcode
+
+ The function returns the new QAnimationState. This state can be used if you want to add additional
+ transitions into or out from the animation state, and if you want to add additional animations.
+
+ \sa QAnimationState
+*/
+QAnimationState *QState::addAnimatedTransition(QAbstractTransition *transition,
+ QAbstractAnimation *animation)
+{
+ if (!transition) {
+ qWarning("QState::addAnimatedTransition: cannot add null transition");
+ return 0;
+ }
+ QList<QAbstractState*> targets = transition->targetStates();
+ Q_ASSERT(!targets.isEmpty());
+ if (!targets.at(0)->parentState()) {
+ qWarning("QState::addAnimatedTransition: cannot add transition to target that doesn't have a parent state");
+ return 0;
+ }
+ QAnimationState *animState = new QAnimationState(animation, targets.at(0)->parentState());
+ animState->addTransition(new QStateFinishedTransition(animState, targets));
+ transition->setTargetStates(QList<QAbstractState*>() << animState);
+ addTransition(transition);
+ return animState;
+}
+
+#endif
+
+/*!
+ Returns this state's initial state, or 0 if the state has no initial state.
+*/
+QAbstractState *QState::initialState() const
+{
+ Q_D(const QState);
+ return d->initialState;
+}
+
+/*!
+ Sets this state's initial state to be the given \a state.
+ \a state has to be a child of this state.
+*/
+void QState::setInitialState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (d->isParallelGroup) {
+ qWarning("QState::setInitialState: ignoring attempt to set initial state "
+ "of parallel state group %p", this);
+ return;
+ }
+ if (state && (state->parentState() != this)) {
+ qWarning("QState::setInitialState: state %p is not a child of this state (%p)",
+ state, this);
+ return;
+ }
+ d->initialState = state;
+}
+
+/*!
+ \reimp
+*/
+bool QState::event(QEvent *e)
+{
+ return QActionState::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h
new file mode 100644
index 0000000..ba2d034
--- /dev/null
+++ b/src/corelib/statemachine/qstate.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATE_H
+#define QSTATE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qactionstate.h>
+#else
+#include "qactionstate.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QAbstractTransition;
+class QHistoryState;
+#ifndef QT_NO_ANIMATION
+class QAbstractAnimation;
+class QAnimationState;
+#endif
+
+class QStatePrivate;
+class Q_CORE_EXPORT QState : public QActionState
+{
+ Q_OBJECT
+public:
+ enum Type {
+ Normal,
+ ParallelGroup
+ };
+
+ enum HistoryType {
+ ShallowHistory,
+ DeepHistory
+ };
+
+ QState(QState *parent = 0);
+ QState(Type type, QState *parent = 0);
+ ~QState();
+
+ QAbstractState *errorState() const;
+ void setErrorState(QAbstractState *state);
+
+ void addTransition(QAbstractTransition *transition);
+ void addTransition(QObject *sender, const char *signal, QAbstractState *target);
+ void addTransition(QAbstractState *target);
+ void addFinishedTransition(QAbstractState *target);
+ void removeTransition(QAbstractTransition *transition);
+ QList<QAbstractTransition*> transitions() const;
+
+#ifndef QT_NO_ANIMATION
+ QAnimationState *addAnimatedTransition(QObject *sender, const char *signal,
+ QAbstractState *targetState,
+ QAbstractAnimation *animation = 0);
+ QAnimationState *addAnimatedTransition(QAbstractTransition *transition,
+ QAbstractAnimation *animation = 0);
+#endif
+
+ QHistoryState *addHistoryState(HistoryType type = ShallowHistory);
+
+ QAbstractState *initialState() const;
+ void setInitialState(QAbstractState *state);
+
+protected:
+ void onEntry();
+ void onExit();
+
+ bool event(QEvent *e);
+
+protected:
+ QState(QStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QState)
+ Q_DECLARE_PRIVATE(QState)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h
new file mode 100644
index 0000000..fe9b24a
--- /dev/null
+++ b/src/corelib/statemachine/qstate_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATE_P_H
+#define QSTATE_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 "qactionstate_p.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QState;
+class Q_CORE_EXPORT QStatePrivate : public QActionStatePrivate
+{
+ Q_DECLARE_PUBLIC(QState)
+public:
+ QStatePrivate();
+ ~QStatePrivate();
+
+ static QStatePrivate *get(QState *q);
+ static const QStatePrivate *get(const QState *q);
+
+ QList<QAbstractState*> childStates() const;
+ QList<QHistoryState*> historyStates() const;
+ QList<QAbstractTransition*> transitions() const;
+
+ QAbstractState *errorState;
+ bool isParallelGroup;
+ QAbstractState *initialState;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstateaction.cpp b/src/corelib/statemachine/qstateaction.cpp
new file mode 100644
index 0000000..c12b093
--- /dev/null
+++ b/src/corelib/statemachine/qstateaction.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qstateaction.h"
+#include "qstateaction_p.h"
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+QStateActionPrivate::QStateActionPrivate()
+{
+ when = ExecuteOnEntry;
+}
+
+QStateActionPrivate::~QStateActionPrivate()
+{
+}
+
+QStateActionPrivate *QStateActionPrivate::get(QStateAction *q)
+{
+ return q->d_func();
+}
+
+void QStateActionPrivate::callExecute()
+{
+ Q_Q(QStateAction);
+ q->execute();
+}
+
+/*!
+ \class QStateAction
+
+ \brief The QStateAction class is the base class of QState actions.
+
+ \ingroup statemachine
+
+ A state action is added to a state by calling QState::addEntryAction() or
+ QState::addExitAction(). QStateAction is part of \l{The State Machine
+ Framework}.
+
+ \section1 Subclassing
+
+ Subclasses must implement the execute() function.
+*/
+
+/*!
+ Constructs a new QStateAction object with the given \a parent.
+*/
+QStateAction::QStateAction(QObject *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ *new QStateActionPrivate,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(new QStateActionPrivate)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ \internal
+*/
+QStateAction::QStateAction(QStateActionPrivate &dd, QObject *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ dd,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(&dd)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ Destroys this QStateAction object.
+*/
+QStateAction::~QStateAction()
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ delete d_ptr;
+#endif
+}
+
+/*!
+ \fn QStateAction::execute()
+
+ Executes this action.
+*/
+
+/*!
+ \reimp
+*/
+bool QStateAction::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QStateSetPropertyActionPrivate *QStateSetPropertyActionPrivate::get(QStateSetPropertyAction *q)
+{
+ return q->d_func();
+}
+
+/*!
+ \class QStateSetPropertyAction
+
+ \brief The QStateSetPropertyAction class provides a set property action for QObjects.
+
+ \ingroup statemachine
+
+ The QStateSetPropertyAction class provides an action that sets a property of
+ a QObject to a pre-defined value when a QState is entered or exited.
+ QStateSetPropertyAction is part of \l{The State Machine Framework}.
+
+ Typically you don't construct QStateSetPropertyAction objects directly, but
+ rather call the QState::setPropertyOnEntry() function or the
+ QState::setPropertyOnExit() function.
+*/
+
+/*!
+ \property QStateSetPropertyAction::target
+
+ \brief the object for which this action sets a property
+*/
+
+/*!
+ \property QStateSetPropertyAction::propertyName
+
+ \brief the name of the property set by this action
+*/
+
+/*!
+ \property QStateSetPropertyAction::value
+
+ \brief the value set by this action
+*/
+
+/*!
+ Constructs a new QStateSetPropertyAction object for the property named \a
+ propertyName of the given \a target object, with the given \a value, and
+ with the given \a parent.
+*/
+QStateSetPropertyAction::QStateSetPropertyAction(
+ QObject *target, const QByteArray &propertyName,
+ const QVariant &value, QObject *parent)
+ : QStateAction(*new QStateSetPropertyActionPrivate, parent)
+{
+ Q_D(QStateSetPropertyAction);
+ d->target = target;
+ d->propertyName = propertyName;
+ d->value = value;
+}
+
+/*!
+ Constructs a new QStateSetPropertyAction object with the given \a parent.
+*/
+QStateSetPropertyAction::QStateSetPropertyAction(QObject *parent)
+ : QStateAction(*new QStateSetPropertyActionPrivate, parent)
+{
+ Q_D(QStateSetPropertyAction);
+ d->target = 0;
+}
+
+/*!
+ Destroys this QStateAbstractSetPropertyAction object.
+*/
+QStateSetPropertyAction::~QStateSetPropertyAction()
+{
+}
+
+/*!
+ Returns the object for which this action sets a property.
+*/
+QObject *QStateSetPropertyAction::targetObject() const
+{
+ Q_D(const QStateSetPropertyAction);
+ return d->target;
+}
+
+/*!
+ Sets the object for which this action sets a property.
+*/
+void QStateSetPropertyAction::setTargetObject(QObject *target)
+{
+ Q_D(QStateSetPropertyAction);
+ d->target = target;
+}
+
+/*!
+ Returns the name of the property set by this action.
+*/
+QByteArray QStateSetPropertyAction::propertyName() const
+{
+ Q_D(const QStateSetPropertyAction);
+ return d->propertyName;
+}
+
+/*!
+ Sets the name of the property set by this action.
+*/
+void QStateSetPropertyAction::setPropertyName(const QByteArray &propertyName)
+{
+ Q_D(QStateSetPropertyAction);
+ d->propertyName = propertyName;
+}
+
+/*!
+ Returns the value set by this action.
+*/
+QVariant QStateSetPropertyAction::value() const
+{
+ Q_D(const QStateSetPropertyAction);
+ return d->value;
+}
+
+/*!
+ Sets the value set by this action.
+*/
+void QStateSetPropertyAction::setValue(const QVariant &value)
+{
+ Q_D(QStateSetPropertyAction);
+ d->value = value;
+}
+
+/*!
+ \reimp
+*/
+void QStateSetPropertyAction::execute()
+{
+ Q_D(QStateSetPropertyAction);
+ if (!d->target)
+ return;
+ d->target->setProperty(d->propertyName, d->value);
+}
+
+/*!
+ \reimp
+*/
+bool QStateSetPropertyAction::event(QEvent *e)
+{
+ return QStateAction::event(e);
+}
+
+QStateInvokeMethodActionPrivate *QStateInvokeMethodActionPrivate::get(QStateInvokeMethodAction *q)
+{
+ return q->d_func();
+}
+
+/*!
+ \class QStateInvokeMethodAction
+
+ \brief The QStateInvokeMethodAction class provides an invoke method action for QObjects.
+
+ \ingroup statemachine
+
+ The QStateInvokeMethodAction class provides an action that calls a method of
+ a QObject when a QState is entered or exited. QStateInvokeMethodAction is
+ part of \l{The State Machine Framework}.
+
+ Typically you don't construct QStateInvokeMethodAction objects directly, but
+ rather call the QState::invokeMethodOnEntry() function or the
+ QState::invokeMethodOnExit() function.
+*/
+
+/*!
+ \property QStateInvokeMethodAction::arguments
+
+ \brief the arguments to the method this action invokes
+*/
+
+/*!
+ \property QStateInvokeMethodAction::methodName
+
+ \brief the name of the method this action invokes
+*/
+
+/*!
+ \property QStateInvokeMethodAction::target
+
+ \brief the object on which this action invokes a method
+*/
+
+/*!
+ Constructs a new QStateInvokeMethodAction object for the method named \a
+ methodName of the given \a target object, with the given \a parent.
+*/
+QStateInvokeMethodAction::QStateInvokeMethodAction(
+ QObject *target, const QByteArray &methodName, QObject *parent)
+ : QStateAction(*new QStateInvokeMethodActionPrivate, parent)
+{
+ Q_D(QStateInvokeMethodAction);
+ d->target = target;
+ d->methodName = methodName;
+ d->methodIndex = -1;
+}
+
+/*!
+ Constructs a new QStateInvokeMethodAction object for the method named \a
+ methodName of the given \a target object, with the given arguments, \a args,
+ and with the given \a parent.
+*/
+QStateInvokeMethodAction::QStateInvokeMethodAction(
+ QObject *target, const QByteArray &methodName,
+ const QList<QVariant> &args, QObject *parent)
+ : QStateAction(*new QStateInvokeMethodActionPrivate, parent)
+{
+ Q_D(QStateInvokeMethodAction);
+ d->target = target;
+ d->methodName = methodName;
+ d->methodIndex = -1;
+ d->args = args;
+}
+
+/*!
+ Constructs a new QStateInvokeMethodAction object with the given \a parent.
+*/
+QStateInvokeMethodAction::QStateInvokeMethodAction(QObject *parent)
+ : QStateAction(*new QStateInvokeMethodActionPrivate, parent)
+{
+ Q_D(QStateInvokeMethodAction);
+ d->target = 0;
+ d->methodIndex = -1;
+}
+
+/*!
+ Destroys this QStateInvokeMethodAction object.
+*/
+QStateInvokeMethodAction::~QStateInvokeMethodAction()
+{
+}
+
+/*!
+ \reimp
+*/
+void QStateInvokeMethodAction::execute()
+{
+ Q_D(QStateInvokeMethodAction);
+ if (!d->target)
+ return;
+
+ if (d->methodIndex == -1) {
+ QVarLengthArray<char, 512> sig;
+ int len = d->methodName.length();
+ if (len <= 0)
+ return;
+ sig.append(d->methodName, len);
+ sig.append('(');
+
+ int paramCount;
+ for (paramCount = 0; paramCount < d->args.size() && paramCount < 10; ++paramCount) {
+ const char *tn = d->args.at(paramCount).typeName();
+ len = qstrlen(tn);
+ if (len <= 0)
+ break;
+ sig.append(tn, len);
+ sig.append(',');
+ }
+ if (paramCount == 0)
+ sig.append(')'); // no parameters
+ else
+ sig[sig.size() - 1] = ')';
+ sig.append('\0');
+
+ const QMetaObject *meta = d->target->metaObject();
+ int idx = meta->indexOfMethod(sig.constData());
+ if (idx < 0) {
+ QByteArray norm = QMetaObject::normalizedSignature(sig.constData());
+ idx = meta->indexOfMethod(norm.constData());
+ if ((idx < 0) || (idx >= meta->methodCount())) {
+ qWarning("InvokeMethodAction: unable to find method '%s' of %s(%p)",
+ sig.constData(), meta->className(), d->target);
+ return;
+ }
+ }
+ d->methodIndex = idx;
+ }
+
+ void *param[11];
+ param[0] = 0; // return value
+ for (int i = 0; i < 10; ++i)
+ param[i+1] = (i < d->args.size()) ? const_cast<void*>(d->args.at(i).constData()) : (void*)0;
+ (void)d->target->qt_metacall(QMetaObject::InvokeMetaMethod, d->methodIndex, param);
+}
+
+/*!
+ Returns the object on which this action invokes a method.
+*/
+QObject *QStateInvokeMethodAction::targetObject() const
+{
+ Q_D(const QStateInvokeMethodAction);
+ return d->target;
+}
+
+/*!
+ Sets the object on which this action invokes a method.
+*/
+void QStateInvokeMethodAction::setTargetObject(QObject *target)
+{
+ Q_D(QStateInvokeMethodAction);
+ d->target = target;
+}
+
+/*!
+ Returns the name of the method this action will invoke.
+*/
+QByteArray QStateInvokeMethodAction::methodName() const
+{
+ Q_D(const QStateInvokeMethodAction);
+ return d->methodName;
+}
+
+/*!
+ Sets the name of the method this action will invoke.
+*/
+void QStateInvokeMethodAction::setMethodName(const QByteArray &methodName)
+{
+ Q_D(QStateInvokeMethodAction);
+ if (methodName != d->methodName) {
+ d->methodName = methodName;
+ d->methodIndex = -1;
+ }
+}
+
+/*!
+ Returns the arguments to the method this action will invoke.
+*/
+QVariantList QStateInvokeMethodAction::arguments() const
+{
+ Q_D(const QStateInvokeMethodAction);
+ return d->args;
+}
+
+/*!
+ Sets the arguments to the method this action will invoke.
+*/
+void QStateInvokeMethodAction::setArguments(const QVariantList &arguments)
+{
+ Q_D(QStateInvokeMethodAction);
+ if (d->args != arguments) {
+ d->args = arguments;
+ d->methodIndex = -1;
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QStateInvokeMethodAction::event(QEvent *e)
+{
+ return QStateAction::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qstateaction.h b/src/corelib/statemachine/qstateaction.h
new file mode 100644
index 0000000..df1e0f0
--- /dev/null
+++ b/src/corelib/statemachine/qstateaction.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEACTION_H
+#define QSTATEACTION_H
+
+#include <QtCore/qobject.h>
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QStateActionPrivate;
+class Q_CORE_EXPORT QStateAction : public QObject
+{
+ Q_OBJECT
+public:
+ ~QStateAction();
+
+protected:
+ QStateAction(QObject *parent = 0);
+
+ virtual void execute() = 0;
+
+ bool event(QEvent *e);
+
+protected:
+#ifdef QT_STATEMACHINE_SOLUTION
+ QStateActionPrivate *d_ptr;
+#endif
+ QStateAction(QStateActionPrivate &dd, QObject *parent);
+
+private:
+ Q_DISABLE_COPY(QStateAction)
+ Q_DECLARE_PRIVATE(QStateAction)
+};
+
+class QStateSetPropertyActionPrivate;
+class Q_CORE_EXPORT QStateSetPropertyAction : public QStateAction
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* target READ targetObject WRITE setTargetObject)
+ Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+public:
+ QStateSetPropertyAction(QObject *target, const QByteArray &propertyName,
+ const QVariant &value, QObject *parent = 0);
+ QStateSetPropertyAction(QObject *parent = 0);
+ ~QStateSetPropertyAction();
+
+ QObject *targetObject() const;
+ void setTargetObject(QObject *target);
+
+ QByteArray propertyName() const;
+ void setPropertyName(const QByteArray &name);
+
+ QVariant value() const;
+ void setValue(const QVariant &value);
+
+protected:
+ void execute();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QStateSetPropertyAction)
+ Q_DECLARE_PRIVATE(QStateSetPropertyAction)
+};
+
+class QStateInvokeMethodActionPrivate;
+class Q_CORE_EXPORT QStateInvokeMethodAction : public QStateAction
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* target READ targetObject WRITE setTargetObject)
+ Q_PROPERTY(QByteArray methodName READ methodName WRITE setMethodName)
+ Q_PROPERTY(QVariantList arguments READ arguments WRITE setArguments)
+public:
+ QStateInvokeMethodAction(QObject *target, const QByteArray &methodName,
+ QObject *parent = 0);
+ QStateInvokeMethodAction(QObject *target, const QByteArray &methodName,
+ const QList<QVariant> &args, QObject *parent = 0);
+ QStateInvokeMethodAction(QObject *parent = 0);
+ ~QStateInvokeMethodAction();
+
+ QObject *targetObject() const;
+ void setTargetObject(QObject *target);
+
+ QByteArray methodName() const;
+ void setMethodName(const QByteArray &methodName);
+
+ QVariantList arguments() const;
+ void setArguments(const QVariantList &arguments);
+
+protected:
+ void execute();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QStateInvokeMethodAction)
+ Q_DECLARE_PRIVATE(QStateInvokeMethodAction)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstateaction_p.h b/src/corelib/statemachine/qstateaction_p.h
new file mode 100644
index 0000000..54e3a05
--- /dev/null
+++ b/src/corelib/statemachine/qstateaction_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEACTION_P_H
+#define QSTATEACTION_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.
+//
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <private/qobject_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QStateAction;
+class QStateActionPrivate
+#ifndef QT_STATEMACHINE_SOLUTION
+ : public QObjectPrivate
+#endif
+{
+ Q_DECLARE_PUBLIC(QStateAction)
+public:
+ QStateActionPrivate();
+ ~QStateActionPrivate();
+
+ static QStateActionPrivate *get(QStateAction *q);
+
+ void callExecute();
+
+ enum When {
+ ExecuteOnEntry,
+ ExecuteOnExit
+ };
+
+ When when;
+
+#ifdef QT_STATEMACHINE_SOLUTION
+ QStateAction *q_ptr;
+#endif
+};
+
+class QStateSetPropertyAction;
+class QStateSetPropertyActionPrivate : public QStateActionPrivate
+{
+ Q_DECLARE_PUBLIC(QStateSetPropertyAction)
+public:
+ QStateSetPropertyActionPrivate() {}
+ ~QStateSetPropertyActionPrivate() {}
+
+ static QStateSetPropertyActionPrivate *get(QStateSetPropertyAction *q);
+
+ QObject *target;
+ QByteArray propertyName;
+ QVariant value;
+};
+
+class QStateInvokeMethodAction;
+class QStateInvokeMethodActionPrivate : public QStateActionPrivate
+{
+ Q_DECLARE_PUBLIC(QStateInvokeMethodAction)
+public:
+ QStateInvokeMethodActionPrivate() {}
+ ~QStateInvokeMethodActionPrivate() {}
+
+ static QStateInvokeMethodActionPrivate *get(QStateInvokeMethodAction *q);
+
+ QObject *target;
+ QByteArray methodName;
+ int methodIndex;
+ QList<QVariant> args;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstatefinishedevent.h b/src/corelib/statemachine/qstatefinishedevent.h
new file mode 100644
index 0000000..d6a1146
--- /dev/null
+++ b/src/corelib/statemachine/qstatefinishedevent.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEFINISHEDEVENT_H
+#define QSTATEFINISHEDEVENT_H
+
+#include <QtCore/qcoreevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QState;
+
+class Q_CORE_EXPORT QStateFinishedEvent : public QEvent
+{
+public:
+ QStateFinishedEvent(QState *state);
+ ~QStateFinishedEvent();
+
+ QState *state() const;
+
+private:
+ QState *m_state;
+ void *d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qstatefinishedtransition.cpp b/src/corelib/statemachine/qstatefinishedtransition.cpp
new file mode 100644
index 0000000..3d8c588
--- /dev/null
+++ b/src/corelib/statemachine/qstatefinishedtransition.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qstatefinishedtransition.h"
+#include "qstatefinishedevent.h"
+#include "qtransition_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QStateFinishedTransition
+
+ \brief The QStateFinishedTransition class provides a transition that triggers when a state is finished.
+
+ \ingroup statemachine
+
+ A state is finished when one of its final child states (a QFinalState) is
+ entered; this will cause a QStateFinishedEvent to be generated. The
+ QStateFinishedTransition class provides a way of associating a transition
+ with such an event. QStateFinishedTransition is part of \l{The State Machine
+ Framework}.
+
+ \code
+ QStateMachine machine;
+ QState *s1 = new QState(machine.rootState());
+ QState *s11 = new QState(s1);
+ QFinalState *s12 = new QFinalState(s1);
+ s11->addTransition(s12);
+
+ QState *s2 = new QState(machine.rootState());
+ QStateFinishedTransition *finishedTransition = new QStateFinishedTransition(s1);
+ finishedTransition->setTargetState(s2);
+ s1->addTransition(finishedTransition);
+ \endcode
+
+ \sa QState::addFinishedTransition(), QStateFinishedEvent
+*/
+
+/*!
+ \property QStateFinishedTransition::state
+
+ \brief the state whose QStateFinishedEvent this transition is associated with
+*/
+
+class QStateFinishedTransitionPrivate : public QTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QStateFinishedTransition)
+public:
+ QStateFinishedTransitionPrivate();
+
+ static QStateFinishedTransitionPrivate *get(QStateFinishedTransition *q);
+
+ QState *state;
+};
+
+QStateFinishedTransitionPrivate::QStateFinishedTransitionPrivate()
+{
+ state = 0;
+}
+
+QStateFinishedTransitionPrivate *QStateFinishedTransitionPrivate::get(QStateFinishedTransition *q)
+{
+ return q->d_func();
+}
+
+/*!
+ Constructs a new QStateFinishedTransition object that has the given \a
+ sourceState.
+*/
+QStateFinishedTransition::QStateFinishedTransition(QState *sourceState)
+ : QTransition(*new QStateFinishedTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new QStateFinishedTransition object associated with the given
+ \a state, and that has the given \a targets and \a sourceState.
+*/
+QStateFinishedTransition::QStateFinishedTransition(
+ QState *state, const QList<QAbstractState*> &targets, QState *sourceState)
+ : QTransition(*new QStateFinishedTransitionPrivate, targets, sourceState)
+{
+ Q_D(QStateFinishedTransition);
+ d->state = state;
+}
+
+/*!
+ Destroys this QStateFinishedTransition.
+*/
+QStateFinishedTransition::~QStateFinishedTransition()
+{
+}
+
+/*!
+ Returns the state associated with this QStateFinishedTransition.
+*/
+QState *QStateFinishedTransition::state() const
+{
+ Q_D(const QStateFinishedTransition);
+ return d->state;
+}
+
+/*!
+ Sets the \a state associated with this QStateFinishedTransition.
+*/
+void QStateFinishedTransition::setState(QState *state)
+{
+ Q_D(QStateFinishedTransition);
+ d->state = state;
+}
+
+/*!
+ \reimp
+*/
+bool QStateFinishedTransition::eventTest(QEvent *event) const
+{
+ Q_D(const QStateFinishedTransition);
+#ifndef QT_STATEMACHINE_SOLUTION
+ if (event->type() == QEvent::StateFinished) {
+#else
+ if (event->type() == QEvent::Type(QEvent::User-2)) {
+#endif
+ QStateFinishedEvent *sfe = static_cast<QStateFinishedEvent*>(event);
+ return (sfe->state() == d->state);
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QStateFinishedTransition::onTransition()
+{
+}
+
+/*!
+ \reimp
+*/
+bool QStateFinishedTransition::event(QEvent *e)
+{
+ return QTransition::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qstatefinishedtransition.h b/src/corelib/statemachine/qstatefinishedtransition.h
new file mode 100644
index 0000000..bcd82fa
--- /dev/null
+++ b/src/corelib/statemachine/qstatefinishedtransition.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEFINISHEDTRANSITION_H
+#define QSTATEFINISHEDTRANSITION_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qtransition.h>
+#else
+#include "qtransition.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QState;
+
+class QStateFinishedTransitionPrivate;
+class Q_CORE_EXPORT QStateFinishedTransition : public QTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QState* state READ state WRITE setState)
+public:
+ QStateFinishedTransition(QState *sourceState = 0);
+ QStateFinishedTransition(QState *state, const QList<QAbstractState*> &targets,
+ QState *sourceState = 0);
+ ~QStateFinishedTransition();
+
+ QState *state() const; // ### name
+ void setState(QState *state);
+
+protected:
+ bool eventTest(QEvent *event) const;
+ void onTransition();
+
+ bool event(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QStateFinishedTransition)
+ Q_DECLARE_PRIVATE(QStateFinishedTransition)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
new file mode 100644
index 0000000..208c6a9
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -0,0 +1,1847 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qsignaltransition_p.h"
+#include "qsignalevent.h"
+#include "qsignaleventgenerator_p.h"
+#include "qabstractstate.h"
+#include "qabstractstate_p.h"
+#include "qactionstate.h"
+#include "qactionstate_p.h"
+#include "qfinalstate.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+#include "qstatefinishedevent.h"
+#include "qstatefinishedtransition.h"
+#include "qmetaobject.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstateaction.h"
+#include "qstateaction_p.h"
+#ifndef QT_STATEMACHINE_SOLUTION
+#include "private/qobject_p.h"
+#include "private/qthread_p.h"
+#endif
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+#include "qeventtransition.h"
+#include "qeventtransition_p.h"
+#include "qboundevent_p.h"
+#endif
+
+#ifndef QT_NO_ANIMATION
+#include "qpropertyanimation.h"
+#include "qanimationstate.h"
+#endif
+
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QStateMachine
+ \reentrant
+
+ \brief The QStateMachine class provides a hierarchical finite state machine.
+
+ \ingroup statemachine
+
+ The QStateMachine class provides a hierarchical finite state machine based
+ on \l{Statecharts: A visual formalism for complex systems}{Statecharts}
+ concepts and notation. QStateMachine is part of \l{The State Machine
+ Framework}.
+
+ A state machine manages a set of states (QAbstractState objects) and
+ transitions (QAbstractTransition objects) between those states; the states
+ and the transitions collectively define a state graph. Once a state graph
+ has been defined, the state machine can execute it. QStateMachine's
+ execution algorithm is based on the \l{State Chart XML: State Machine
+ Notation for Control Abstraction}{State Chart XML (SCXML)} algorithm.
+
+ The QState class provides a state that you can use to set properties and
+ invoke methods on QObjects when the state is entered or exited. This is
+ typically used in conjunction with \l{Signals and Slots}{signals}; the
+ signals determine the flow of the state graph, whereas the states' property
+ assigments and method invocations are the actions.
+
+ Use the addState() function to add a state to the state machine;
+ alternatively, pass the machine's rootState() to the state constructor. Use
+ the removeState() function to remove a state from the state machine.
+
+ The following snippet shows a state machine that will finish when a button
+ is clicked:
+
+ \code
+ QPushButton button;
+
+ QStateMachine machine;
+ QState *s1 = new QState();
+ s1->setPropertyOnEntry(&button, "text", "Click me");
+
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(&button, SIGNAL(clicked()), s2);
+
+ machine.addState(s1);
+ machine.addState(s2);
+ machine.setInitialState(s1);
+ machine.start();
+ \endcode
+
+ The setInitialState() function sets the state machine's initial state; this
+ state is entered when the state machine is started.
+
+ The start() function starts the state machine. The state machine executes
+ asynchronously, i.e. you need to run an event loop in order for it to make
+ progress. The started() signal is emitted when the state machine has entered
+ the initial state.
+
+ The state machine processes events and takes transitions until a top-level
+ final state is entered; the state machine then emits the finished() signal.
+
+ The stop() function stops the state machine. The stopped() signal is emitted
+ when the state machine has stopped.
+
+ The postEvent() function posts an event to the state machine. This is useful
+ when you are using custom events to trigger transitions.
+
+ The rootState() function returns the state machine's root state. All
+ top-level states have the root state as their parent.
+
+ \sa QAbstractState, QAbstractTransition
+*/
+
+/*!
+ \property QStateMachine::rootState
+
+ \brief the root state of this state machine
+*/
+
+/*!
+ \property QStateMachine::initialState
+
+ \brief the initial state of this state machine
+*/
+
+/*!
+ \property QStateMachine::errorState
+
+ \brief the error state of this state machine
+*/
+
+/*!
+ \property QStateMachine::errorString
+
+ \brief the error string of this state machine
+*/
+
+// #define QSTATEMACHINE_DEBUG
+// #define QT_NO_STATEMACHINE_RESTOREPROPERTIES
+
+QStateMachinePrivate::QStateMachinePrivate()
+{
+ state = NotRunning;
+ processing = false;
+ processingScheduled = false;
+ stop = false;
+ error = QStateMachine::NoError;
+ globalRestorePolicy = QState::DoNotRestoreProperties;
+ rootState = 0;
+ initialErrorStateForRoot = 0;
+#ifndef QT_STATEMACHINE_SOLUTION
+ signalEventGenerator = 0;
+#endif
+}
+
+QStateMachinePrivate::~QStateMachinePrivate()
+{
+ qDeleteAll(internalEventQueue);
+ qDeleteAll(externalEventQueue);
+}
+
+QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q)
+{
+ if (q)
+ return q->d_func();
+ return 0;
+}
+
+static QEvent *cloneEvent(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::None:
+ return new QEvent(*e);
+ case QEvent::Timer:
+ return new QTimerEvent(*static_cast<QTimerEvent*>(e));
+ default:
+ Q_ASSERT_X(false, "cloneEvent()", "not implemented");
+ break;
+ }
+ return 0;
+}
+
+const QStateMachinePrivate::Handler qt_kernel_statemachine_handler = {
+ cloneEvent
+};
+
+const QStateMachinePrivate::Handler *QStateMachinePrivate::handler = &qt_kernel_statemachine_handler;
+
+Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler()
+{
+ return &qt_kernel_statemachine_handler;
+}
+
+bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s1->children().indexOf(s1)
+ < s2->children().indexOf(s2);
+ } else if (isDescendantOf(s1, s2)) {
+ return false;
+ } else if (isDescendantOf(s2, s1)) {
+ return true;
+ } else {
+ // ### fixme
+ return s1 < s2;
+ }
+}
+
+bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s1->children().indexOf(s1)
+ < s2->children().indexOf(s2);
+ } else if (isDescendantOf(s1, s2)) {
+ return true;
+ } else if (isDescendantOf(s2, s1)) {
+ return false;
+ } else {
+ // ### fixme
+ return s2 < s1;
+ }
+}
+
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states)
+{
+ if (states.isEmpty())
+ return 0;
+ QList<QState*> ancestors = properAncestors(states.at(0), 0);
+ for (int i = 0; i < ancestors.size(); ++i) {
+ QState *anc = ancestors.at(i);
+ bool ok = true;
+ for (int j = states.size() - 1; (j > 0) && ok; --j) {
+ const QAbstractState *s = states.at(j);
+ if (!isDescendantOf(s, anc))
+ ok = false;
+ }
+ if (ok)
+ return anc;
+ }
+ return 0;
+}
+
+bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const
+{
+ QSet<QAbstractTransition*>::const_iterator it;
+ for (it = transitions.constBegin(); it != transitions.constEnd(); ++it) {
+ QAbstractTransition *t = *it;
+ QList<QAbstractState*> lst = t->targetStates();
+ if (!lst.isEmpty()) {
+ lst.prepend(t->sourceState());
+ QAbstractState *lca = findLCA(lst);
+ if (isDescendantOf(s, lca)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ":" << transitions << "preempts selection of a transition from"
+ << s << "because" << s << "is a descendant of" << lca;
+#endif
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event) const
+{
+ Q_Q(const QStateMachine);
+ QSet<QAbstractTransition*> enabledTransitions;
+ QSet<QAbstractState*>::const_iterator it;
+ const_cast<QStateMachine*>(q)->beginSelectTransitions(event);
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *state = *it;
+ if (!isAtomic(state))
+ continue;
+ if (isPreempted(state, enabledTransitions))
+ continue;
+ QList<QState*> lst = properAncestors(state, 0);
+ if (QState *grp = qobject_cast<QState*>(state))
+ lst.prepend(grp);
+ bool found = false;
+ for (int j = 0; (j < lst.size()) && !found; ++j) {
+ QState *s = lst.at(j);
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s)->transitions();
+ for (int k = 0; k < transitions.size(); ++k) {
+ QAbstractTransition *t = transitions.at(k);
+ if (QAbstractTransitionPrivate::get(t)->callEventTest(event)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": selecting transition" << t;
+#endif
+ enabledTransitions.insert(t);
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ const_cast<QStateMachine*>(q)->endSelectTransitions(event);
+ return enabledTransitions;
+}
+
+void QStateMachinePrivate::microstep(const QList<QAbstractTransition*> &enabledTransitions)
+{
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ")";
+ qDebug() << q_func() << ": configuration before exiting states:" << configuration;
+#endif
+ exitStates(enabledTransitions);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after exiting states:" << configuration;
+#endif
+ executeTransitionContent(enabledTransitions);
+ enterStates(enabledTransitions);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after entering states:" << configuration;
+ qDebug() << q_func() << ": end microstep";
+#endif
+}
+
+void QStateMachinePrivate::exitStates(const QList<QAbstractTransition*> &enabledTransitions)
+{
+// qDebug() << "exitStates(" << enabledTransitions << ")";
+ QSet<QAbstractState*> statesToExit;
+// QSet<QAbstractState*> statesToSnapshot;
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+ QList<QAbstractState*> lst = t->targetStates();
+ if (lst.isEmpty())
+ continue;
+ lst.prepend(t->sourceState());
+ QAbstractState *lca = findLCA(lst);
+ {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *s = *it;
+ if (isDescendantOf(s, lca))
+ statesToExit.insert(s);
+ }
+ }
+ }
+ QList<QAbstractState*> statesToExit_sorted = statesToExit.toList();
+ qSort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+ if (QState *grp = qobject_cast<QState*>(s)) {
+ QList<QHistoryState*> hlst = QStatePrivate::get(grp)->historyStates();
+ for (int j = 0; j < hlst.size(); ++j) {
+ QHistoryState *h = hlst.at(j);
+ QHistoryStatePrivate::get(h)->configuration.clear();
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *s0 = *it;
+ if (QHistoryStatePrivate::get(h)->historyType == QState::DeepHistory) {
+ if (isAtomic(s0) && isDescendantOf(s0, s))
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ } else if (s0->parentState() == s) {
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ }
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": recorded" << ((QHistoryStatePrivate::get(h)->historyType == QState::DeepHistory) ? "deep" : "shallow")
+ << "history for" << s << "in" << h << ":" << QHistoryStatePrivate::get(h)->configuration;
+#endif
+ }
+ }
+ }
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": exiting" << s;
+#endif
+ QAbstractStatePrivate::get(s)->callOnExit();
+ configuration.remove(s);
+ }
+}
+
+void QStateMachinePrivate::executeTransitionContent(const QList<QAbstractTransition*> &enabledTransitions)
+{
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": triggering" << t;
+#endif
+ QAbstractTransitionPrivate::get(t)->callOnTransition();
+ }
+}
+
+void QStateMachinePrivate::enterStates(const QList<QAbstractTransition*> &enabledTransitions)
+{
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+#endif
+// qDebug() << "enterStates(" << enabledTransitions << ")";
+ QSet<QAbstractState*> statesToEnter;
+ QSet<QAbstractState*> statesForDefaultEntry;
+
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+ QList<QAbstractState*> lst = t->targetStates();
+ if (lst.isEmpty())
+ continue;
+ lst.prepend(t->sourceState());
+ QState *lca = findLCA(lst);
+ for (int j = 1; j < lst.size(); ++j) {
+ QAbstractState *s = lst.at(j);
+ if (QHistoryState *h = qobject_cast<QHistoryState*>(s)) {
+ QList<QAbstractState*> hconf = QHistoryStatePrivate::get(h)->configuration;
+ if (!hconf.isEmpty()) {
+ for (int k = 0; k < hconf.size(); ++k) {
+ QAbstractState *s0 = hconf.at(k);
+ addStatesToEnter(s0, lca, statesToEnter, statesForDefaultEntry);
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": restoring"
+ << ((QHistoryStatePrivate::get(h)->historyType == QState::DeepHistory) ? "deep" : "shallow")
+ << "history from" << s << ":" << hconf;
+#endif
+ } else {
+ QList<QAbstractState*> hlst;
+ if (QHistoryStatePrivate::get(h)->defaultState)
+ hlst.append(QHistoryStatePrivate::get(h)->defaultState);
+ if (hlst.isEmpty()) {
+ setError(QStateMachine::NoDefaultStateInHistoryState, h);
+ } else {
+ for (int k = 0; k < hlst.size(); ++k) {
+ QAbstractState *s0 = hlst.at(k);
+ addStatesToEnter(s0, lca, statesToEnter, statesForDefaultEntry);
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": initial history targets for" << s << ":" << hlst;
+#endif
+ }
+ }
+ } else {
+ addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+
+ // Did an error occur while selecting transitions? Then we enter the error state.
+ if (!pendingErrorStates.isEmpty()) {
+ statesToEnter.clear();
+ statesToEnter = pendingErrorStates;
+ statesForDefaultEntry = pendingErrorStatesForDefaultEntry;
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+ }
+
+ QList<QAbstractState*> statesToEnter_sorted = statesToEnter.toList();
+ qSort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan);
+
+#ifndef QT_NO_STATEMACHINE_RESTOREPROPERTIES
+ bool hasAnimationState = false;
+
+ QHash<RestorableId, QVariant> pendingRestorables = registeredRestorables;
+ for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
+ QAbstractState *as = statesToEnter_sorted.at(i);
+
+#ifndef QT_NO_ANIMATION
+ // If we are going to an animation state, it will restore properties for us
+ hasAnimationState = hasAnimationState
+ || qobject_cast<QAnimationState*>(as) != 0;
+#endif
+
+ QActionState *s = qobject_cast<QActionState*>(as);
+ if (s == 0)
+ continue;
+
+ QActionState::RestorePolicy restorePolicy = s->restorePolicy();
+ if (restorePolicy == QActionState::GlobalRestorePolicy)
+ restorePolicy = globalRestorePolicy;
+
+ if (restorePolicy == QActionState::DoNotRestoreProperties)
+ continue;
+
+ QActionStatePrivate *s_d = QActionStatePrivate::get(s);
+ QList<QStateAction*> actions = s_d->entryActions();
+
+ for (int j = 0; j < actions.size(); ++j) {
+ QStateSetPropertyAction *spa = qobject_cast<QStateSetPropertyAction*>(actions.at(j));
+ if (spa == 0 || spa->targetObject() == 0)
+ continue;
+
+ registerRestorable(spa->targetObject(), spa->propertyName());
+ pendingRestorables.remove(RestorableId(spa->targetObject(), spa->propertyName()));
+ }
+ }
+
+#ifndef QT_NO_ANIMATION
+ // If the configuration has an animation state, we do not want to restore here, as we
+ // might be transitioning inside the animation state (into the final state for instance.)
+ // We let the animation state handle the restoration.
+ QSet<QAbstractState*>::const_iterator it;
+ for (it=configuration.constBegin(); !hasAnimationState && it!=configuration.constEnd(); ++it)
+ hasAnimationState = qobject_cast<QAnimationState*>(*it) != 0;
+#endif
+
+ if (!hasAnimationState) {
+ QHash<RestorableId, QVariant>::const_iterator it;
+ for (it = pendingRestorables.constBegin(); it != pendingRestorables.constEnd(); ++it) {
+ QObject *object = it.key().first;
+ QByteArray propertyName = it.key().second;
+
+ object->setProperty(propertyName, it.value());
+ unregisterRestorable(object, propertyName);
+ }
+ }
+
+#endif // QT_NO_STATEMACHINE_RESTOREPROPERTIES
+
+ for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
+ QAbstractState *s = statesToEnter_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": entering" << s;
+#endif
+ configuration.insert(s);
+ registerTransitions(s);
+ QAbstractStatePrivate::get(s)->callOnEntry();
+ if (statesForDefaultEntry.contains(s)) {
+ // ### executeContent(s.initial.transition.children())
+ }
+ if (isFinal(s)) {
+ QState *parent = s->parentState();
+ if (parent) {
+ QState *grandparent = parent->parentState();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": posting finished event for" << parent;
+#endif
+ internalEventQueue.append(new QStateFinishedEvent(parent));
+ if (grandparent && isParallel(grandparent)) {
+ bool allChildStatesFinal = true;
+ QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates();
+ for (int j = 0; j < childStates.size(); ++j) {
+ QAbstractState *cs = childStates.at(j);
+ if (!isInFinalState(cs)) {
+ allChildStatesFinal = false;
+ break;
+ }
+ }
+ if (allChildStatesFinal) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": posting finished event for" << grandparent;
+#endif
+ internalEventQueue.append(new QStateFinishedEvent(grandparent));
+ }
+ }
+ }
+ }
+ }
+ {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ if (isFinal(*it) && (*it)->parentState() == rootState) {
+ processing = false;
+ stopProcessingReason = Finished;
+ break;
+ }
+ }
+ }
+// qDebug() << "configuration:" << configuration.toList();
+}
+
+void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ statesToEnter.insert(s);
+ if (isParallel(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *child = lst.at(i);
+ addStatesToEnter(child, grp, statesToEnter, statesForDefaultEntry);
+ }
+ } else if (isCompound(s)) {
+ statesForDefaultEntry.insert(s);
+ QState *grp = qobject_cast<QState*>(s);
+ QAbstractState *initial = grp->initialState();
+ if (initial != 0) {
+ addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry);
+ } else {
+ setError(QStateMachine::NoInitialStateError, grp);
+ return;
+ }
+ }
+ QList<QState*> ancs = properAncestors(s, root);
+ for (int i = 0; i < ancs.size(); ++i) {
+ QState *anc = ancs.at(i);
+ if (!anc->parentState())
+ continue;
+ statesToEnter.insert(anc);
+ if (isParallel(anc)) {
+ QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates();
+ for (int j = 0; j < lst.size(); ++j) {
+ QAbstractState *child = lst.at(j);
+ bool hasDescendantInList = false;
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) {
+ if (isDescendantOf(*it, child)) {
+ hasDescendantInList = true;
+ break;
+ }
+ }
+ if (!hasDescendantInList)
+ addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
+bool QStateMachinePrivate::isFinal(const QAbstractState *s)
+{
+ return qobject_cast<const QFinalState*>(s) != 0;
+}
+
+bool QStateMachinePrivate::isParallel(const QAbstractState *s)
+{
+ const QState *ss = qobject_cast<const QState*>(s);
+ return ss && QStatePrivate::get(ss)->isParallelGroup;
+}
+
+bool QStateMachinePrivate::isCompound(const QAbstractState *s)
+{
+ const QState *group = qobject_cast<const QState*>(s);
+ if (!group)
+ return false;
+ return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty())
+ || (qobject_cast<QStateMachine*>(group->parent()) != 0);
+}
+
+bool QStateMachinePrivate::isAtomic(const QAbstractState *s)
+{
+ const QState *ss = qobject_cast<const QState*>(s);
+ return (ss && !QStatePrivate::get(ss)->isParallelGroup
+ && QStatePrivate::get(ss)->childStates().isEmpty())
+ || isFinal(s);
+}
+
+
+bool QStateMachinePrivate::isDescendantOf(const QAbstractState *state, const QAbstractState *other)
+{
+ Q_ASSERT(state != 0);
+ for (QAbstractState *s = state->parentState(); s != 0; s = s->parentState()) {
+ if (s == other)
+ return true;
+ }
+ return false;
+}
+
+QList<QState*> QStateMachinePrivate::properAncestors(const QAbstractState *state, const QState *upperBound)
+{
+ Q_ASSERT(state != 0);
+ QList<QState*> result;
+ for (QState *s = state->parentState(); s && s != upperBound; s = s->parentState()) {
+ result.append(s);
+ }
+ return result;
+}
+
+bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const
+{
+ if (isCompound(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (isFinal(cs) && configuration.contains(cs))
+ return true;
+ }
+ return false;
+ } else if (isParallel(s)) {
+ QState *grp = qobject_cast<QState*>(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (!isInFinalState(cs))
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+void QStateMachinePrivate::registerRestorable(QObject *object, const QByteArray &propertyName)
+{
+ RestorableId id(object, propertyName);
+ if (!registeredRestorables.contains(id))
+ registeredRestorables.insert(id, object->property(propertyName));
+}
+
+/*!
+ \internal
+ Returns true if the variable with the given \a id has been registered for restoration.
+*/
+bool QStateMachinePrivate::hasRestorable(QObject *object, const QByteArray &propertyName) const
+{
+ return registeredRestorables.contains(RestorableId(object, propertyName));
+}
+
+QVariant QStateMachinePrivate::restorableValue(QObject *object, const QByteArray &propertyName) const
+{
+ return registeredRestorables.value(RestorableId(object, propertyName), QVariant());
+}
+
+
+/*!
+ \internal
+ Unregisters the variable identified by \a id
+*/
+void QStateMachinePrivate::unregisterRestorable(QObject *object, const QByteArray &propertyName)
+{
+ RestorableId id(object, propertyName);
+ registeredRestorables.remove(id);
+
+#ifndef QT_NO_ANIMATION
+ registeredRestorableAnimations.remove(id);
+#endif
+
+}
+
+#ifndef QT_NO_ANIMATION
+void QStateMachinePrivate::registerRestorable(QPropertyAnimation *animation)
+{
+ // We always want to restore to the first registered value, so if one is already present, we
+ // leave it be.
+ RestorableId id(animation->targetObject(), animation->propertyName());
+ if (!registeredRestorableAnimations.contains(id))
+ registeredRestorableAnimations.insert(id, animation);
+ registerRestorable(animation->targetObject(), animation->propertyName());
+}
+
+
+/*!
+ \internal
+ Returns all variables currently registered. The list returned is in no particular order.
+*/
+QList<QPropertyAnimation*> QStateMachinePrivate::restorableAnimations() const
+{
+ return registeredRestorableAnimations.values();
+}
+
+/*!
+ \internal
+ Returns a reference to the restorable identified by \a id.
+*/
+QPropertyAnimation *QStateMachinePrivate::restorableAnimation(QObject *object,
+ const QByteArray &propertyName)
+{
+ return registeredRestorableAnimations.value(RestorableId(object, propertyName), 0);
+}
+
+#endif // QT_NO_ANIMATION
+
+QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context)
+{
+ // If the user sets the root state's error state to 0, we return the initial error state
+ if (context == 0)
+ return initialErrorStateForRoot;
+
+ // Find error state recursively in parent hierarchy if not set explicitly for context state
+ QAbstractState *errorState = 0;
+ QState *s = qobject_cast<QState*>(context);
+ if (s) {
+ errorState = s->errorState();
+ if (!errorState)
+ errorState = findErrorState(s->parentState());
+ return errorState;
+ }
+
+ return errorState;
+}
+
+void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext)
+{
+ error = errorCode;
+
+ switch (errorCode) {
+ case QStateMachine::NoInitialStateError:
+ Q_ASSERT(currentContext != 0);
+
+ errorString = QStateMachine::tr("Missing initial state in compound state '%1'")
+ .arg(currentContext->objectName());
+
+ break;
+ case QStateMachine::NoDefaultStateInHistoryState:
+ Q_ASSERT(currentContext != 0);
+
+ errorString = QStateMachine::tr("Missing default state in history state '%1'")
+ .arg(currentContext->objectName());
+ break;
+ default:
+ errorString = QStateMachine::tr("Unknown error");
+ };
+
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+
+ QAbstractState *currentErrorState = findErrorState(currentContext);
+
+ // Avoid infinite loop if the error state itself has an error
+ if (currentContext == currentErrorState) {
+ Q_ASSERT(currentContext != initialErrorStateForRoot); // RootErrorState is broken
+ currentErrorState = initialErrorStateForRoot;
+ }
+
+ if (currentErrorState) {
+ QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
+ addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ }
+}
+
+namespace {
+
+class StartState : public QState
+{
+public:
+ StartState(QState *parent)
+ : QState(parent) {}
+protected:
+ void onEntry() {}
+ void onExit() {}
+};
+
+class InitialTransition : public QAbstractTransition
+{
+public:
+ InitialTransition(QAbstractState *target)
+ : QAbstractTransition(QList<QAbstractState*>() << target) {}
+protected:
+ virtual bool eventTest(QEvent *) const { return true; }
+ virtual void onTransition() {}
+};
+
+} // namespace
+
+void QStateMachinePrivate::_q_start()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Starting);
+ if (!rootState) {
+ state = NotRunning;
+ return;
+ }
+ QAbstractState *initial = rootState->initialState();
+ if (initial == 0)
+ setError(QStateMachine::NoInitialStateError, rootState);
+
+ configuration.clear();
+ qDeleteAll(internalEventQueue);
+ internalEventQueue.clear();
+ qDeleteAll(externalEventQueue);
+ externalEventQueue.clear();
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting";
+#endif
+ state = Running;
+ processingScheduled = true; // we call _q_process() below
+ emit q->started();
+
+ StartState *start = new StartState(rootState);
+ QAbstractTransition *initialTransition = new InitialTransition(initial);
+ start->addTransition(initialTransition);
+ QList<QAbstractTransition*> transitions;
+ transitions.append(initialTransition);
+ executeTransitionContent(transitions);
+ enterStates(transitions);
+ delete start;
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": initial configuration:" << configuration;
+#endif
+ _q_process();
+}
+
+void QStateMachinePrivate::_q_process()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Running);
+ Q_ASSERT(!processing);
+ processing = true;
+ processingScheduled = false;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting the event processing loop";
+#endif
+ while (processing) {
+ if (stop) {
+ stop = false;
+ processing = false;
+ stopProcessingReason = Stopped;
+ break;
+ }
+ QSet<QAbstractTransition*> enabledTransitions;
+ QEvent *e = new QEvent(QEvent::None);
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ if (enabledTransitions.isEmpty() && !internalEventQueue.isEmpty()) {
+ e = internalEventQueue.takeFirst();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued internal event" << e;
+#endif
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ }
+ if (enabledTransitions.isEmpty()) {
+ if (externalEventQueue.isEmpty()) {
+ if (internalEventQueue.isEmpty()) {
+ processing = false;
+ stopProcessingReason = EventQueueEmpty;
+ }
+ } else {
+ e = externalEventQueue.takeFirst();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued external event" << e;
+#endif
+ enabledTransitions = selectTransitions(e);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = 0;
+ }
+ }
+ }
+ if (!enabledTransitions.isEmpty()) {
+ q->beginMicrostep(e);
+ microstep(enabledTransitions.toList());
+ q->endMicrostep(e);
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ else {
+ qDebug() << q << ": no transitions enabled";
+ }
+#endif
+ delete e;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": finished the event processing loop";
+#endif
+ switch (stopProcessingReason) {
+ case EventQueueEmpty:
+ break;
+ case Finished:
+ state = NotRunning;
+ emit q->finished();
+ break;
+ case Stopped:
+ state = NotRunning;
+ emit q->stopped();
+ break;
+ }
+}
+
+void QStateMachinePrivate::scheduleProcess()
+{
+ if ((state != Running) || processing || processingScheduled)
+ return;
+ processingScheduled = true;
+ QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection);
+}
+
+void QStateMachinePrivate::registerTransitions(QAbstractState *state)
+{
+ QState *group = qobject_cast<QState*>(state);
+ if (!group)
+ return;
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(group)->transitions();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QAbstractTransition *t = transitions.at(i);
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(t)) {
+ registerSignalTransition(st);
+ }
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(t)) {
+ registerEventTransition(oet);
+ }
+#endif
+ }
+}
+
+void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition)
+{
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
+ unregisterSignalTransition(st);
+ }
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
+ unregisterEventTransition(oet);
+ }
+#endif
+}
+
+#ifndef QT_STATEMACHINE_SOLUTION
+
+static int senderSignalIndex(const QObject *sender)
+{
+ QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject*>(sender));
+ QMutexLocker(&d->threadData->mutex);
+ if (!d->currentSender)
+ return -1;
+
+ // Return -1 if d->currentSender isn't in d->senders
+ bool found = false;
+ for (int i = 0; !found && i < d->senders.count(); ++i)
+ found = (d->senders.at(i).sender == d->currentSender->sender);
+ if (!found)
+ return -1;
+ return d->currentSender->signal;
+}
+
+#endif
+
+void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QSignalTransitionPrivate::get(transition)->signalIndex != -1)
+ return; // already registered
+ QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
+ if (!sender)
+ return;
+ QByteArray signal = QSignalTransitionPrivate::get(transition)->signal;
+ if (signal.startsWith('0'+QSIGNAL_CODE))
+ signal.remove(0, 1);
+ int signalIndex = sender->metaObject()->indexOfSignal(signal);
+ if (signalIndex == -1) {
+ qWarning("QSignalTransition: no such signal: %s::%s",
+ sender->metaObject()->className(), signal.constData());
+ return;
+ }
+ QList<int> &connectedSignalIndexes = connections[sender];
+ if (!connectedSignalIndexes.contains(signalIndex)) {
+#ifndef QT_STATEMACHINE_SOLUTION
+ if (!signalEventGenerator)
+ signalEventGenerator = new QSignalEventGenerator(q);
+#else
+ QSignalEventGenerator *signalEventGenerator = new QSignalEventGenerator(signalIndex, q);
+#endif
+ bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator,
+ signalEventGenerator->metaObject()->methodOffset());
+ if (!ok) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": FAILED to add signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << (signal.mid(1))
+ << ", targets =" << transition->targetStates() << ")";
+#endif
+ return;
+ }
+ connectedSignalIndexes.append(signalIndex);
+ }
+ QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << (signal.mid(1))
+ << ", targets =" << transition->targetStates() << ")";
+#endif
+}
+
+void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transition)
+{
+ int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex;
+ if (signalIndex == -1)
+ return; // not registered
+ const QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
+ QList<int> &connectedSignalIndexes = connections[sender];
+ Q_ASSERT(connectedSignalIndexes.contains(signalIndex));
+ Q_ASSERT(signalEventGenerator != 0);
+ bool ok = QMetaObject::disconnect(sender, signalIndex, signalEventGenerator,
+ signalEventGenerator->metaObject()->methodOffset());
+ if (ok) {
+ connectedSignalIndexes.removeOne(signalIndex);
+ if (connectedSignalIndexes.isEmpty())
+ connections.remove(sender);
+ QSignalTransitionPrivate::get(transition)->signalIndex = -1;
+ }
+}
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+void QStateMachinePrivate::registerEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QEventTransitionPrivate::get(transition)->registered)
+ return;
+ if (transition->eventType() >= QEvent::User) {
+ qWarning("QObject event transitions are not supported for custom types");
+ return;
+ }
+ QObject *object = QEventTransitionPrivate::get(transition)->object;
+ if (!object)
+ return;
+#ifndef QT_STATEMACHINE_SOLUTION
+ QObjectPrivate *od = QObjectPrivate::get(object);
+ if (!od->eventFilters.contains(q))
+#endif
+ object->installEventFilter(q);
+ qobjectEvents[object].insert(transition->eventType());
+ QEventTransitionPrivate::get(transition)->registered = true;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added event transition from" << transition->sourceState()
+ << ": ( object =" << object << ", event =" << transition->eventType()
+ << ", targets =" << transition->targetStates() << ")";
+#endif
+}
+
+void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (!QEventTransitionPrivate::get(transition)->registered)
+ return;
+ QObject *object = QEventTransitionPrivate::get(transition)->object;
+ QSet<QEvent::Type> &events = qobjectEvents[object];
+ events.remove(transition->eventType());
+ if (events.isEmpty()) {
+ qobjectEvents.remove(object);
+ object->removeEventFilter(q);
+ }
+ QEventTransitionPrivate::get(transition)->registered = false;
+}
+#endif
+
+void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex,
+ void **argv)
+{
+ const QList<int> &connectedSignalIndexes = connections[sender];
+ Q_ASSERT(connectedSignalIndexes.contains(signalIndex));
+ const QMetaObject *meta = sender->metaObject();
+ QMetaMethod method = meta->method(signalIndex);
+ QList<QByteArray> parameterTypes = method.parameterTypes();
+ int argc = parameterTypes.count();
+ QList<QVariant> vargs;
+ for (int i = 0; i < argc; ++i) {
+ int type = QMetaType::type(parameterTypes.at(i));
+ vargs.append(QVariant(type, argv[i+1]));
+ }
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": sending signal event ( sender =" << sender
+ << ", signal =" << sender->metaObject()->method(signalIndex).signature() << ")";
+#endif
+ internalEventQueue.append(new QSignalEvent(sender, signalIndex, vargs));
+ scheduleProcess();
+}
+
+/*!
+ Constructs a new state machine with the given \a parent.
+*/
+QStateMachine::QStateMachine(QObject *parent)
+ : QObject(
+#ifndef QT_STATEMACHINE_SOLUTION
+ *new QStateMachinePrivate,
+#endif
+ parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , d_ptr(new QStateMachinePrivate)
+#endif
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ d_ptr->q_ptr = this;
+#endif
+}
+
+/*!
+ Destroys this state machine.
+*/
+QStateMachine::~QStateMachine()
+{
+#ifdef QT_STATEMACHINE_SOLUTION
+ delete d_ptr;
+#endif
+}
+
+namespace {
+
+class RootErrorState : public QAbstractState
+{
+public:
+ RootErrorState(QState *parent)
+ : QAbstractState(parent)
+ {
+ setObjectName(QString::fromLatin1("DefaultErrorState"));
+ }
+
+ void onEntry()
+ {
+ QAbstractStatePrivate *d = QAbstractStatePrivate::get(this);
+ QStateMachine *machine = d->machine();
+
+ qWarning("Unrecoverable error detected in running state machine: %s",
+ qPrintable(machine->errorString()));
+ }
+
+ void onExit() {}
+};
+
+class RootState : public QState
+{
+public:
+ RootState(QState *parent)
+ : QState(parent)
+ {
+ }
+
+ void onEntry() {}
+ void onExit() {}
+};
+
+} // namespace
+
+/*!
+ Returns this state machine's root state.
+*/
+QState *QStateMachine::rootState() const
+{
+ Q_D(const QStateMachine);
+ if (!d->rootState) {
+ const_cast<QStateMachinePrivate*>(d)->rootState = new RootState(0);
+ const_cast<QStateMachinePrivate*>(d)->initialErrorStateForRoot = new RootErrorState(d->rootState);
+ d->rootState->setParent(const_cast<QStateMachine*>(this));
+ d->rootState->setErrorState(d->initialErrorStateForRoot);
+ }
+ return d->rootState;
+}
+
+/*!
+ Returns the error state of the state machine's root state.
+
+ \sa QState::errorState()
+*/
+QAbstractState *QStateMachine::errorState() const
+{
+ return rootState()->errorState();
+}
+
+/*!
+ Sets the error state of this state machine's root state to be \a state. When a running state
+ machine encounters an error which puts it in an undefined state, it will enter an error state
+ based on the context of the error that occurred. It will enter this state regardless of what
+ is currently in the event queue.
+
+ If the erroneous state has an error state set, this will be entered by the machine. If no error
+ state has been set, the state machine will search the parent hierarchy recursively for an
+ error state. The error state of the root state can thus be seen as a global error state that
+ applies for the states for which a more specific error state has not been set.
+
+ Before entering the error state, the state machine will set the error code returned by error() and
+ error message returned by errorString().
+
+ The default error state will print a warning to the console containing the information returned by
+ errorString(). By setting a new error state on either the state machine itself, or on specific
+ states, you can fine tune error handling in the state machine.
+
+ If the root state's error state is set to 0, or if the error state selected by the machine itself
+ contains an error, the default error state will be used.
+
+ \sa QState::setErrorState(), rootState()
+*/
+void QStateMachine::setErrorState(QAbstractState *state)
+{
+ rootState()->setErrorState(state);
+}
+
+/*! \enum QStateMachine::Error
+
+ This enum type defines errors that can occur in the state machine at run time. When the state
+ machine encounters an unrecoverable error at run time, it will set the error code returned
+ by error(), the error message returned by errorString(), and enter an error state based on
+ the context of the error.
+
+ \value NoError No error has occurred.
+ \value NoInitialStateError The machine has entered a QState with children which does not have an
+ initial state set. The context of this error is the state which is missing an initial
+ state.
+ \value NoDefaultStateInHistoryState The machine has entered a QHistoryState which does not have
+ a default state set. The context of this error is the QHistoryState which is missing a
+ default state.
+
+ \sa setErrorState()
+*/
+
+/*!
+ Returns the error code of the last error that occurred in the state machine.
+*/
+QStateMachine::Error QStateMachine::error() const
+{
+ Q_D(const QStateMachine);
+ return d->error;
+}
+
+/*!
+ Returns the error string of the last error that occurred in the state machine.
+*/
+QString QStateMachine::errorString() const
+{
+ Q_D(const QStateMachine);
+ return d->errorString;
+}
+
+/*!
+ Clears the error string and error code of the state machine.
+*/
+void QStateMachine::clearError()
+{
+ Q_D(QStateMachine);
+ d->errorString.clear();
+ d->error = NoError;
+}
+
+/*!
+ Returns the global restore policy of the state machine.
+
+ \sa QActionState::restorePolicy()
+*/
+QActionState::RestorePolicy QStateMachine::globalRestorePolicy() const
+{
+ Q_D(const QStateMachine);
+ return d->globalRestorePolicy;
+}
+
+/*!
+ Sets the global restore policy of the state machine to \a restorePolicy. The default global
+ restore policy is QActionState::DoNotRestoreProperties.
+
+ The global restore policy cannot be set to QActionState::GlobalRestorePolicy.
+
+ \sa QActionState::setRestorePolicy()
+*/
+void QStateMachine::setGlobalRestorePolicy(QActionState::RestorePolicy restorePolicy)
+{
+ Q_D(QStateMachine);
+ if (restorePolicy == QState::GlobalRestorePolicy) {
+ qWarning("QStateMachine::setGlobalRestorePolicy: Cannot set global restore policy to "
+ "GlobalRestorePolicy");
+ return;
+ }
+
+ d->globalRestorePolicy = restorePolicy;
+}
+
+/*!
+ Returns this state machine's initial state, or 0 if no initial state has
+ been set.
+*/
+QAbstractState *QStateMachine::initialState() const
+{
+ Q_D(const QStateMachine);
+ if (!d->rootState)
+ return 0;
+ return d->rootState->initialState();
+}
+
+/*!
+ Sets this state machine's initial \a state.
+*/
+void QStateMachine::setInitialState(QAbstractState *state)
+{
+ Q_D(QStateMachine);
+ if (!d->rootState) {
+ if (!state)
+ return;
+ rootState()->setInitialState(state);
+ }
+ d->rootState->setInitialState(state);
+}
+
+/*!
+ Adds the given \a state to this state machine. The state becomes a top-level
+ state (i.e. a child of the rootState()).
+
+ If the state is already in a different machine, it will first be removed
+ from its old machine, and then added to this machine.
+
+ \sa removeState(), rootState()
+*/
+void QStateMachine::addState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::addState: cannot add null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() == this) {
+ qWarning("QStateMachine::addState: state has already been added to this machine");
+ return;
+ }
+ state->setParent(rootState());
+}
+
+/*!
+ Removes the given \a state from this state machine. The state machine
+ releases ownership of the state.
+
+ \sa addState()
+*/
+void QStateMachine::removeState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::removeState: cannot remove null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() != this) {
+ qWarning("QStateMachine::removeState: state %p's machine (%p)"
+ " is different from this machine (%p)",
+ state, QAbstractStatePrivate::get(state)->machine(), this);
+ return;
+ }
+ state->setParent(0);
+}
+
+/*!
+ Starts this state machine.
+ The machine will reset its configuration and transition to the initial
+ state. When a final top-level state is entered, the machine will emit the
+ finished() signal.
+
+ \sa started(), finished(), stop(), initialState()
+*/
+void QStateMachine::start()
+{
+ Q_D(QStateMachine);
+
+ if (rootState()->initialState() == 0) {
+ qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
+ return;
+ }
+
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ d->state = QStateMachinePrivate::Starting;
+ QMetaObject::invokeMethod(this, "_q_start", Qt::QueuedConnection);
+ break;
+ case QStateMachinePrivate::Starting:
+ break;
+ case QStateMachinePrivate::Running:
+ qWarning("QStateMachine::start(): already running");
+ break;
+ }
+}
+
+/*!
+ Stops this state machine.
+
+ \sa stopped()
+*/
+void QStateMachine::stop()
+{
+ Q_D(QStateMachine);
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ break;
+ case QStateMachinePrivate::Starting:
+ // the machine will exit as soon as it enters the event processing loop
+ d->stop = true;
+ break;
+ case QStateMachinePrivate::Running:
+ d->stop = true;
+ d->scheduleProcess();
+ break;
+ }
+}
+
+/*!
+ Posts the given \a event for processing by this state machine, with a delay
+ of \a delay milliseconds.
+
+ This function returns immediately. The event is added to the state machine's
+ event queue. Events are processed in the order posted. The state machine
+ takes ownership of the event and deletes it once it has been processed.
+
+ You can only post events when the state machine is running.
+*/
+void QStateMachine::postEvent(QEvent *event, int delay)
+{
+ Q_D(QStateMachine);
+ if (d->state != QStateMachinePrivate::Running) {
+ qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running");
+ return;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting external event" << event << "with delay" << delay;
+#endif
+ if (delay) {
+ int tid = startTimer(delay);
+ d->delayedEvents[tid] = event;
+ } else {
+ d->externalEventQueue.append(event);
+ d->scheduleProcess();
+ }
+}
+
+/*!
+ \internal
+
+ Posts the given internal \a event for processing by this state machine.
+*/
+void QStateMachine::postInternalEvent(QEvent *event)
+{
+ Q_D(QStateMachine);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting internal event" << event;
+#endif
+ d->internalEventQueue.append(event);
+ d->scheduleProcess();
+}
+
+/*!
+ Returns the list of this state machine's states, or an empty list if the
+ state machine has no states.
+*/
+QList<QAbstractState*> QStateMachine::states() const
+{
+ return QStatePrivate::get(rootState())->childStates();
+}
+
+/*!
+ \internal
+
+ Returns the maximal consistent set of states (including parallel and final
+ states) that this state machine is currently in. If a state \c s is in the
+ configuration, it is always the case that the parent of \c s is also in
+ c. Note, however, that the rootState() is not an explicit member of the
+ configuration.
+*/
+QSet<QAbstractState*> QStateMachine::configuration() const
+{
+ Q_D(const QStateMachine);
+ return d->configuration;
+}
+
+/*!
+ \fn QStateMachine::started()
+
+ This signal is emitted when the state machine has entered its initial state.
+
+ \sa QStateMachine::finished(), QStateMachine::start()
+*/
+
+/*!
+ \fn QStateMachine::finished()
+
+ This signal is emitted when the state machine has reached a top-level final
+ state.
+
+ \sa QStateMachine::started()
+*/
+
+/*!
+ \fn QStateMachine::stopped()
+
+ This signal is emitted when the state machine has stopped.
+
+ \sa QStateMachine::stop()
+*/
+
+/*!
+ \reimp
+*/
+bool QStateMachine::event(QEvent *e)
+{
+ Q_D(QStateMachine);
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = static_cast<QTimerEvent*>(e);
+ int tid = te->timerId();
+ if (d->delayedEvents.contains(tid)) {
+ killTimer(tid);
+ QEvent *ee = d->delayedEvents.take(tid);
+ d->externalEventQueue.append(ee);
+ d->scheduleProcess();
+ return true;
+ }
+ } else if (e->type() == QEvent::ChildAdded) {
+ QChildEvent *ce = static_cast<QChildEvent*>(e);
+ if (QAbstractState *state = qobject_cast<QAbstractState*>(ce->child())) {
+ if (state != rootState()) {
+ state->setParent(rootState());
+ return true;
+ }
+ }
+ }
+ return QObject::event(e);
+}
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+/*!
+ \reimp
+*/
+bool QStateMachine::eventFilter(QObject *watched, QEvent *event)
+{
+ Q_D(QStateMachine);
+ Q_ASSERT(d->qobjectEvents.contains(watched));
+ if (d->qobjectEvents[watched].contains(event->type()))
+ postEvent(new QBoundEvent(watched, d->handler->cloneEvent(event)));
+ return false;
+}
+#endif
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to select
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished selecting
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to do a microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished doing a
+ microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+static const uint qt_meta_data_QSignalEventGenerator[] = {
+
+ // content:
+ 2, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 12, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+
+ // slots: signature, parameters, type, tag, flags
+ 23, 22, 22, 22, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QSignalEventGenerator[] = {
+ "QSignalEventGenerator\0\0execute()\0"
+};
+
+const QMetaObject QSignalEventGenerator::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator,
+ qt_meta_data_QSignalEventGenerator, 0 }
+};
+
+const QMetaObject *QSignalEventGenerator::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QSignalEventGenerator::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator))
+ return static_cast<void*>(const_cast< QSignalEventGenerator*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: {
+#ifndef QT_STATEMACHINE_SOLUTION
+// ### in Qt 4.6 we can use QObject::senderSignalIndex()
+ int signalIndex = senderSignalIndex(this);
+ Q_ASSERT(signalIndex != -1);
+#endif
+ QStateMachine *machine = qobject_cast<QStateMachine*>(parent());
+ QStateMachinePrivate::get(machine)->handleTransitionSignal(sender(), signalIndex, _a);
+ break;
+ }
+ default: ;
+ }
+ _id -= 1;
+ }
+ return _id;
+}
+
+QSignalEventGenerator::QSignalEventGenerator(
+#ifdef QT_STATEMACHINE_SOLUTION
+ int sigIdx,
+#endif
+ QStateMachine *parent)
+ : QObject(parent)
+#ifdef QT_STATEMACHINE_SOLUTION
+ , signalIndex(sigIdx)
+#endif
+{
+}
+
+/*!
+ \class QSignalEvent
+
+ \brief The QSignalEvent class represents a Qt signal event.
+
+ \ingroup statemachine
+
+ A signal event is generated by a QStateMachine in response to a Qt
+ signal. The QSignalTransition class provides a transition associated with a
+ signal event. QSignalEvent is part of \l{The State Machine Framework}.
+
+ The sender() function returns the object that generated the signal. The
+ signalIndex() function returns the index of the signal. The arguments()
+ function returns the arguments of the signal.
+
+ \sa QSignalTransition
+*/
+
+/*!
+ Constructs a new QSignalEvent object with the given \a sender, \a
+ signalIndex and \a arguments.
+*/
+QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments)
+ :
+#ifndef QT_STATEMACHINE_SOLUTION
+ QEvent(QEvent::Signal)
+#else
+ QEvent(QEvent::Type(QEvent::User-1))
+#endif
+ , m_sender(sender), m_signalIndex(signalIndex), m_arguments(arguments)
+{
+}
+
+/*!
+ Destroys this QSignalEvent.
+*/
+QSignalEvent::~QSignalEvent()
+{
+}
+
+/*!
+ \fn QSignalEvent::sender() const
+
+ Returns the object that emitted the signal.
+
+ \sa QObject::sender()
+*/
+
+/*!
+ \fn QSignalEvent::signalIndex() const
+
+ Returns the index of the signal.
+
+ \sa QMetaObject::indexOfSignal()
+*/
+
+/*!
+ \fn QSignalEvent::arguments() const
+
+ Returns the arguments of the signal.
+*/
+
+/*!
+ \class QStateFinishedEvent
+
+ \brief The QStateFinishedEvent class contains parameters that describe a state that has finished.
+
+ \ingroup statemachine
+
+ A state is finished when one of its final child states (a QFinalState) is
+ entered; this will cause a QStateFinishedEvent to be generated by the state
+ machine. QStateFinishedEvent is part of \l{The State Machine Framework}.
+
+ Typically you do not create QStateFinishedEvent objects yourself, but rather
+ use QStateFinishedTransition to create a transition that's triggered by a
+ state's finished event.
+
+ \sa QStateFinishedTransition
+*/
+
+/*!
+ Constructs a new QStateFinishedEvent object associated with the given \a state.
+*/
+QStateFinishedEvent::QStateFinishedEvent(QState *state)
+ :
+#ifndef QT_STATEMACHINE_SOLUTION
+ QEvent(StateFinished)
+#else
+ QEvent(QEvent::Type(QEvent::User-2))
+#endif
+ , m_state(state)
+{
+}
+
+/*!
+ Destroys this QStateFinishedEvent.
+*/
+QStateFinishedEvent::~QStateFinishedEvent()
+{
+}
+
+/*!
+ Returns the state associated with this QStateFinishedEvent.
+*/
+QState *QStateFinishedEvent::state() const
+{
+ return m_state;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qstatemachine.cpp"
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
new file mode 100644
index 0000000..e3b09e0
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEMACHINE_H
+#define QSTATEMACHINE_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+# include <QtCore/qactionstate.h>
+#else
+# include "qactionstate.h"
+#endif
+
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qset.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEvent;
+class QAbstractState;
+class QState;
+
+class QStateMachinePrivate;
+class Q_CORE_EXPORT QStateMachine : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QState* rootState READ rootState)
+ Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState)
+ Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState)
+ Q_PROPERTY(QString errorString READ errorString)
+public:
+
+ enum Error {
+ NoError,
+ NoInitialStateError,
+ NoDefaultStateInHistoryState,
+ };
+
+ QStateMachine(QObject *parent = 0);
+ ~QStateMachine();
+
+ void addState(QAbstractState *state);
+ void removeState(QAbstractState *state);
+
+ QState *rootState() const;
+
+ QAbstractState *initialState() const;
+ void setInitialState(QAbstractState *state);
+
+ QAbstractState *errorState() const;
+ void setErrorState(QAbstractState *state);
+
+ Error error() const;
+ QString errorString() const;
+ void clearError();
+
+ QActionState::RestorePolicy globalRestorePolicy() const;
+ void setGlobalRestorePolicy(QActionState::RestorePolicy restorePolicy);
+
+ void postEvent(QEvent *event, int delay = 0);
+
+ QList<QAbstractState*> states() const;
+ QSet<QAbstractState*> configuration() const;
+
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ bool eventFilter(QObject *watched, QEvent *event);
+#endif
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+Q_SIGNALS:
+ void started();
+ void stopped();
+ void finished();
+
+protected:
+ void postInternalEvent(QEvent *event);
+
+ virtual void beginSelectTransitions(QEvent *event);
+ virtual void endSelectTransitions(QEvent *event);
+
+ virtual void beginMicrostep(QEvent *event);
+ virtual void endMicrostep(QEvent *event);
+
+ bool event(QEvent *e);
+
+#ifdef QT_STATEMACHINE_SOLUTION
+ QStateMachinePrivate *d_ptr;
+#endif
+
+private:
+ Q_DISABLE_COPY(QStateMachine)
+ Q_DECLARE_PRIVATE(QStateMachine)
+ Q_PRIVATE_SLOT(d_func(), void _q_start())
+ Q_PRIVATE_SLOT(d_func(), void _q_process())
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
new file mode 100644
index 0000000..dfa95e5
--- /dev/null
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATEMACHINE_P_H
+#define QSTATEMACHINE_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.
+//
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <private/qobject_p.h>
+#endif
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+
+#include "qstate.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+class QEventTransition;
+#endif
+class QSignalEventGenerator;
+class QSignalTransition;
+class QAbstractState;
+class QAbstractTransition;
+class QState;
+
+#ifndef QT_NO_ANIMATION
+class QPropertyAnimation;
+#endif
+
+class QStateMachine;
+class Q_CORE_EXPORT QStateMachinePrivate
+#ifndef QT_STATEMACHINE_SOLUTION
+ : public QObjectPrivate
+#endif
+{
+ Q_DECLARE_PUBLIC(QStateMachine)
+public:
+ enum State {
+ NotRunning,
+ Starting,
+ Running
+ };
+ enum StopProcessingReason {
+ EventQueueEmpty,
+ Finished,
+ Stopped
+ };
+
+ QStateMachinePrivate();
+ ~QStateMachinePrivate();
+
+ static QStateMachinePrivate *get(QStateMachine *q);
+
+ static QState *findLCA(const QList<QAbstractState*> &states);
+
+ static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
+ static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
+
+ QAbstractState *findErrorState(QAbstractState *context);
+ void setError(QStateMachine::Error error, QAbstractState *currentContext);
+
+ // private slots
+ void _q_start();
+ void _q_process();
+
+ void microstep(const QList<QAbstractTransition*> &transitionList);
+ bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
+ QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
+ void exitStates(const QList<QAbstractTransition*> &transitionList);
+ void executeTransitionContent(const QList<QAbstractTransition*> &transitionList);
+ void enterStates(const QList<QAbstractTransition*> &enabledTransitions);
+ void addStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
+
+ bool isInFinalState(QAbstractState *s) const;
+ static bool isFinal(const QAbstractState *s);
+ static bool isParallel(const QAbstractState *s);
+ static bool isCompound(const QAbstractState *s);
+ static bool isAtomic(const QAbstractState *s);
+ static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
+ static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
+
+ void registerTransitions(QAbstractState *state);
+ void registerSignalTransition(QSignalTransition *transition);
+ void unregisterSignalTransition(QSignalTransition *transition);
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ void registerEventTransition(QEventTransition *transition);
+ void unregisterEventTransition(QEventTransition *transition);
+#endif
+ void unregisterTransition(QAbstractTransition *transition);
+ void handleTransitionSignal(const QObject *sender, int signalIndex,
+ void **args);
+ void scheduleProcess();
+
+ typedef QPair<QObject *, QByteArray> RestorableId;
+ QHash<RestorableId, QVariant> registeredRestorables;
+ void registerRestorable(QObject *object, const QByteArray &propertyName);
+ void unregisterRestorable(QObject *object, const QByteArray &propertyName);
+ bool hasRestorable(QObject *object, const QByteArray &propertyName) const;
+ QVariant restorableValue(QObject *object, const QByteArray &propertyName) const;
+
+#ifndef QT_NO_ANIMATION
+ void registerRestorable(QPropertyAnimation *animation);
+
+ QPropertyAnimation *restorableAnimation(QObject *object, const QByteArray &propertyName);
+ QList<QPropertyAnimation *> restorableAnimations() const;
+
+ QHash<RestorableId, QPropertyAnimation*> registeredRestorableAnimations;
+#endif // QT_NO_ANIMATION
+
+ State state;
+ bool processing;
+ bool processingScheduled;
+ bool stop;
+ StopProcessingReason stopProcessingReason;
+ QState *rootState;
+ QSet<QAbstractState*> configuration;
+ QList<QEvent*> internalEventQueue;
+ QList<QEvent*> externalEventQueue;
+
+ QStateMachine::Error error;
+ QActionState::RestorePolicy globalRestorePolicy;
+
+ QString errorString;
+ QSet<QAbstractState *> pendingErrorStates;
+ QSet<QAbstractState *> pendingErrorStatesForDefaultEntry;
+ QAbstractState *initialErrorStateForRoot;
+
+#ifndef QT_STATEMACHINE_SOLUTION
+ QSignalEventGenerator *signalEventGenerator;
+#endif
+ QHash<const QObject*, QList<int> > connections;
+#ifndef QT_NO_STATEMACHINE_EVENTFILTER
+ QHash<QObject*, QSet<QEvent::Type> > qobjectEvents;
+#endif
+ QHash<int, QEvent*> delayedEvents;
+
+ typedef QEvent* (*f_cloneEvent)(QEvent*);
+ struct Handler {
+ f_cloneEvent cloneEvent;
+ };
+
+ static const Handler *handler;
+
+#ifdef QT_STATEMACHINE_SOLUTION
+ QStateMachine *q_ptr;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/qtransition.cpp b/src/corelib/statemachine/qtransition.cpp
new file mode 100644
index 0000000..ebd972c
--- /dev/null
+++ b/src/corelib/statemachine/qtransition.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "qtransition.h"
+#include "qtransition_p.h"
+#include "qstateaction.h"
+#include "qstateaction_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QTransition
+
+ \brief The QTransition class provides an action-based transition.
+
+ \ingroup statemachine
+
+ QTransition provides an action-based transition; you add actions with the
+ addAction() function. The transition executes the actions when the
+ transition is triggered. QTransition is part of \l{The State Machine
+ Framework}.
+
+ Built-in actions are provided for setting properties and invoking methods of
+ QObjects. The setPropertyOnTransition() function is used for defining
+ property assignments that should be performed when a transition is taken.
+ The invokeMethodOnTransition() function is used for defining method
+ invocations that should be performed when a transition is taken.
+
+ \code
+ QStateMachine machine;
+ QState *s1 = new QState();
+ machine.addState(s1);
+ QTransition *t1 = new QTransition();
+ QLabel label;
+ t1->setPropertyOnTransition(&label, "text", "Transition t1 was triggered");
+ QState *s2 = new QState();
+ machine.addState(s2);
+ t1->setTargetState(s2);
+ s1->addTransition(t1);
+ \endcode
+
+ Actions are executed in the order in which they were added.
+
+ \sa QState::addTransition(), QStateAction
+*/
+
+QTransitionPrivate::QTransitionPrivate()
+{
+}
+
+QTransitionPrivate::~QTransitionPrivate()
+{
+}
+
+QTransitionPrivate *QTransitionPrivate::get(QTransition *q)
+{
+ return q->d_func();
+}
+
+const QTransitionPrivate *QTransitionPrivate::get(const QTransition *q)
+{
+ return q->d_func();
+}
+
+QList<QStateAction*> QTransitionPrivate::actions() const
+{
+ QList<QStateAction*> result;
+ QList<QObject*>::const_iterator it;
+#ifdef QT_STATEMACHINE_SOLUTION
+ const QObjectList &children = q_func()->children();
+#endif
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QStateAction *s = qobject_cast<QStateAction*>(*it);
+ if (s)
+ result.append(s);
+ }
+ return result;
+}
+
+/*!
+ Constructs a new QTransition object with the given \a sourceState.
+*/
+QTransition::QTransition(QState *sourceState)
+ : QAbstractTransition(*new QTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new QTransition object with the given \a targets and \a
+ sourceState.
+*/
+QTransition::QTransition(const QList<QAbstractState*> &targets, QState *sourceState)
+ : QAbstractTransition(*new QTransitionPrivate, targets, sourceState)
+{
+}
+
+/*!
+ \internal
+*/
+QTransition::QTransition(QTransitionPrivate &dd, QState *parent)
+ : QAbstractTransition(dd, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QTransition::QTransition(QTransitionPrivate &dd, const QList<QAbstractState*> &targets, QState *parent)
+ : QAbstractTransition(dd, targets, parent)
+{
+}
+
+/*!
+ Destroys this transition.
+*/
+QTransition::~QTransition()
+{
+}
+
+/*!
+ Instructs this QTransition to set the property with the given \a name of the
+ given \a object to the given \a value when the transition is taken. This
+ function will create a QStateSetPropertyAction object and add it to the
+ actions of the transition. If there is already an existing action associated
+ with the property, the value of that action is updated.
+
+ \sa invokeMethodOnTransition()
+*/
+void QTransition::setPropertyOnTransition(QObject *object, const char *name,
+ const QVariant &value)
+{
+ Q_D(QTransition);
+ QList<QStateAction*> actions = d->actions();
+ for (int i = 0; i < actions.size(); ++i) {
+ QStateAction *action = actions.at(i);
+ if (QStateSetPropertyAction *spa = qobject_cast<QStateSetPropertyAction*>(action)) {
+ if (spa->targetObject() == object && spa->propertyName() == name) {
+ QStateSetPropertyActionPrivate::get(spa)->value = value;
+ return;
+ }
+ }
+ }
+ addAction(new QStateSetPropertyAction(object, name, value));
+}
+
+/*!
+ Instructs this QTransition to invoke the given \a method of the given \a
+ object with the given \a arguments when the transition is taken. This
+ function will create a QStateInvokeMethodAction object and add it to the
+ actions of the transition.
+
+ \sa setPropertyOnTransition()
+*/
+void QTransition::invokeMethodOnTransition(QObject *object, const char *method,
+ const QList<QVariant> &arguments)
+{
+ addAction(new QStateInvokeMethodAction(object, method, arguments));
+}
+
+/*!
+ Adds the given \a action to this transition.
+ The action will be executed when the transition is triggered.
+ The transition takes ownership of the action.
+
+ \sa removeAction()
+*/
+void QTransition::addAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QTransition::addAction: cannot add null action");
+ return;
+ }
+ action->setParent(this);
+}
+
+/*!
+ Removes the given \a action from this transition.
+ The transition releases ownership of the action.
+
+ \sa addAction()
+*/
+void QTransition::removeAction(QStateAction *action)
+{
+ if (!action) {
+ qWarning("QTransition::removeAction: cannot remove null action");
+ return;
+ }
+ action->setParent(0);
+}
+
+/*!
+ Returns this transitions's actions, or an empty list if the transition has
+ no actions.
+
+ \sa addAction()
+*/
+QList<QStateAction*> QTransition::actions() const
+{
+ Q_D(const QTransition);
+ return d->actions();
+}
+
+/*!
+ \reimp
+*/
+void QTransition::onTransition()
+{
+ Q_D(QTransition);
+ QList<QStateAction*> actions = d->actions();
+ for (int i = 0; i < actions.size(); ++i)
+ QStateActionPrivate::get(actions.at(i))->callExecute();
+}
+
+/*!
+ \reimp
+*/
+bool QTransition::event(QEvent *e)
+{
+ return QAbstractTransition::event(e);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qtransition.h b/src/corelib/statemachine/qtransition.h
new file mode 100644
index 0000000..57d9718
--- /dev/null
+++ b/src/corelib/statemachine/qtransition.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTRANSITION_H
+#define QTRANSITION_H
+
+#ifndef QT_STATEMACHINE_SOLUTION
+#include <QtCore/qabstracttransition.h>
+#else
+#include "qabstracttransition.h"
+#endif
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QStateAction;
+
+class QTransitionPrivate;
+class Q_CORE_EXPORT QTransition : public QAbstractTransition
+{
+ Q_OBJECT
+public:
+ QTransition(QState *sourceState = 0);
+ QTransition(const QList<QAbstractState*> &targets, QState *sourceState = 0);
+ ~QTransition();
+
+ void setPropertyOnTransition(QObject *object, const char *name,
+ const QVariant &value);
+ void invokeMethodOnTransition(QObject *object, const char *method,
+ const QList<QVariant> &args = QList<QVariant>());
+
+ void addAction(QStateAction *action);
+ void removeAction(QStateAction *action);
+ QList<QStateAction*> actions() const;
+
+protected:
+ virtual void onTransition();
+
+ bool event(QEvent *e);
+
+protected:
+ QTransition(QTransitionPrivate &dd, QState *parent);
+ QTransition(QTransitionPrivate &dd, const QList<QAbstractState*> &targets, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QTransition)
+ Q_DECLARE_PRIVATE(QTransition)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/statemachine/qtransition_p.h b/src/corelib/statemachine/qtransition_p.h
new file mode 100644
index 0000000..e5da6de
--- /dev/null
+++ b/src/corelib/statemachine/qtransition_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTRANSITION_P_H
+#define QTRANSITION_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 "qabstracttransition_p.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStateAction;
+
+class QTransition;
+class Q_CORE_EXPORT QTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QTransition)
+public:
+ QTransitionPrivate();
+ ~QTransitionPrivate();
+
+ static QTransitionPrivate *get(QTransition *q);
+ static const QTransitionPrivate *get(const QTransition *q);
+
+ QList<QStateAction*> actions() const;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/statemachine/statemachine.pri b/src/corelib/statemachine/statemachine.pri
new file mode 100644
index 0000000..8409b4d
--- /dev/null
+++ b/src/corelib/statemachine/statemachine.pri
@@ -0,0 +1,47 @@
+HEADERS += $$PWD/qstatemachine.h \
+ $$PWD/qstatemachine_p.h \
+ $$PWD/qstateaction.h \
+ $$PWD/qstateaction_p.h \
+ $$PWD/qsignaleventgenerator_p.h \
+ $$PWD/qabstractstate.h \
+ $$PWD/qabstractstate_p.h \
+ $$PWD/qactionstate.h \
+ $$PWD/qactionstate_p.h \
+ $$PWD/qstate.h \
+ $$PWD/qstate_p.h \
+ $$PWD/qfinalstate.h \
+ $$PWD/qhistorystate.h \
+ $$PWD/qhistorystate_p.h \
+ $$PWD/qabstracttransition.h \
+ $$PWD/qabstracttransition_p.h \
+ $$PWD/qtransition.h \
+ $$PWD/qtransition_p.h \
+ $$PWD/qstatefinishedevent.h \
+ $$PWD/qstatefinishedtransition.h \
+ $$PWD/qsignalevent.h \
+ $$PWD/qsignaltransition.h \
+ $$PWD/qsignaltransition_p.h
+
+SOURCES += $$PWD/qstatemachine.cpp \
+ $$PWD/qstateaction.cpp \
+ $$PWD/qabstractstate.cpp \
+ $$PWD/qactionstate.cpp \
+ $$PWD/qstate.cpp \
+ $$PWD/qfinalstate.cpp \
+ $$PWD/qhistorystate.cpp \
+ $$PWD/qabstracttransition.cpp \
+ $$PWD/qtransition.cpp \
+ $$PWD/qstatefinishedtransition.cpp \
+ $$PWD/qsignaltransition.cpp
+
+!contains(DEFINES, QT_NO_STATEMACHINE_EVENTFILTER) {
+HEADERS += $$PWD/qboundevent_p.h \
+ $$PWD/qeventtransition.h \
+ $$PWD/qeventtransition_p.h
+SOURCES += $$PWD/qeventtransition.cpp
+}
+
+!contains(DEFINES, QT_NO_ANIMATION) {
+HEADERS += $$PWD/qanimationstate.h
+SOURCES += $$PWD/qanimationstate.cpp
+}
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
new file mode 100644
index 0000000..a1a0d1f
--- /dev/null
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -0,0 +1,844 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+
+| *property* | *Used for type* |
+| period | QEasingCurve::{In,Out,InOut,OutIn}Elastic |
+| amplitude | QEasingCurve::{In,Out,InOut,OutIn}Bounce, QEasingCurve::{In,Out,InOut,OutIn}Elastic |
+| overshoot | QEasingCurve::{In,Out,InOut,OutIn}Back |
+
+*/
+
+
+
+
+/*!
+ \class QEasingCurve
+ \ingroup animation
+ \brief The QEasingCurve class provides easing curves for controlling animation.
+
+ Easing curves describe a function that controls how the speed of the interpolation
+ between 0 and 1 should be. Easing curves allow transitions from
+ one value to another to appear more natural than a simple constant speed would allow.
+ The QEasingCurve class is usually used in conjunction with the QAnimation class,
+ but can be used on its own.
+
+ To calculate the speed of the interpolation, the easing curve provides the function
+ valueForProgress(), where the \a progress argument specifies the progress of the
+ interpolation: 0 is the start value of the interpolation, 1 is the end value of the
+ interpolation. The returned value is the effective progress of the interpolation.
+ If the returned value is the same as the input value for all input values the easing
+ curve is a linear curve. This is the default behaviour.
+
+ For example,
+ \code
+ QEasingCurve easing(QEasingCurve::InOutQuad);
+
+ for(qreal t = 0.0; t < 1.0; t+=0.1)
+ qWarning() << "Effective progress" << t << " is
+ << easing.valueForProgress(t);
+ \endcode
+ will print the effective progress of the interpolation between 0 and 1.
+
+ When using a QAnimation, the easing curve will be used to control the
+ progress of the interpolation between startValue and endValue:
+ \code
+ QAnimation animation;
+ animation.setStartValue(0);
+ animation.setEndValue(1000);
+ animation.setDuration(1000);
+ animation.setEasingCurve(QEasingCurve::InOutQuad);
+ \endcode
+ */
+
+/*!
+ \enum QEasingCurve::Type
+
+ The type of easing curve.
+
+ \value Linear \inlineimage qeasingcurve-linear.png
+ \br
+ Easing equation function for a simple linear tweening,
+ with no easing.
+ \value InQuad \inlineimage qeasingcurve-inquad.png
+ \br
+ Easing equation function for a quadratic (t^2) easing
+ in: accelerating from zero velocity.
+ \value OutQuad \inlineimage qeasingcurve-outquad.png
+ \br
+ Easing equation function for a quadratic (t^2) easing
+ out: decelerating to zero velocity.
+ \value InOutQuad \inlineimage qeasingcurve-inoutquad.png
+ \br
+ Easing equation function for a quadratic (t^2) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInQuad \inlineimage qeasingcurve-outinquad.png
+ \br
+ Easing equation function for a quadratic (t^2) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InCubic \inlineimage qeasingcurve-incubic.png
+ \br
+ Easing equation function for a cubic (t^3) easing
+ in: accelerating from zero velocity.
+ \value OutCubic \inlineimage qeasingcurve-outcubic.png
+ \br
+ Easing equation function for a cubic (t^3) easing
+ out: decelerating from zero velocity.
+ \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png
+ \br
+ Easing equation function for a cubic (t^3) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInCubic \inlineimage qeasingcurve-outincubic.png
+ \br
+ Easing equation function for a cubic (t^3) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InQuart \inlineimage qeasingcurve-inquart.png
+ \br
+ Easing equation function for a quartic (t^4) easing
+ in: accelerating from zero velocity.
+ \value OutQuart \inlineimage qeasingcurve-outquart.png
+ \br
+ Easing equation function for a quartic (t^4) easing
+ out: decelerating from zero velocity.
+ \value InOutQuart \inlineimage qeasingcurve-inoutquart.png
+ \br
+ Easing equation function for a quartic (t^4) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInQuart \inlineimage qeasingcurve-outinquart.png
+ \br
+ Easing equation function for a quartic (t^4) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InQuint \inlineimage qeasingcurve-inquint.png
+ \br
+ Easing equation function for a quintic (t^5) easing
+ in: accelerating from zero velocity.
+ \value OutQuint \inlineimage qeasingcurve-outquint.png
+ \br
+ Easing equation function for a quintic (t^5) easing
+ out: decelerating from zero velocity.
+ \value InOutQuint \inlineimage qeasingcurve-inoutquint.png
+ \br
+ Easing equation function for a quintic (t^5) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInQuint \inlineimage qeasingcurve-outinquint.png
+ \br
+ Easing equation function for a quintic (t^5) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InSine \inlineimage qeasingcurve-insine.png
+ \br
+ Easing equation function for a sinusoidal (sin(t)) easing
+ in: accelerating from zero velocity.
+ \value OutSine \inlineimage qeasingcurve-outsine.png
+ \br
+ Easing equation function for a sinusoidal (sin(t)) easing
+ out: decelerating from zero velocity.
+ \value InOutSine \inlineimage qeasingcurve-inoutsine.png
+ \br
+ Easing equation function for a sinusoidal (sin(t)) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInSine \inlineimage qeasingcurve-outinsine.png
+ \br
+ Easing equation function for a sinusoidal (sin(t)) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InExpo \inlineimage qeasingcurve-inexpo.png
+ \br
+ Easing equation function for an exponential (2^t) easing
+ in: accelerating from zero velocity.
+ \value OutExpo \inlineimage qeasingcurve-outexpo.png
+ \br
+ Easing equation function for an exponential (2^t) easing
+ out: decelerating from zero velocity.
+ \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png
+ \br
+ Easing equation function for an exponential (2^t) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInExpo \inlineimage qeasingcurve-outinexpo.png
+ \br
+ Easing equation function for an exponential (2^t) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InCirc \inlineimage qeasingcurve-incirc.png
+ \br
+ Easing equation function for a circular (sqrt(1-t^2)) easing
+ in: accelerating from zero velocity.
+ \value OutCirc \inlineimage qeasingcurve-outcirc.png
+ \br
+ Easing equation function for a circular (sqrt(1-t^2)) easing
+ out: decelerating from zero velocity.
+ \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png
+ \br
+ Easing equation function for a circular (sqrt(1-t^2)) easing
+ in/out: acceleration until halfway, then deceleration.
+ \value OutInCirc \inlineimage qeasingcurve-outincirc.png
+ \br
+ Easing equation function for a circular (sqrt(1-t^2)) easing
+ out/in: deceleration until halfway, then acceleration.
+ \value InElastic \inlineimage qeasingcurve-inelastic.png
+ \br
+ Easing equation function for an elastic
+ (exponentially decaying sine wave) easing in:
+ accelerating from zero velocity. The peak amplitude
+ can be set with the \e amplitude parameter, and the
+ period of decay by the \e period parameter.
+ \value OutElastic \inlineimage qeasingcurve-outelastic.png
+ \br
+ Easing equation function for an elastic
+ (exponentially decaying sine wave) easing out:
+ decelerating from zero velocity. The peak amplitude
+ can be set with the \e amplitude parameter, and the
+ period of decay by the \e period parameter.
+ \value InOutElastic \inlineimage qeasingcurve-inoutelastic.png
+ \br
+ Easing equation function for an elastic
+ (exponentially decaying sine wave) easing in/out:
+ acceleration until halfway, then deceleration.
+ \value OutInElastic \inlineimage qeasingcurve-outinelastic.png
+ \br
+ Easing equation function for an elastic
+ (exponentially decaying sine wave) easing out/in:
+ deceleration until halfway, then acceleration.
+ \value InBack \inlineimage qeasingcurve-inback.png
+ \br
+ Easing equation function for a back (overshooting
+ cubic easing: (s+1)*t^3 - s*t^2) easing in:
+ accelerating from zero velocity.
+ \value OutBack \inlineimage qeasingcurve-outback.png
+ \br
+ Easing equation function for a back (overshooting
+ cubic easing: (s+1)*t^3 - s*t^2) easing out:
+ decelerating from zero velocity.
+ \value InOutBack \inlineimage qeasingcurve-inoutback.png
+ \br
+ Easing equation function for a back (overshooting
+ cubic easing: (s+1)*t^3 - s*t^2) easing in/out:
+ acceleration until halfway, then deceleration.
+ \value OutInBack \inlineimage qeasingcurve-outinback.png
+ \br
+ Easing equation function for a back (overshooting
+ cubic easing: (s+1)*t^3 - s*t^2) easing out/in:
+ deceleration until halfway, then acceleration.
+ \value InBounce \inlineimage qeasingcurve-inbounce.png
+ \br
+ Easing equation function for a bounce (exponentially
+ decaying parabolic bounce) easing in: accelerating
+ from zero velocity.
+ \value OutBounce \inlineimage qeasingcurve-outbounce.png
+ \br
+ Easing equation function for a bounce (exponentially
+ decaying parabolic bounce) easing out: decelerating
+ from zero velocity.
+ \value InOutBounce \inlineimage qeasingcurve-inoutbounce.png
+ \br
+ Easing equation function for a bounce (exponentially
+ decaying parabolic bounce) easing in/out:
+ acceleration until halfway, then deceleration.
+ \value OutInBounce \inlineimage qeasingcurve-outinbounce.png
+ \br
+ Easing equation function for a bounce (exponentially
+ decaying parabolic bounce) easing out/in:
+ deceleration until halfway, then acceleration.
+ \omitvalue InCurve
+ \omitvalue OutCurve
+ \omitvalue SineCurve
+ \omitvalue CosineCurve
+ \value Custom This is returned if the user have specified a custom curve type with setCustomType(). Note that you cannot call setType() with this value, but type() can return it.
+ \omitvalue NCurveTypes
+*/
+
+/*!
+ \typedef QEasingCurve::EasingFunction
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_corelib_tools_qeasingcurve.cpp 0
+
+*/
+
+#include "qeasingcurve.h"
+
+QT_BEGIN_NAMESPACE
+
+static bool isConfigFunction(QEasingCurve::Type type)
+{
+ return type >= QEasingCurve::InElastic
+ && type <= QEasingCurve::OutInBounce;
+}
+
+class QEasingCurveFunction
+{
+public:
+ enum Type { In, Out, InOut, OutIn };
+
+ QEasingCurveFunction(QEasingCurveFunction::Type type = In, qreal period = 0.3, qreal amplitude = 1.0,
+ qreal overshoot = 1.70158f)
+ : _t(type), _p(period), _a(amplitude), _o(overshoot)
+ { }
+ virtual ~QEasingCurveFunction() {}
+ virtual qreal value(qreal t);
+ virtual QEasingCurveFunction *copy() const;
+ bool operator==(const QEasingCurveFunction& other);
+
+ Type _t;
+ qreal _p;
+ qreal _a;
+ qreal _o;
+};
+
+qreal QEasingCurveFunction::value(qreal t)
+{
+ return t;
+}
+
+QEasingCurveFunction *QEasingCurveFunction::copy() const
+{
+ return new QEasingCurveFunction(_t, _p, _a, _o);
+}
+
+bool QEasingCurveFunction::operator==(const QEasingCurveFunction& other)
+{
+ return _t == other._t &&
+ _p == other._p &&
+ _a == other._a &&
+ _o == other._o;
+}
+
+#ifdef QT_EXPERIMENTAL_SOLUTION
+# include "easing.cpp"
+#else
+# include "../3rdparty/easing/easing.cpp"
+#endif
+
+class QEasingCurvePrivate
+{
+public:
+ QEasingCurvePrivate()
+ : type(QEasingCurve::Linear),
+ config(0),
+ func(&easeNone)
+ { }
+ void setType_helper(QEasingCurve::Type);
+
+ QEasingCurve::Type type;
+ QEasingCurveFunction *config;
+ QEasingCurve::EasingFunction func;
+};
+
+struct ElasticEase : public QEasingCurveFunction
+{
+ ElasticEase(Type type)
+ : QEasingCurveFunction(type, qreal(0.3), qreal(1.0))
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ ElasticEase *rv = new ElasticEase(_t);
+ rv->_p = _p;
+ rv->_a = _a;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal p = (_p < 0) ? 0.3f : _p;
+ qreal a = (_a < 0) ? 1.0f : _a;
+ switch(_t) {
+ case In:
+ return easeInElastic(t, a, p);
+ case Out:
+ return easeOutElastic(t, a, p);
+ case InOut:
+ return easeInOutElastic(t, a, p);
+ case OutIn:
+ return easeOutInElastic(t, a, p);
+ default:
+ return t;
+ }
+ }
+};
+
+struct BounceEase : public QEasingCurveFunction
+{
+ BounceEase(Type type)
+ : QEasingCurveFunction(type, 0.3f, 1.0f)
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ BounceEase *rv = new BounceEase(_t);
+ rv->_a = _a;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal a = (_a < 0) ? 1.0f : _a;
+ switch(_t) {
+ case In:
+ return easeInBounce(t, a);
+ case Out:
+ return easeOutBounce(t, a);
+ case InOut:
+ return easeInOutBounce(t, a);
+ case OutIn:
+ return easeOutInBounce(t, a);
+ default:
+ return t;
+ }
+ }
+};
+
+struct BackEase : public QEasingCurveFunction
+{
+ BackEase(Type type)
+ : QEasingCurveFunction(type, 0.3f, 1.0f, 1.70158f)
+ { }
+
+ QEasingCurveFunction *copy() const
+ {
+ BackEase *rv = new BackEase(_t);
+ rv->_o = _o;
+ return rv;
+ }
+
+ qreal value(qreal t)
+ {
+ qreal o = (_o < 0) ? 1.70158f : _o;
+ switch(_t) {
+ case In:
+ return easeInBack(t, o);
+ case Out:
+ return easeOutBack(t, o);
+ case InOut:
+ return easeInOutBack(t, o);
+ case OutIn:
+ return easeOutInBack(t, o);
+ default:
+ return t;
+ }
+ }
+};
+
+static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve)
+{
+ switch(curve) {
+ case QEasingCurve::Linear:
+ return &easeNone;
+ case QEasingCurve::InQuad:
+ return &easeInQuad;
+ case QEasingCurve::OutQuad:
+ return &easeOutQuad;
+ case QEasingCurve::InOutQuad:
+ return &easeInOutQuad;
+ case QEasingCurve::OutInQuad:
+ return &easeOutInQuad;
+ case QEasingCurve::InCubic:
+ return &easeInCubic;
+ case QEasingCurve::OutCubic:
+ return &easeOutCubic;
+ case QEasingCurve::InOutCubic:
+ return &easeInOutCubic;
+ case QEasingCurve::OutInCubic:
+ return &easeOutInCubic;
+ case QEasingCurve::InQuart:
+ return &easeInQuart;
+ case QEasingCurve::OutQuart:
+ return &easeOutQuart;
+ case QEasingCurve::InOutQuart:
+ return &easeInOutQuart;
+ case QEasingCurve::OutInQuart:
+ return &easeOutInQuart;
+ case QEasingCurve::InQuint:
+ return &easeInQuint;
+ case QEasingCurve::OutQuint:
+ return &easeOutQuint;
+ case QEasingCurve::InOutQuint:
+ return &easeInOutQuint;
+ case QEasingCurve::OutInQuint:
+ return &easeOutInQuint;
+ case QEasingCurve::InSine:
+ return &easeInSine;
+ case QEasingCurve::OutSine:
+ return &easeOutSine;
+ case QEasingCurve::InOutSine:
+ return &easeInOutSine;
+ case QEasingCurve::OutInSine:
+ return &easeOutInSine;
+ case QEasingCurve::InExpo:
+ return &easeInExpo;
+ case QEasingCurve::OutExpo:
+ return &easeOutExpo;
+ case QEasingCurve::InOutExpo:
+ return &easeInOutExpo;
+ case QEasingCurve::OutInExpo:
+ return &easeOutInExpo;
+ case QEasingCurve::InCirc:
+ return &easeInCirc;
+ case QEasingCurve::OutCirc:
+ return &easeOutCirc;
+ case QEasingCurve::InOutCirc:
+ return &easeInOutCirc;
+ case QEasingCurve::OutInCirc:
+ return &easeOutInCirc;
+ // Internal for, compatibility with QTimeLine only ??
+ case QEasingCurve::InCurve:
+ return &easeInCurve;
+ case QEasingCurve::OutCurve:
+ return &easeOutCurve;
+ case QEasingCurve::SineCurve:
+ return &easeSineCurve;
+ case QEasingCurve::CosineCurve:
+ return &easeCosineCurve;
+ default:
+ return 0;
+ };
+}
+
+static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type)
+{
+ QEasingCurveFunction *curveFunc = 0;
+ switch(type) {
+ case QEasingCurve::InElastic:
+ curveFunc = new ElasticEase(ElasticEase::In);
+ break;
+ case QEasingCurve::OutElastic:
+ curveFunc = new ElasticEase(ElasticEase::Out);
+ break;
+ case QEasingCurve::InOutElastic:
+ curveFunc = new ElasticEase(ElasticEase::InOut);
+ break;
+ case QEasingCurve::OutInElastic:
+ curveFunc = new ElasticEase(ElasticEase::OutIn);
+ break;
+ case QEasingCurve::OutBounce:
+ curveFunc = new BounceEase(BounceEase::Out);
+ break;
+ case QEasingCurve::InBounce:
+ curveFunc = new BounceEase(BounceEase::In);
+ break;
+ case QEasingCurve::OutInBounce:
+ curveFunc = new BounceEase(BounceEase::OutIn);
+ break;
+ case QEasingCurve::InOutBounce:
+ curveFunc = new BounceEase(BounceEase::InOut);
+ break;
+ case QEasingCurve::InBack:
+ curveFunc = new BackEase(BackEase::In);
+ break;
+ case QEasingCurve::OutBack:
+ curveFunc = new BackEase(BackEase::Out);
+ break;
+ case QEasingCurve::InOutBack:
+ curveFunc = new BackEase(BackEase::InOut);
+ break;
+ case QEasingCurve::OutInBack:
+ curveFunc = new BackEase(BackEase::OutIn);
+ break;
+ default:
+ curveFunc = new QEasingCurveFunction(QEasingCurveFunction::In, 0.3f, 1.0f, 1.70158f); // ###
+ }
+
+ return curveFunc;
+}
+
+/*!
+ Constructs an easing curve of the given \a type.
+ */
+QEasingCurve::QEasingCurve(Type type)
+ : d_ptr(new QEasingCurvePrivate)
+{
+ setType(type);
+}
+
+/*!
+ Construct a copy of \a other.
+ */
+QEasingCurve::QEasingCurve(const QEasingCurve &other)
+: d_ptr(new QEasingCurvePrivate)
+{
+ // ### non-atomic, requires malloc on shallow copy
+ *d_ptr = *other.d_ptr;
+ if(other.d_ptr->config)
+ d_ptr->config = other.d_ptr->config->copy();
+}
+
+/*!
+ Destructor.
+ */
+
+QEasingCurve::~QEasingCurve()
+{
+ delete d_ptr;
+}
+
+/*!
+ Copy \a other.
+ */
+QEasingCurve &QEasingCurve::operator=(const QEasingCurve &other)
+{
+ // ### non-atomic, requires malloc on shallow copy
+ if (d_ptr->config) {
+ delete d_ptr->config;
+ d_ptr->config = 0;
+ }
+
+ *d_ptr = *other.d_ptr;
+ if(other.d_ptr->config)
+ d_ptr->config = other.d_ptr->config->copy();
+
+ return *this;
+}
+
+/*!
+ Compare this easing curve with \a other and returns true if they are
+ equal. It will also compare the properties of a curve.
+ */
+bool QEasingCurve::operator==(const QEasingCurve &other) const
+{
+ bool res = d_ptr->func == other.d_ptr->func
+ && d_ptr->type == other.d_ptr->type;
+ if (res && d_ptr->config && other.d_ptr->config) {
+ // catch the config content
+ res = d_ptr->config->operator==(*(other.d_ptr->config));
+ }
+ return res;
+}
+
+/*!
+ \fn bool QEasingCurve::operator!=(const QEasingCurve &other) const
+ Compare this easing curve with \a other and returns true if they are not equal.
+ It will also compare the properties of a curve.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns the amplitude. This is not applicable for all curve types.
+ It is only applicable for bounce and elastic curves (curves of type()
+ QEasingCurve::InBounce, QEasingCurve::OutBounce, QEasingCurve::InOutBounce,
+ QEasingCurve::OutInBounce, QEasingCurve::InElastic, QEasingCurve::OutElastic,
+ QEasingCurve::InOutElastic or QEasingCurve::OutInElastic).
+ */
+qreal QEasingCurve::amplitude() const
+{
+ return d_ptr->config ? d_ptr->config->_a : 1.0;
+}
+
+/*!
+ Sets the amplitude to \a amplitude.
+
+ This will set the amplitude of the bounce or the amplitude of the
+ elastic "spring" effect. The higher the number, the higher the amplitude.
+ \sa amplitude()
+*/
+void QEasingCurve::setAmplitude(qreal amplitude)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_a = amplitude;
+}
+
+/*!
+ Returns the period. This is not applicable for all curve types.
+ It is only applicable if type() is QEasingCurve::InElastic, QEasingCurve::OutElastic,
+ QEasingCurve::InOutElastic or QEasingCurve::OutInElastic.
+ */
+qreal QEasingCurve::period() const
+{
+ return d_ptr->config ? d_ptr->config->_p : 0.3;
+}
+
+/*!
+ Sets the period to \a period.
+ Setting a small period value will give a high frequency of the curve. A
+ large period will give it a small frequency.
+
+ \sa period()
+*/
+void QEasingCurve::setPeriod(qreal period)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_p = period;
+}
+
+/*!
+ Returns the overshoot. This is not applicable for all curve types.
+ It is only applicable if type() is QEasingCurve::InBack, QEasingCurve::OutBack,
+ QEasingCurve::InOutBack or QEasingCurve::OutInBack.
+ */
+qreal QEasingCurve::overshoot() const
+{
+ return d_ptr->config ? d_ptr->config->_o : 1.70158f;
+}
+
+/*!
+ Sets the overshoot to \a overshoot.
+
+ 0 produces no overshoot, and the default value of 1.70158 produces an overshoot of 10 percent.
+
+ \sa overshoot()
+*/
+void QEasingCurve::setOvershoot(qreal overshoot)
+{
+ if (!d_ptr->config)
+ d_ptr->config = curveToFunctionObject(d_ptr->type);
+ d_ptr->config->_o = overshoot;
+}
+
+/*!
+ Returns the type of the easing curve.
+*/
+QEasingCurve::Type QEasingCurve::type() const
+{
+ return d_ptr->type;
+}
+
+void QEasingCurvePrivate::setType_helper(QEasingCurve::Type newType)
+{
+ qreal amp = -1.0;
+ qreal period = -1.0;
+ qreal overshoot = -1.0;
+
+ if (config) {
+ amp = config->_a;
+ period = config->_p;
+ overshoot = config->_o;
+ delete config;
+ config = 0;
+ }
+
+ if (isConfigFunction(newType) || (amp != -1.0) || (period != -1.0) || (overshoot != -1.0)) {
+ config = curveToFunctionObject(newType);
+ if (amp != -1.0)
+ config->_a = amp;
+ if (period != -1.0)
+ config->_p = period;
+ if (overshoot != -1.0)
+ config->_o = overshoot;
+ func = 0;
+ } else if (newType != QEasingCurve::Custom) {
+ func = curveToFunc(newType);
+ }
+ Q_ASSERT((func == 0) == (config != 0));
+ type = newType;
+}
+
+/*!
+ Sets the type of the easing curve to \a type.
+*/
+void QEasingCurve::setType(Type type)
+{
+ if (d_ptr->type == type)
+ return;
+ if (type < Linear || type >= NCurveTypes - 1) {
+ qWarning("QEasingCurve: Invalid curve type %d", type);
+ return;
+ }
+
+ d_ptr->setType_helper(type);
+}
+
+/*!
+ Sets a custom easing curve that is defined by the user in the function \a func.
+ The signature of the function is qreal myEasingFunction(qreal progress),
+ where \e progress and the return value is considered to be normalized between 0 and 1.
+ (In some cases the return value can be outside that range)
+ After calling this function type() will return QEasingCurve::Custom.
+ \a func cannot be zero.
+
+ \sa customType()
+ \sa valueForProgress()
+*/
+void QEasingCurve::setCustomType(EasingFunction func)
+{
+ if (!func) {
+ qWarning("Function pointer must not be null");
+ return;
+ }
+ d_ptr->func = func;
+ d_ptr->setType_helper(Custom);
+}
+
+/*!
+ Returns the function pointer to the custom easing curve.
+ If type() does not return QEasingCurve::Custom, this function
+ will return 0.
+*/
+QEasingCurve::EasingFunction QEasingCurve::customType() const
+{
+ return d_ptr->type == Custom ? d_ptr->func : 0;
+}
+
+/*!
+ Return the effective progress for the easing curve at \a progress.
+ While \a progress must be between 0 and 1, the returned effective progress
+ can be outside those bounds. For instance, QEasingCurve::InBack will
+ return negative values in the beginning of the function.
+ */
+qreal QEasingCurve::valueForProgress(qreal progress) const
+{
+ progress = qBound<qreal>(0, progress, 1);
+ if (d_ptr->func)
+ return d_ptr->func(progress);
+ else if (d_ptr->config)
+ return d_ptr->config->value(progress);
+ else
+ return progress;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#include <QtCore/QString>
+QDebug operator<<(QDebug debug, const QEasingCurve &item)
+{
+ debug << "type:" << item.d_ptr->type
+ << "func:" << item.d_ptr->func;
+ if (item.d_ptr->config) {
+ debug << QString::fromAscii("period:%1").arg(item.d_ptr->config->_p, 0, 'f', 20)
+ << QString::fromAscii("amp:%1").arg(item.d_ptr->config->_a, 0, 'f', 20)
+ << QString::fromAscii("overshoot:%1").arg(item.d_ptr->config->_o, 0, 'f', 20);
+ }
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
new file mode 100644
index 0000000..a240bc0
--- /dev/null
+++ b/src/corelib/tools/qeasingcurve.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEASINGCURVE_H
+#define QEASINGCURVE_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobjectdefs.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QEasingCurvePrivate;
+class Q_CORE_EXPORT QEasingCurve
+{
+ Q_GADGET
+ Q_ENUMS(Type)
+public:
+ enum Type {
+ Linear,
+ InQuad, OutQuad, InOutQuad, OutInQuad,
+ InCubic, OutCubic, InOutCubic, OutInCubic,
+ InQuart, OutQuart, InOutQuart, OutInQuart,
+ InQuint, OutQuint, InOutQuint, OutInQuint,
+ InSine, OutSine, InOutSine, OutInSine,
+ InExpo, OutExpo, InOutExpo, OutInExpo,
+ InCirc, OutCirc, InOutCirc, OutInCirc,
+ InElastic, OutElastic, InOutElastic, OutInElastic,
+ InBack, OutBack, InOutBack, OutInBack,
+ InBounce, OutBounce, InOutBounce, OutInBounce,
+ InCurve, OutCurve, SineCurve, CosineCurve,
+ Custom, NCurveTypes
+ };
+
+ QEasingCurve(Type type = Linear);
+ QEasingCurve(const QEasingCurve &other);
+ ~QEasingCurve();
+
+ QEasingCurve &operator=(const QEasingCurve &other);
+ bool operator==(const QEasingCurve &other) const;
+ inline bool operator!=(const QEasingCurve &other) const
+ { return !(this->operator==(other)); }
+
+ qreal amplitude() const;
+ void setAmplitude(qreal amplitude);
+
+ qreal period() const;
+ void setPeriod(qreal period);
+
+ qreal overshoot() const;
+ void setOvershoot(qreal overshoot);
+
+ Type type() const;
+ void setType(Type type);
+ typedef qreal (*EasingFunction)(qreal progress);
+ void setCustomType(EasingFunction func);
+ EasingFunction customType() const;
+
+ qreal valueForProgress(qreal progress) const;
+private:
+ QEasingCurvePrivate *d_ptr;
+ friend Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp
index 2979a09..78ce7bd 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -48,20 +48,6 @@
QT_BEGIN_NAMESPACE
-static const qreal pi = qreal(3.14159265359);
-static const qreal halfPi = pi / qreal(2.0);
-
-
-static inline qreal qt_sinProgress(qreal value)
-{
- return qSin((value * pi) - halfPi) / 2 + qreal(0.5);
-}
-
-static inline qreal qt_smoothBeginEndMixFactor(qreal value)
-{
- return qMin(qMax(1 - value * 2 + qreal(0.3), qreal(0.0)), qreal(1.0));
-}
-
class QTimeLinePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QTimeLine)
@@ -70,7 +56,7 @@ public:
: startTime(0), duration(1000), startFrame(0), endFrame(0),
updateInterval(1000 / 25),
totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
- direction(QTimeLine::Forward), curveShape(QTimeLine::EaseInOutCurve),
+ direction(QTimeLine::Forward), easingCurve(QEasingCurve::InOutSine),
state(QTimeLine::NotRunning)
{ }
@@ -88,7 +74,7 @@ public:
QTime timer;
QTimeLine::Direction direction;
- QTimeLine::CurveShape curveShape;
+ QEasingCurve easingCurve;
QTimeLine::State state;
inline void setState(QTimeLine::State newState)
{
@@ -521,12 +507,68 @@ void QTimeLine::setUpdateInterval(int interval)
QTimeLine::CurveShape QTimeLine::curveShape() const
{
Q_D(const QTimeLine);
- return d->curveShape;
+ switch (d->easingCurve.type()) {
+ default:
+ case QEasingCurve::InOutSine:
+ return EaseInOutCurve;
+ case QEasingCurve::InCurve:
+ return EaseInCurve;
+ case QEasingCurve::OutCurve:
+ return EaseOutCurve;
+ case QEasingCurve::Linear:
+ return LinearCurve;
+ case QEasingCurve::SineCurve:
+ return SineCurve;
+ case QEasingCurve::CosineCurve:
+ return CosineCurve;
+ }
+ return EaseInOutCurve;
}
+
void QTimeLine::setCurveShape(CurveShape shape)
{
+ switch (shape) {
+ default:
+ case EaseInOutCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::InOutSine));
+ break;
+ case EaseInCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::InCurve));
+ break;
+ case EaseOutCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::OutCurve));
+ break;
+ case LinearCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::Linear));
+ break;
+ case SineCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::SineCurve));
+ break;
+ case CosineCurve:
+ setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve));
+ break;
+ }
+}
+
+/*!
+ \property QTimeLine::easingCurve
+
+ Specifies the easing curve that the timeline will use.
+ If both easing curve and curveShape are set, the last set property will
+ override the previous one. (If valueForTime() is reimplemented it will
+ override both)
+*/
+
+QEasingCurve QTimeLine::easingCurve() const
+{
+ Q_D(const QTimeLine);
+ return d->easingCurve;
+}
+
+void QTimeLine::setEasingCurve(const QEasingCurve& curve)
+{
Q_D(QTimeLine);
- d->curveShape = shape;
+ d->easingCurve = curve;
}
/*!
@@ -606,42 +648,8 @@ qreal QTimeLine::valueForTime(int msec) const
Q_D(const QTimeLine);
msec = qMin(qMax(msec, 0), d->duration);
- // Simple linear interpolation
qreal value = msec / qreal(d->duration);
-
- switch (d->curveShape) {
- case EaseInOutCurve:
- value = qt_sinProgress(value);
- break;
- // SmoothBegin blends Smooth and Linear Interpolation.
- // Progress 0 - 0.3 : Smooth only
- // Progress 0.3 - ~ 0.5 : Mix of Smooth and Linear
- // Progress ~ 0.5 - 1 : Linear only
- case EaseInCurve: {
- const qreal sinProgress = qt_sinProgress(value);
- const qreal linearProgress = value;
- const qreal mix = qt_smoothBeginEndMixFactor(value);
- value = sinProgress * mix + linearProgress * (1 - mix);
- break;
- }
- case EaseOutCurve: {
- const qreal sinProgress = qt_sinProgress(value);
- const qreal linearProgress = value;
- const qreal mix = qt_smoothBeginEndMixFactor(1 - value);
- value = sinProgress * mix + linearProgress * (1 - mix);
- break;
- }
- case SineCurve:
- value = (qSin(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2;
- break;
- case CosineCurve:
- value = (qCos(((msec * pi * 2) / d->duration) - pi/2) + 1) / 2;
- break;
- default:
- break;
- }
-
- return value;
+ return d->easingCurve.valueForProgress(value);
}
/*!
diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h
index 18c3980..314dd7c 100644
--- a/src/corelib/tools/qtimeline.h
+++ b/src/corelib/tools/qtimeline.h
@@ -42,8 +42,11 @@
#ifndef QTIMELINE_H
#define QTIMELINE_H
+#include <QtCore/qeasingcurve.h>
#include <QtCore/qobject.h>
+QT_EXPERIMENTAL_USE_NAMESPACE
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -60,6 +63,7 @@ class Q_CORE_EXPORT QTimeLine : public QObject
Q_PROPERTY(Direction direction READ direction WRITE setDirection)
Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount)
Q_PROPERTY(CurveShape curveShape READ curveShape WRITE setCurveShape)
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve)
public:
enum State {
NotRunning,
@@ -105,6 +109,9 @@ public:
CurveShape curveShape() const;
void setCurveShape(CurveShape shape);
+ QEasingCurve easingCurve() const;
+ void setEasingCurve(const QEasingCurve &curve);
+
int currentTime() const;
int currentFrame() const;
qreal currentValue() const;
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index e5bf7e4..41557f0 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -11,6 +11,7 @@ HEADERS += \
tools/qcryptographichash.h \
tools/qdatetime.h \
tools/qdatetime_p.h \
+ tools/qeasingcurve.h \
tools/qhash.h \
tools/qline.h \
tools/qlinkedlist.h \
@@ -46,6 +47,7 @@ SOURCES += \
tools/qcryptographichash.cpp \
tools/qdatetime.cpp \
tools/qdumper.cpp \
+ tools/qeasingcurve.cpp \
tools/qhash.cpp \
tools/qline.cpp \
tools/qlinkedlist.cpp \