From 8589b7c526f8c7d436c6a7c3bfb39dc505eff78e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 12 May 2009 18:52:58 +0200 Subject: doc: Add documentation for Tank Game example --- doc/src/examples.qdoc | 1 + doc/src/examples/tankgame.qdoc | 115 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 doc/src/examples/tankgame.qdoc diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 0153252..6fb903c 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -315,6 +315,7 @@ \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/tankgame.qdoc b/doc/src/examples/tankgame.qdoc new file mode 100644 index 0000000..e10161c --- /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 3 + + 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. + +*/ -- cgit v0.12 From 288de11968d4b71c97fc5d1a175d4c4ac7023552 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 13 May 2009 11:01:32 +0200 Subject: doc: Correct names of snippets in docs for Tank Game example --- doc/src/examples/tankgame.qdoc | 2 +- examples/statemachine/tankgame/mainwindow.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/src/examples/tankgame.qdoc b/doc/src/examples/tankgame.qdoc index e10161c..1501a99 100644 --- a/doc/src/examples/tankgame.qdoc +++ b/doc/src/examples/tankgame.qdoc @@ -98,7 +98,7 @@ 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 3 + \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 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] } } } -- cgit v0.12 From 5c7c8208c559d82e96aa7aa8c753c224d89022a2 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Wed, 13 May 2009 11:20:14 +0200 Subject: document statemachine/factorial example --- doc/src/examples.qdoc | 1 + doc/src/examples/factorial.qdoc | 102 +++++++++++++++++++++++++++++++ doc/src/images/factorial-example.png | Bin 0 -> 4032 bytes examples/statemachine/factorial/main.cpp | 64 +++++++++++-------- 4 files changed, 141 insertions(+), 26 deletions(-) create mode 100644 doc/src/examples/factorial.qdoc create mode 100644 doc/src/images/factorial-example.png diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 6fb903c..6603390 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -312,6 +312,7 @@ \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 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/images/factorial-example.png b/doc/src/images/factorial-example.png new file mode 100644 index 0000000..8fb1cc6 Binary files /dev/null and b/doc/src/images/factorial-example.png differ 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 #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(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(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(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" -- cgit v0.12 From 6b2d3e437bf1632191f62c603f754f895d4122eb Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Wed, 13 May 2009 12:39:11 +0200 Subject: kill the QT_STATEMACHINE_SOLUTION define We won't release another Qt Solution, so the define is no longer needed. --- src/corelib/statemachine/qabstractstate.cpp | 27 +------- src/corelib/statemachine/qabstractstate.h | 3 - src/corelib/statemachine/qabstractstate_p.h | 8 --- src/corelib/statemachine/qabstracttransition.cpp | 51 ++------------- src/corelib/statemachine/qabstracttransition.h | 3 - src/corelib/statemachine/qabstracttransition_p.h | 8 --- src/corelib/statemachine/qeventtransition.cpp | 4 -- src/corelib/statemachine/qeventtransition.h | 6 -- src/corelib/statemachine/qfinalstate.h | 4 -- src/corelib/statemachine/qhistorystate.h | 4 -- src/corelib/statemachine/qsignaleventgenerator_p.h | 9 +-- src/corelib/statemachine/qsignaltransition.cpp | 4 -- src/corelib/statemachine/qsignaltransition.h | 4 -- src/corelib/statemachine/qstate.cpp | 9 --- src/corelib/statemachine/qstate.h | 4 -- src/corelib/statemachine/qstatemachine.cpp | 76 ++-------------------- src/corelib/statemachine/qstatemachine.h | 9 +-- src/corelib/statemachine/qstatemachine_p.h | 11 +--- src/gui/statemachine/qguistatemachine.cpp | 5 -- 19 files changed, 16 insertions(+), 233 deletions(-) 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 -#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 &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 &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 &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 &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 -#endif #include #include @@ -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 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(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 -#else -#include "qabstracttransition.h" -#endif #include 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 -#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 -#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(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 -#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 QStatePrivate::childStates() const { QList result; QList::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(*it); if (!s || qobject_cast(s)) @@ -209,9 +206,6 @@ QList QStatePrivate::historyStates() const { QList result; QList::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(*it); if (h) @@ -224,9 +218,6 @@ QList QStatePrivate::transitions() const { QList result; QList::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(*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 -#else -#include "qabstractstate.h" -#endif QT_BEGIN_HEADER diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 40a465a..c2b2696 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 -# else -# include "qvariantanimation_p.h" -# endif +#include #endif #include @@ -212,9 +206,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 +1266,6 @@ void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition) #endif } -#ifndef QT_STATEMACHINE_SOLUTION - static int senderSignalIndex(const QObject *sender) { QObjectPrivate *d = QObjectPrivate::get(const_cast(sender)); @@ -1292,8 +1282,6 @@ static int senderSignalIndex(const QObject *sender) return d->currentSender->signal; } -#endif - void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition) { Q_Q(QStateMachine); @@ -1315,12 +1303,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 +1330,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 &connectedSignalIndexes = connections[sender]; @@ -1362,7 +1345,6 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit if (sum == 0) connections.remove(sender); } -#endif } void QStateMachinePrivate::unregisterAllTransitions() @@ -1392,10 +1374,8 @@ 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()); QEventTransitionPrivate::get(transition)->registered = true; @@ -1449,36 +1429,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 +1446,6 @@ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) */ QStateMachine::~QStateMachine() { -#ifdef QT_STATEMACHINE_SOLUTION - delete d_ptr; -#endif } namespace { @@ -2088,11 +2045,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(parent()); QStateMachinePrivate::get(machine)->handleTransitionSignal(sender(), signalIndex, _a); break; @@ -2104,15 +2059,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 +2091,8 @@ QSignalEventGenerator::QSignalEventGenerator( */ QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex, const QList &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 +2151,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 -#else -# include "qabstractstate.h" -#endif +#include #include #include @@ -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..9b4b861 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 -#endif #include #include #include @@ -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,9 +196,8 @@ public: #endif // QT_NO_ANIMATION -#ifndef QT_STATEMACHINE_SOLUTION QSignalEventGenerator *signalEventGenerator; -#endif + QHash > connections; #ifndef QT_NO_STATEMACHINE_EVENTFILTER QHash > qobjectEvents; @@ -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 #include -#endif #include #include -- cgit v0.12 From c89557db5b643eb8018de8ca87e5e56140ed6d2d Mon Sep 17 00:00:00 2001 From: Geir Vattekar Date: Wed, 13 May 2009 12:40:27 +0200 Subject: Doc: Work on QStateMachine class description Reviewed-by: Kent Hansen --- src/corelib/statemachine/qstatemachine.cpp | 140 +++++++++++++++++------------ 1 file changed, 85 insertions(+), 55 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 24af8e4..42e965a 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -89,68 +89,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} */ /*! -- cgit v0.12 From db5c26f49d86d195306273038a84a48b3ea62719 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 13 May 2009 13:18:00 +0200 Subject: doc: Add screenshot for Tank Game Example --- doc/src/images/tankgame-example.png | Bin 0 -> 16089 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/src/images/tankgame-example.png diff --git a/doc/src/images/tankgame-example.png b/doc/src/images/tankgame-example.png new file mode 100644 index 0000000..9e17e30 Binary files /dev/null and b/doc/src/images/tankgame-example.png differ -- cgit v0.12 From d1f79472826577406a675de61122cd4fc9413c52 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Wed, 13 May 2009 13:31:34 +0200 Subject: more statemachine docs --- doc/src/images/statemachine-customevents2.png | Bin 0 -> 6713 bytes doc/src/statemachine.qdoc | 45 +++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 doc/src/images/statemachine-customevents2.png diff --git a/doc/src/images/statemachine-customevents2.png b/doc/src/images/statemachine-customevents2.png new file mode 100644 index 0000000..57b37ef Binary files /dev/null and b/doc/src/images/statemachine-customevents2.png 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, -- cgit v0.12 From a82714c6c82f682e02969d9afa551f37f8132653 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Wed, 13 May 2009 13:56:44 +0200 Subject: correctly handle multiple event transitions for same (object,event) The event filter was not removed at the right time. We now store the number of active event transitions for a particular (object,event) and only remove the filtering when the count drops to zero. --- src/corelib/statemachine/qstatemachine.cpp | 19 ++++++---- src/corelib/statemachine/qstatemachine_p.h | 2 +- tests/auto/qstatemachine/tst_qstatemachine.cpp | 48 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 2f620c7..046fbb4 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1407,7 +1407,7 @@ void QStateMachinePrivate::registerEventTransition(QEventTransition *transition) QObjectPrivate *od = QObjectPrivate::get(object); if (!od->eventFilters.contains(q)) 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() @@ -1422,11 +1422,18 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio if (!QEventTransitionPrivate::get(transition)->registered) return; QObject *object = QEventTransitionPrivate::get(transition)->object; - QSet &events = qobjectEvents[object]; - events.remove(transition->eventType()); - if (events.isEmpty()) { - qobjectEvents.remove(object); - object->removeEventFilter(q); + QHash &events = qobjectEvents[object]; + Q_ASSERT(events.value(transition->eventType()) > 0); + if (--events[transition->eventType()] == 0) { + events.remove(transition->eventType()); + int sum = 0; + QHash::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; } diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 9b4b861..dfa5575 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -200,7 +200,7 @@ public: QHash > connections; #ifndef QT_NO_STATEMACHINE_EVENTFILTER - QHash > qobjectEvents; + QHash > qobjectEvents; #endif QHash delayedEvents; 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() -- cgit v0.12