summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/examples.qdoc2
-rw-r--r--doc/src/examples/factorial.qdoc102
-rw-r--r--doc/src/examples/tankgame.qdoc115
-rw-r--r--doc/src/images/factorial-example.pngbin0 -> 4032 bytes
-rw-r--r--doc/src/images/statemachine-customevents2.pngbin0 -> 6713 bytes
-rw-r--r--doc/src/images/tankgame-example.pngbin0 -> 16089 bytes
-rw-r--r--doc/src/statemachine.qdoc45
-rw-r--r--examples/statemachine/factorial/main.cpp64
-rw-r--r--examples/statemachine/tankgame/mainwindow.cpp4
-rw-r--r--src/corelib/statemachine/qabstractstate.cpp27
-rw-r--r--src/corelib/statemachine/qabstractstate.h3
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h8
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp51
-rw-r--r--src/corelib/statemachine/qabstracttransition.h3
-rw-r--r--src/corelib/statemachine/qabstracttransition_p.h8
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp4
-rw-r--r--src/corelib/statemachine/qeventtransition.h6
-rw-r--r--src/corelib/statemachine/qfinalstate.h4
-rw-r--r--src/corelib/statemachine/qhistorystate.h4
-rw-r--r--src/corelib/statemachine/qsignaleventgenerator_p.h9
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp4
-rw-r--r--src/corelib/statemachine/qsignaltransition.h4
-rw-r--r--src/corelib/statemachine/qstate.cpp9
-rw-r--r--src/corelib/statemachine/qstate.h4
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp235
-rw-r--r--src/corelib/statemachine/qstatemachine.h9
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h13
-rw-r--r--src/gui/statemachine/qguistatemachine.cpp5
-rw-r--r--tests/auto/qstatemachine/tst_qstatemachine.cpp48
29 files changed, 464 insertions, 326 deletions
diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc
index 0153252..6603390 100644
--- a/doc/src/examples.qdoc
+++ b/doc/src/examples.qdoc
@@ -312,9 +312,11 @@
\list
\o \l{statemachine/eventtransitions}{Event Transitions}\raisedaster
+ \o \l{statemachine/factorial}{Factorial States}\raisedaster
\o \l{statemachine/pingpong}{Ping Pong States}\raisedaster
\o \l{statemachine/trafficlight}{Traffic Light}\raisedaster
\o \l{statemachine/twowaybutton}{Two-way Button}\raisedaster
+ \o \l{statemachine/tankgame}{Tank Game}\raisedaster
\endlist
\section1 Threads
diff --git a/doc/src/examples/factorial.qdoc b/doc/src/examples/factorial.qdoc
new file mode 100644
index 0000000..2a72e0a
--- /dev/null
+++ b/doc/src/examples/factorial.qdoc
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the documentation 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$
+**
+****************************************************************************/
+
+/*!
+ \example statemachine/factorial
+ \title Factorial States Example
+
+ The Factorial States example shows how to use \l{The State Machine
+ Framework} to calculate the factorial of an integer.
+
+ The statechart for calculating the factorial looks as follows:
+
+ \img factorial-example.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ In other words, the state machine calculates the factorial of 6 and prints
+ the result.
+
+ \snippet examples/statemachine/factorial/main.cpp 0
+
+ The Factorial class is used to hold the data of the computation, \c x and
+ \c fac. It also provides a signal that's emitted whenever the value of \c
+ x changes.
+
+ \snippet examples/statemachine/factorial/main.cpp 1
+
+ The FactorialLoopTransition class implements the guard (\c x > 1) and
+ calculations (\c fac = \c x * \c fac; \c x = \c x - 1) of the factorial
+ loop.
+
+ \snippet examples/statemachine/factorial/main.cpp 2
+
+ The FactorialDoneTransition class implements the guard (\c x <= 1) that
+ terminates the factorial computation. It also prints the final result to
+ standard output.
+
+ \snippet examples/statemachine/factorial/main.cpp 3
+
+ The application's main() function first creates the application object, a
+ Factorial object and a state machine.
+
+ \snippet examples/statemachine/factorial/main.cpp 4
+
+ The \c compute state is created, and the initial values of \c x and \c fac
+ are defined. A FactorialLoopTransition object is created and added to the
+ state.
+
+ \snippet examples/statemachine/factorial/main.cpp 5
+
+ A final state, \c done, is created, and a FactorialDoneTransition object
+ is created with \c done as its target state. The transition is then added
+ to the \c compute state.
+
+ \snippet examples/statemachine/factorial/main.cpp 6
+
+ The machine's initial state is set to be the \c compute state. We connect
+ the QStateMachine::finished() signal to the QCoreApplication::quit() slot,
+ so the application will quit when the state machine's work is
+ done. Finally, the state machine is started, and the application's event
+ loop is entered.
+
+ */
diff --git a/doc/src/examples/tankgame.qdoc b/doc/src/examples/tankgame.qdoc
new file mode 100644
index 0000000..1501a99
--- /dev/null
+++ b/doc/src/examples/tankgame.qdoc
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the documentation 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$
+**
+****************************************************************************/
+
+/*!
+ \example statemachine/tankgame
+ \title Tank Game Example
+
+ The Tank Game example is part of the in \l{The State Machine Framework}. It shows how to use
+ parallel states to implement artificial intelligence controllers that run in parallel, and error
+ states to handle run-time errors in parts of the state graph created by external plugins.
+
+ \image tankgame-example.png
+
+ In this example we write a simple game. The application runs a state machine with two main
+ states: A "stopped" state and a "running" state. The user can load plugins from the disk by
+ selecting the "Add tank" menu item.
+
+ When the "Add tank" menu item is selected, the "plugins" subdirectory in the example's
+ directory is searched for compatible plugins. If any are found, they will be listed in a
+ dialog box created using QInputDialog::getItem().
+
+ \snippet examples/statemachine/tankgame/mainwindow.cpp 1
+
+ If the user selects a plugin, the application will construct a TankItem object, which inherits
+ from QGraphicsItem and QObject, and which implements an agreed-upon interface using the
+ meta-object mechanism.
+
+ \snippet examples/statemachine/tankgame/tankitem.h 0
+
+ The tank item will be passed to the plugin's create() function. This will in turn return a
+ QState object which is expected to implement an artificial intelligence which controls the
+ tank and attempts to destroy other tanks it detects.
+
+ \snippet examples/statemachine/tankgame/mainwindow.cpp 2
+
+ Each returned QState object becomes a descendant of a \c region in the "running" state, which is
+ defined as a parallel state. This means that entering the "running" state will cause each of the
+ plugged-in QState objects to be entered simultaneously, allowing the tanks to run independently
+ of each other.
+
+ \snippet examples/statemachine/tankgame/mainwindow.cpp 0
+
+ The maximum number of tanks on the map is four, and when this number is reached, the
+ "Add tank" menu item should be disabled. This is implemented by giving the "stopped" state two
+ children which define whether the map is full or not.
+
+ To make sure that we go into the correct child state when returning from the "running" state
+ (if the "Stop game" menu item is selected while the game is running) we also give the "stopped"
+ state a history state which we make the initial state of "stopped" state.
+
+ \snippet examples/statemachine/tankgame/mainwindow.cpp 3
+
+ Since part of the state graph is defined by external plugins, we have no way of controlling
+ whether they contain errors. By default, run-time errors are handled in the state machine by
+ entering a top level state which prints out an error message and never exits. If we were to
+ use this default behavior, a run-time error in any of the plugins would cause the "running"
+ state to exit, and thus all the other tanks to stop running as well. A better solution would
+ be if the broken plugin was disabled and the rest of the tanks allowed to continue as before.
+
+ This is done by setting the error state of the plugin's top-most state to a special error state
+ defined specifically for the plugin in question.
+
+ \snippet examples/statemachine/tankgame/mainwindow.cpp 4
+
+ If a run-time error occurs in \c pluginState or any of its descendants, the state machine will
+ search the hierarchy of ancestors until it finds a state whose error state is different from
+ \c null. (Note that if we are worried that a plugin could inadvertedly be overriding our
+ error state, we could search the descendants of \c pluginState and verify that their error
+ states are set to \c null before accepting the plugin.)
+
+ The specialized \c errorState sets the "enabled" property of the tank item in question to false,
+ causing it to be painted with a red cross over it to indicate that it is no longer running.
+ Since the error state is a child of the same region in the parallel "running" state as
+ \c pluginState, it will not exit the "running" state, and the other tanks will continue running
+ without disruption.
+
+*/
diff --git a/doc/src/images/factorial-example.png b/doc/src/images/factorial-example.png
new file mode 100644
index 0000000..8fb1cc6
--- /dev/null
+++ b/doc/src/images/factorial-example.png
Binary files differ
diff --git a/doc/src/images/statemachine-customevents2.png b/doc/src/images/statemachine-customevents2.png
new file mode 100644
index 0000000..57b37ef
--- /dev/null
+++ b/doc/src/images/statemachine-customevents2.png
Binary files differ
diff --git a/doc/src/images/tankgame-example.png b/doc/src/images/tankgame-example.png
new file mode 100644
index 0000000..9e17e30
--- /dev/null
+++ b/doc/src/images/tankgame-example.png
Binary files differ
diff --git a/doc/src/statemachine.qdoc b/doc/src/statemachine.qdoc
index 27bd4f8..5a89f4d 100644
--- a/doc/src/statemachine.qdoc
+++ b/doc/src/statemachine.qdoc
@@ -147,6 +147,9 @@
QObject::connect(s3, SIGNAL(exited()), button, SLOT(showMinimized()));
\endcode
+ Custom states can reimplement QAbstractState::onEntry() and
+ QAbstractState::onExit().
+
\section1 State Machines That Finish
The state machine defined in the previous section never finishes. In order
@@ -155,6 +158,9 @@
final state, the machine will emit the QStateMachine::finished() signal and
halt.
+ All you need to do to introduce a final state in the graph is create a
+ QFinalState object and use it as the target of one or more transitions.
+
\section1 Sharing Transitions By Grouping States
Assume we wanted the user to be able to quit the application at any time by
@@ -315,16 +321,32 @@
\section1 Detecting that a Composite State has Finished
A child state can be final (a QFinalState object); when a final child state
- is entered, the parent state emits the QState::finished() signal.
+ is entered, the parent state emits the QState::finished() signal. The
+ following diagram shows a composite state \c s1 which does some processing
+ before entering a final state:
\img statemachine-finished.png
\omit
\caption This is a caption
\endomit
- This is useful when you want to hide the internal details of a state;
- i.e. the only thing the outside world should be able to do is enter the
- state, and get a notification when the state has completed its work.
+ When \c s1 's final state is entered, \c s1 will automatically emit
+ finished(). We use a signal transition to cause this event to trigger a
+ state change:
+
+ \code
+ s1->addTransition(s1, SIGNAL(finished()), s2);
+ \endcode
+
+ Using final states in composite states is useful when you want to hide the
+ internal details of a composite state; i.e. the only thing the outside world
+ should be able to do is enter the state, and get a notification when the
+ state has completed its work. This is a very powerful abstraction and
+ encapsulation mechanism when building complex (deeply nested) state
+ machines. (In the above example, you could of course create a transition
+ directly from \c s1 's \c done state rather than relying on \c s1 's
+ finished() signal, but with the consequence that implementation details of
+ \c s1 are exposed and depended on).
For parallel state groups, the QState::finished() signal is emitted when \e
all the child states have entered final states.
@@ -425,7 +447,20 @@
machine.postEvent(new StringEvent("Hello"));
machine.postEvent(new StringEvent("world"));
\endcode
-
+
+ An event that is not handled by any relevant transition will be silently
+ consumed by the state machine. It can be useful to group states and provide
+ a default handling of such events; for example, as illustrated in the
+ following statechart:
+
+ \img statemachine-customevents2.png
+ \omit
+ \caption This is a caption
+ \endomit
+
+ For deeply nested statecharts, you can add such "fallback" transitions at
+ the level of granularity that's most appropriate.
+
\section1 Using Restore Policy To Automatically Restore Properties
In some state machines it can be useful to focus the attention on assigning properties in states,
diff --git a/examples/statemachine/factorial/main.cpp b/examples/statemachine/factorial/main.cpp
index 2b63690..ae5928f 100644
--- a/examples/statemachine/factorial/main.cpp
+++ b/examples/statemachine/factorial/main.cpp
@@ -48,6 +48,7 @@
#include <qfinalstate.h>
#endif
+//! [0]
class Factorial : public QObject
{
Q_OBJECT
@@ -55,10 +56,8 @@ class Factorial : public QObject
Q_PROPERTY(int fac READ fac WRITE setFac)
public:
Factorial(QObject *parent = 0)
- : QObject(parent)
+ : QObject(parent), m_x(-1), m_fac(1)
{
- m_fac = 1;
- m_x = -1;
}
int x() const
@@ -71,7 +70,7 @@ public:
if (x == m_x)
return;
m_x = x;
- emit xChanged();
+ emit xChanged(x);
}
int fac() const
@@ -85,28 +84,34 @@ public:
}
Q_SIGNALS:
- void xChanged();
+ void xChanged(int value);
private:
int m_x;
int m_fac;
};
+//! [0]
+//! [1]
class FactorialLoopTransition : public QSignalTransition
{
public:
FactorialLoopTransition(Factorial *fact)
- : QSignalTransition(fact, SIGNAL(xChanged())), m_fact(fact)
+ : QSignalTransition(fact, SIGNAL(xChanged(int))), m_fact(fact)
{}
- virtual bool eventTest(QEvent *) const
+ virtual bool eventTest(QEvent *e) const
{
- return m_fact->property("x").toInt() > 1;
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ return se->arguments().at(0).toInt() > 1;
}
- virtual void onTransition(QEvent *)
+ virtual void onTransition(QEvent *e)
{
- int x = m_fact->property("x").toInt();
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ int x = se->arguments().at(0).toInt();
int fac = m_fact->property("fac").toInt();
m_fact->setProperty("fac", x * fac);
m_fact->setProperty("x", x - 1);
@@ -115,17 +120,22 @@ public:
private:
Factorial *m_fact;
};
+//! [1]
+//! [2]
class FactorialDoneTransition : public QSignalTransition
{
public:
FactorialDoneTransition(Factorial *fact)
- : QSignalTransition(fact, SIGNAL(xChanged())), m_fact(fact)
+ : QSignalTransition(fact, SIGNAL(xChanged(int))), m_fact(fact)
{}
- virtual bool eventTest(QEvent *) const
+ virtual bool eventTest(QEvent *e) const
{
- return m_fact->property("x").toInt() <= 1;
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QSignalEvent *se = static_cast<QSignalEvent*>(e);
+ return se->arguments().at(0).toInt() <= 1;
}
virtual void onTransition(QEvent *)
@@ -136,35 +146,37 @@ public:
private:
Factorial *m_fact;
};
+//! [2]
+//! [3]
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
-
Factorial factorial;
-
QStateMachine machine;
+//! [3]
- QState *computing = new QState(machine.rootState());
- computing->addTransition(new FactorialLoopTransition(&factorial));
+//! [4]
+ QState *compute = new QState(machine.rootState());
+ compute->assignProperty(&factorial, "fac", 1);
+ compute->assignProperty(&factorial, "x", 6);
+ compute->addTransition(new FactorialLoopTransition(&factorial));
+//! [4]
+//! [5]
QFinalState *done = new QFinalState(machine.rootState());
FactorialDoneTransition *doneTransition = new FactorialDoneTransition(&factorial);
doneTransition->setTargetState(done);
- computing->addTransition(doneTransition);
-
- QState *initialize = new QState(machine.rootState());
- initialize->assignProperty(&factorial, "x", 6);
- FactorialLoopTransition *enterLoopTransition = new FactorialLoopTransition(&factorial);
- enterLoopTransition->setTargetState(computing);
- initialize->addTransition(enterLoopTransition);
+ compute->addTransition(doneTransition);
+//! [5]
+//! [6]
+ machine.setInitialState(compute);
QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit()));
-
- machine.setInitialState(initialize);
machine.start();
return app.exec();
}
+//! [6]
#include "main.moc"
diff --git a/examples/statemachine/tankgame/mainwindow.cpp b/examples/statemachine/tankgame/mainwindow.cpp
index 3bc9bbe..870bc9c 100644
--- a/examples/statemachine/tankgame/mainwindow.cpp
+++ b/examples/statemachine/tankgame/mainwindow.cpp
@@ -135,8 +135,10 @@ void MainWindow::init()
spawnsAvailable->addTransition(this, SIGNAL(mapFull()), noSpawnsAvailable);
+//! [3]
QHistoryState *hs = new QHistoryState(stoppedState);
hs->setDefaultState(spawnsAvailable);
+//! [3]
stoppedState->setInitialState(hs);
@@ -255,9 +257,11 @@ void MainWindow::addTank()
// If the plugin has an error it is disabled
+//! [4]
QState *errorState = new QState(region);
errorState->assignProperty(tankItem, "enabled", false);
pluginState->setErrorState(errorState);
+//! [4]
}
}
}
diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp
index 3f84314..7e59a7d 100644
--- a/src/corelib/statemachine/qabstractstate.cpp
+++ b/src/corelib/statemachine/qabstractstate.cpp
@@ -129,36 +129,16 @@ void QAbstractStatePrivate::emitExited()
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
+ : QObject(*new QAbstractStatePrivate, parent)
{
-#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
+ : QObject(dd, parent)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
}
/*!
@@ -166,9 +146,6 @@ QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent)
*/
QAbstractState::~QAbstractState()
{
-#ifdef QT_STATEMACHINE_SOLUTION
- delete d_ptr;
-#endif
}
/*!
diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h
index f6b4b21..d0ebb52 100644
--- a/src/corelib/statemachine/qabstractstate.h
+++ b/src/corelib/statemachine/qabstractstate.h
@@ -76,9 +76,6 @@ protected:
bool event(QEvent *e);
protected:
-#ifdef QT_STATEMACHINE_SOLUTION
- QAbstractStatePrivate *d_ptr;
-#endif
QAbstractState(QAbstractStatePrivate &dd, QState *parent);
private:
diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h
index 6c09696..1a99d6c 100644
--- a/src/corelib/statemachine/qabstractstate_p.h
+++ b/src/corelib/statemachine/qabstractstate_p.h
@@ -53,9 +53,7 @@
// We mean it.
//
-#ifndef QT_STATEMACHINE_SOLUTION
#include <private/qobject_p.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -63,9 +61,7 @@ class QStateMachine;
class QAbstractState;
class Q_CORE_EXPORT QAbstractStatePrivate
-#ifndef QT_STATEMACHINE_SOLUTION
: public QObjectPrivate
-#endif
{
Q_DECLARE_PUBLIC(QAbstractState)
@@ -82,10 +78,6 @@ public:
void emitEntered();
void emitExited();
-
-#ifdef QT_STATEMACHINE_SOLUTION
- QAbstractState *q_ptr;
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
index 6ddb416..f7a7d34 100644
--- a/src/corelib/statemachine/qabstracttransition.cpp
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -147,18 +147,8 @@ QState *QAbstractTransitionPrivate::sourceState() const
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
+ : QObject(*new QAbstractTransitionPrivate, sourceState)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
}
/*!
@@ -167,18 +157,8 @@ QAbstractTransition::QAbstractTransition(QState *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
+ : QObject(*new QAbstractTransitionPrivate, sourceState)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
setTargetStates(targets);
}
@@ -187,18 +167,8 @@ QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets,
*/
QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
QState *parent)
- : QObject(
-#ifndef QT_STATEMACHINE_SOLUTION
- dd,
-#endif
- parent)
-#ifdef QT_STATEMACHINE_SOLUTION
- , d_ptr(&dd)
-#endif
+ : QObject(dd, parent)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
}
/*!
@@ -207,18 +177,8 @@ QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
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
+ : QObject(dd, parent)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
setTargetStates(targets);
}
@@ -227,9 +187,6 @@ QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
*/
QAbstractTransition::~QAbstractTransition()
{
-#ifdef QT_STATEMACHINE_SOLUTION
- delete d_ptr;
-#endif
}
/*!
diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h
index e207944..8f0cefa 100644
--- a/src/corelib/statemachine/qabstracttransition.h
+++ b/src/corelib/statemachine/qabstracttransition.h
@@ -95,9 +95,6 @@ protected:
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);
diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h
index eb0ec21..156e70e 100644
--- a/src/corelib/statemachine/qabstracttransition_p.h
+++ b/src/corelib/statemachine/qabstracttransition_p.h
@@ -53,9 +53,7 @@
// We mean it.
//
-#ifndef QT_STATEMACHINE_SOLUTION
#include <private/qobject_p.h>
-#endif
#include <QtCore/qlist.h>
#include <QtCore/qpointer.h>
@@ -68,9 +66,7 @@ class QStateMachine;
class QAbstractTransition;
class Q_CORE_EXPORT QAbstractTransitionPrivate
-#ifndef QT_STATEMACHINE_SOLUTION
: public QObjectPrivate
-#endif
{
Q_DECLARE_PUBLIC(QAbstractTransition)
public:
@@ -89,10 +85,6 @@ public:
#ifndef QT_NO_ANIMATION
QList<QAbstractAnimation*> animations;
#endif
-
-#ifdef QT_STATEMACHINE_SOLUTION
- QAbstractTransition *q_ptr;
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp
index 86259e4..3ae3ed9 100644
--- a/src/corelib/statemachine/qeventtransition.cpp
+++ b/src/corelib/statemachine/qeventtransition.cpp
@@ -255,11 +255,7 @@ void QEventTransition::setEventObject(QObject *object)
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::Wrapped) {
-#endif
QWrappedEvent *we = static_cast<QWrappedEvent*>(event);
return (we->object() == d->object)
&& (we->event()->type() == d->eventType);
diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h
index a128cee..68ee4fc 100644
--- a/src/corelib/statemachine/qeventtransition.h
+++ b/src/corelib/statemachine/qeventtransition.h
@@ -42,11 +42,7 @@
#ifndef QEVENTTRANSITION_H
#define QEVENTTRANSITION_H
-#ifndef QT_STATEMACHINE_SOLUTION
#include <QtCore/qabstracttransition.h>
-#else
-#include "qabstracttransition.h"
-#endif
#include <QtCore/qcoreevent.h>
QT_BEGIN_HEADER
@@ -60,9 +56,7 @@ class Q_CORE_EXPORT QEventTransition : public QAbstractTransition
{
Q_OBJECT
Q_PROPERTY(QObject* eventObject READ eventObject WRITE setEventObject)
-#ifndef QT_STATEMACHINE_SOLUTION
Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType)
-#endif
public:
QEventTransition(QState *sourceState = 0);
QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0);
diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h
index eb8aa0f..fa68394 100644
--- a/src/corelib/statemachine/qfinalstate.h
+++ b/src/corelib/statemachine/qfinalstate.h
@@ -42,11 +42,7 @@
#ifndef QFINALSTATE_H
#define QFINALSTATE_H
-#ifndef QT_STATEMACHINE_SOLUTION
#include <QtCore/qabstractstate.h>
-#else
-#include "qabstractstate.h"
-#endif
QT_BEGIN_HEADER
diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h
index d0f75de..a0682bd 100644
--- a/src/corelib/statemachine/qhistorystate.h
+++ b/src/corelib/statemachine/qhistorystate.h
@@ -42,11 +42,7 @@
#ifndef QHISTORYSTATE_H
#define QHISTORYSTATE_H
-#ifndef QT_STATEMACHINE_SOLUTION
#include <QtCore/qabstractstate.h>
-#else
-#include "qabstractstate.h"
-#endif
QT_BEGIN_HEADER
diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h
index d18def8..cf0ea1e 100644
--- a/src/corelib/statemachine/qsignaleventgenerator_p.h
+++ b/src/corelib/statemachine/qsignaleventgenerator_p.h
@@ -62,11 +62,7 @@ class QStateMachine;
class QSignalEventGenerator : public QObject
{
public:
- QSignalEventGenerator(
-#ifdef QT_STATEMACHINE_SOLUTION
- int signalIndex,
-#endif
- QStateMachine *parent);
+ QSignalEventGenerator(QStateMachine *parent);
static const QMetaObject staticMetaObject;
virtual const QMetaObject *metaObject() const;
@@ -74,9 +70,6 @@ public:
virtual int qt_metacall(QMetaObject::Call, int, void **argv);
private:
-#ifdef QT_STATEMACHINE_SOLUTION
- int signalIndex;
-#endif
Q_DISABLE_COPY(QSignalEventGenerator)
};
diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp
index d5833bd..fd17292 100644
--- a/src/corelib/statemachine/qsignaltransition.cpp
+++ b/src/corelib/statemachine/qsignaltransition.cpp
@@ -228,11 +228,7 @@ void QSignalTransition::setSignal(const QByteArray &signal)
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
if (d->signalIndex == -1)
return false;
QSignalEvent *se = static_cast<QSignalEvent*>(event);
diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h
index 98a9ae7..7f457b8 100644
--- a/src/corelib/statemachine/qsignaltransition.h
+++ b/src/corelib/statemachine/qsignaltransition.h
@@ -42,11 +42,7 @@
#ifndef QSIGNALTRANSITION_H
#define QSIGNALTRANSITION_H
-#ifndef QT_STATEMACHINE_SOLUTION
#include <QtCore/qabstracttransition.h>
-#else
-#include "qabstracttransition.h"
-#endif
QT_BEGIN_HEADER
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
index f1528b8..8893bfe 100644
--- a/src/corelib/statemachine/qstate.cpp
+++ b/src/corelib/statemachine/qstate.cpp
@@ -193,9 +193,6 @@ 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))
@@ -209,9 +206,6 @@ 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)
@@ -224,9 +218,6 @@ 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)
diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h
index 73955d7..6729c69 100644
--- a/src/corelib/statemachine/qstate.h
+++ b/src/corelib/statemachine/qstate.h
@@ -42,11 +42,7 @@
#ifndef QSTATE_H
#define QSTATE_H
-#ifndef QT_STATEMACHINE_SOLUTION
#include <QtCore/qabstractstate.h>
-#else
-#include "qabstractstate.h"
-#endif
QT_BEGIN_HEADER
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 40a465a..046fbb4 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -54,10 +54,8 @@
#include "qfinalstate.h"
#include "qhistorystate.h"
#include "qhistorystate_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"
@@ -68,11 +66,7 @@
#ifndef QT_NO_ANIMATION
#include "qpropertyanimation.h"
#include "qanimationgroup.h"
-# ifndef QT_STATEMACHINE_SOLUTION
-# include <private/qvariantanimation_p.h>
-# else
-# include "qvariantanimation_p.h"
-# endif
+#include <private/qvariantanimation_p.h>
#endif
#include <QtCore/qmetaobject.h>
@@ -89,68 +83,98 @@ QT_BEGIN_NAMESPACE
\since 4.6
\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
+ QStateMachine is based on the concepts and notation of
+ \l{Statecharts: A visual formalism for complex
+ systems}{Statecharts}. QStateMachine is part of \l{The State
+ Machine Framework}.
+
+ A state machine manages a set of states (classes that inherit from
+ QAbstractState) and transitions (descendants of
+ QAbstractTransition) between those states; these states and
+ transitions define a state graph. Once a state graph has been
+ built, the state machine can execute it. \l{QStateMachine}'s
+ execution algorithm is based on the \l{State Chart XML: State
+ Machine Notation for Control Abstraction}{State Chart XML (SCXML)}
+ algorithm. The framework's \l{The State Machine
+ Framework}{overview} gives several state graphs and the code to
+ build them.
+
+ The rootState() is the parent of all top-level states in the
+ machine; it is used, for instance, when the state graph is
+ deleted. It is created by the machine.
+
+ Use the addState() function to add a state to the state machine.
+ All top-level states are added to the root state. States are
+ removed with the removeState() function. Removing states while the
+ machine is running is discouraged.
+
+ Before the machine can be started, the \l{initialState}{initial
+ state} must be set. The initial state is the state that the
+ machine enters when started. You can then start() the state
+ machine. The started() signal is emitted when the initial state is
+ entered.
+
+ The machine is event driven and keeps its own event loop. Events
+ are posted to the machine through postEvent(). Note that this
+ means that it executes asynchronously, and that it will not
+ progress without a running event loop. You will normally not have
+ to post events to the machine directly as Qt's transitions, e.g.,
+ QEventTransition and its subclasses, handle this. But for custom
+ transitions triggered by events, postEvent() is useful.
+
+ The state machine processes events and takes transitions until a
+ top-level final state is entered; the state machine then emits the
+ finished() signal. You can also stop() the state machine
+ explicitly. The stopped() signal is emitted in this case.
+
+ 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->assignProperty(&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
+
+ This code example uses QState, which inherits QAbstractState. The
+ QState class provides a state that you can use to set properties
+ and invoke methods on \l{QObject}s when the state is entered or
+ exited. It also contains convenience functions for adding
+ transitions, e.g., \l{QSignalTransition}s as in this example. See
+ the QState class description for further details.
+
+ If an error is encountered, the machine will enter the
+ \l{errorState}{error state}, which is a special state created by
+ the machine. The types of errors possible are described by the
+ \l{QStateMachine::}{Error} enum. After the error state is entered,
+ the type of the error can be retrieved with error(). The execution
+ of the state graph will not stop when the error state is entered.
+ So it is possible to handle the error, for instance, by connecting
+ to the \l{QAbstractState::}{entered()} signal of the error state.
+ It is also possible to set a custom error state with
+ setErrorState().
+
+ \omit This stuff will be moved elsewhere
+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
assignments 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->assignProperty(&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.
+ \endomit
- The rootState() function returns the state machine's root state. All
- top-level states have the root state as their parent.
-
- \sa QAbstractState, QAbstractTransition
+ \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework}
*/
/*!
@@ -212,9 +236,7 @@ QStateMachinePrivate::QStateMachinePrivate()
globalRestorePolicy = QStateMachine::DoNotRestoreProperties;
rootState = 0;
initialErrorStateForRoot = 0;
-#ifndef QT_STATEMACHINE_SOLUTION
signalEventGenerator = 0;
-#endif
#ifndef QT_NO_ANIMATION
animationsEnabled = true;
#endif
@@ -1274,8 +1296,6 @@ void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition)
#endif
}
-#ifndef QT_STATEMACHINE_SOLUTION
-
static int senderSignalIndex(const QObject *sender)
{
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject*>(sender));
@@ -1292,8 +1312,6 @@ static int senderSignalIndex(const QObject *sender)
return d->currentSender->signal;
}
-#endif
-
void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition)
{
Q_Q(QStateMachine);
@@ -1315,12 +1333,8 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio
if (connectedSignalIndexes.size() <= signalIndex)
connectedSignalIndexes.resize(signalIndex+1);
if (connectedSignalIndexes.at(signalIndex) == 0) {
-#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) {
@@ -1346,7 +1360,6 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit
int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex;
if (signalIndex == -1)
return; // not registered
-#ifndef QT_STATEMACHINE_SOLUTION
QSignalTransitionPrivate::get(transition)->signalIndex = -1;
const QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
QVector<int> &connectedSignalIndexes = connections[sender];
@@ -1362,7 +1375,6 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit
if (sum == 0)
connections.remove(sender);
}
-#endif
}
void QStateMachinePrivate::unregisterAllTransitions()
@@ -1392,12 +1404,10 @@ void QStateMachinePrivate::registerEventTransition(QEventTransition *transition)
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());
+ ++qobjectEvents[object][transition->eventType()];
QEventTransitionPrivate::get(transition)->registered = true;
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": added event transition from" << transition->sourceState()
@@ -1412,11 +1422,18 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio
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);
+ QHash<QEvent::Type, int> &events = qobjectEvents[object];
+ Q_ASSERT(events.value(transition->eventType()) > 0);
+ if (--events[transition->eventType()] == 0) {
+ events.remove(transition->eventType());
+ int sum = 0;
+ QHash<QEvent::Type, int>::const_iterator it;
+ for (it = events.constBegin(); it != events.constEnd(); ++it)
+ sum += it.value();
+ if (sum == 0) {
+ qobjectEvents.remove(object);
+ object->removeEventFilter(q);
+ }
}
QEventTransitionPrivate::get(transition)->registered = false;
}
@@ -1449,36 +1466,16 @@ void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int sig
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
+ : QObject(*new QStateMachinePrivate, parent)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
}
/*!
\internal
*/
QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
- : QObject(
-#ifndef QT_STATEMACHINE_SOLUTION
- dd,
-#endif
- parent)
-#ifdef QT_STATEMACHINE_SOLUTION
- , d_ptr(&dd)
-#endif
+ : QObject(dd, parent)
{
-#ifdef QT_STATEMACHINE_SOLUTION
- d_ptr->q_ptr = this;
-#endif
}
/*!
@@ -1486,9 +1483,6 @@ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
*/
QStateMachine::~QStateMachine()
{
-#ifdef QT_STATEMACHINE_SOLUTION
- delete d_ptr;
-#endif
}
namespace {
@@ -2088,11 +2082,9 @@ int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
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;
@@ -2104,15 +2096,8 @@ int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
return _id;
}
-QSignalEventGenerator::QSignalEventGenerator(
-#ifdef QT_STATEMACHINE_SOLUTION
- int sigIdx,
-#endif
- QStateMachine *parent)
+QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
: QObject(parent)
-#ifdef QT_STATEMACHINE_SOLUTION
- , signalIndex(sigIdx)
-#endif
{
}
@@ -2143,13 +2128,8 @@ QSignalEventGenerator::QSignalEventGenerator(
*/
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)
+ : QEvent(QEvent::Signal), m_sender(sender),
+ m_signalIndex(signalIndex), m_arguments(arguments)
{
}
@@ -2208,12 +2188,7 @@ QSignalEvent::~QSignalEvent()
and \a event.
*/
QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event)
-#ifdef QT_STATEMACHINE_SOLUTION
- : QEvent(QEvent::Type(QEvent::User-3))
-#else
- : QEvent(QEvent::Wrapped)
-#endif
- , m_object(object), m_event(event)
+ : QEvent(QEvent::Wrapped), m_object(object), m_event(event)
{
}
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
index 5dc6c0b..2a98a9a 100644
--- a/src/corelib/statemachine/qstatemachine.h
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -42,11 +42,7 @@
#ifndef QSTATEMACHINE_H
#define QSTATEMACHINE_H
-#ifndef QT_STATEMACHINE_SOLUTION
-# include <QtCore/qabstractstate.h>
-#else
-# include "qabstractstate.h"
-#endif
+#include <QtCore/qabstractstate.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
@@ -151,9 +147,6 @@ protected:
bool event(QEvent *e);
protected:
-#ifdef QT_STATEMACHINE_SOLUTION
- QStateMachinePrivate *d_ptr;
-#endif
QStateMachine(QStateMachinePrivate &dd, QObject *parent);
private:
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index 4bf9ce2..dfa5575 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -53,9 +53,7 @@
// 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>
@@ -84,9 +82,7 @@ class QAbstractAnimation;
class QStateMachine;
class Q_CORE_EXPORT QStateMachinePrivate
-#ifndef QT_STATEMACHINE_SOLUTION
: public QObjectPrivate
-#endif
{
Q_DECLARE_PUBLIC(QStateMachine)
public:
@@ -200,12 +196,11 @@ public:
#endif // QT_NO_ANIMATION
-#ifndef QT_STATEMACHINE_SOLUTION
QSignalEventGenerator *signalEventGenerator;
-#endif
+
QHash<const QObject*, QVector<int> > connections;
#ifndef QT_NO_STATEMACHINE_EVENTFILTER
- QHash<QObject*, QSet<QEvent::Type> > qobjectEvents;
+ QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents;
#endif
QHash<int, QEvent*> delayedEvents;
@@ -215,10 +210,6 @@ public:
};
static const Handler *handler;
-
-#ifdef QT_STATEMACHINE_SOLUTION
- QStateMachine *q_ptr;
-#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp
index d30265a..b7563d7 100644
--- a/src/gui/statemachine/qguistatemachine.cpp
+++ b/src/gui/statemachine/qguistatemachine.cpp
@@ -9,13 +9,8 @@
**
****************************************************************************/
-#ifdef QT_STATEMACHINE_SOLUTION
-#include "qstatemachine.h"
-#include "qstatemachine_p.h"
-#else
#include <QtCore/qstatemachine.h>
#include <private/qstatemachine_p.h>
-#endif
#include <QtGui/qevent.h>
#include <QtGui/qgraphicssceneevent.h>
diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp
index 3f94ad9..f8a778a 100644
--- a/tests/auto/qstatemachine/tst_qstatemachine.cpp
+++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp
@@ -1881,6 +1881,54 @@ void tst_QStateMachine::eventTransitions()
QTRY_COMPARE(finishedSpy.count(), 1);
}
+ // Multiple transitions for same (object,event)
+ {
+ QStateMachine machine;
+ QState *s0 = new QState(machine.rootState());
+ QState *s1 = new QState(machine.rootState());
+ QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress);
+ t0->setTargetState(s1);
+ s0->addTransition(t0);
+ QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonPress);
+ t1->setTargetState(s0);
+ s1->addTransition(t1);
+
+ QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
+ machine.setInitialState(s0);
+ machine.start();
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s0));
+
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+
+ s0->removeTransition(t0);
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s0));
+
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s0));
+
+ s1->removeTransition(t1);
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s0));
+
+ s0->addTransition(t0);
+ s1->addTransition(t1);
+ QTest::mousePress(&button, Qt::LeftButton);
+ QCoreApplication::processEvents();
+ QCOMPARE(machine.configuration().size(), 1);
+ QVERIFY(machine.configuration().contains(s1));
+ }
}
void tst_QStateMachine::historyStates()