diff options
author | Geir Vattekar <geir.vattekar@trolltech.com> | 2009-05-13 10:41:19 (GMT) |
---|---|---|
committer | Geir Vattekar <geir.vattekar@trolltech.com> | 2009-05-13 10:41:19 (GMT) |
commit | a536da400fcd31e2b662d5d837dbc13d93f34bf1 (patch) | |
tree | be443380cbad740059b9d363bb429034e1c47668 | |
parent | c89557db5b643eb8018de8ca87e5e56140ed6d2d (diff) | |
parent | 0cd84ffef786310c12cf7bd314a8922ac1aca1c0 (diff) | |
download | Qt-a536da400fcd31e2b662d5d837dbc13d93f34bf1.zip Qt-a536da400fcd31e2b662d5d837dbc13d93f34bf1.tar.gz Qt-a536da400fcd31e2b662d5d837dbc13d93f34bf1.tar.bz2 |
Merge branch 'kinetic-animations' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-animations
53 files changed, 689 insertions, 498 deletions
diff --git a/doc/src/examples-overview.qdoc b/doc/src/examples-overview.qdoc index 549574d..92ccd4e 100644 --- a/doc/src/examples-overview.qdoc +++ b/doc/src/examples-overview.qdoc @@ -319,6 +319,14 @@ from displaying Web pages within a Qt user interface to an implementation of a basic function Web browser. + \section1 \l{Qt Examples#State Machine}{State Machine} + + Qt provides a powerful hierchical finite state machine through the Qt State + Machine classes. + + These examples demonstrate the fundamental aspects of implementing + Statecharts with Qt. + \section1 \l{Qt Examples#Qt for Embedded Linux}{Qt for Embedded Linux} \l{Qt Examples#Qt for Embedded Linux}{\inlineimage qt-embedded-examples.png diff --git a/doc/src/examples.qdoc b/doc/src/examples.qdoc index 06d7727..0153252 100644 --- a/doc/src/examples.qdoc +++ b/doc/src/examples.qdoc @@ -311,7 +311,10 @@ \section1 State Machine \list + \o \l{statemachine/eventtransitions}{Event Transitions}\raisedaster + \o \l{statemachine/pingpong}{Ping Pong States}\raisedaster \o \l{statemachine/trafficlight}{Traffic Light}\raisedaster + \o \l{statemachine/twowaybutton}{Two-way Button}\raisedaster \endlist \section1 Threads diff --git a/doc/src/examples/eventtransitions.qdoc b/doc/src/examples/eventtransitions.qdoc new file mode 100644 index 0000000..3b956bb --- /dev/null +++ b/doc/src/examples/eventtransitions.qdoc @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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/eventtransitions + \title Event Transitions Example + + The Event Transitions example shows how to use event transitions, a + feature of \l{The State Machine Framework}. + + \snippet examples/statemachine/eventtransitions/main.cpp 0 + + The \c Window class's constructors begins by creating a button. + + \snippet examples/statemachine/eventtransitions/main.cpp 1 + + Two states, \c s1 and \c s2, are created; upon entry they will assign + "Outside" and "Inside" to the button's text, respectively. + + \snippet examples/statemachine/eventtransitions/main.cpp 2 + + When the button receives an event of type QEvent::Enter and the state + machine is in state \c s1, the machine will transition to state \c s2. + + \snippet examples/statemachine/eventtransitions/main.cpp 3 + + When the button receives an event of type QEvent::Leave and the state + machine is in state \c s2, the machine will transition back to state \c + s1. + + \snippet examples/statemachine/eventtransitions/main.cpp 4 + + Next, the state \c s3 is created. \c s3 will be entered when the button + receives an event of type QEvent::MouseButtonPress and the state machine + is in state \c s2. When the button receives an event of type + QEvent::MouseButtonRelease and the state machine is in state \c s3, the + machine will transition back to state \c s2. + + \snippet examples/statemachine/eventtransitions/main.cpp 5 + + Finally, the states are added to the machine as top-level states, the + initial state is set to be \c s1 ("Outside"), and the machine is started. + + \snippet examples/statemachine/eventtransitions/main.cpp 6 + + The main() function constructs a Window object and shows it. + +*/ diff --git a/doc/src/examples/pingpong.qdoc b/doc/src/examples/pingpong.qdoc new file mode 100644 index 0000000..040e429 --- /dev/null +++ b/doc/src/examples/pingpong.qdoc @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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/pingpong + \title Ping Pong States Example + + The Ping Pong States example shows how to use parallel states together + with custom events and transitions in \l{The State Machine Framework}. + + This example implements a statechart where two states communicate by + posting events to the state machine. The state chart looks as follows: + + \img pingpong-example.png + \omit + \caption This is a caption + \endomit + + The \c pinger and \c ponger states are parallel states, i.e. they are + entered simultaneously and will take transitions independently of + eachother. + + The \c pinger state will post the first \c ping event upon entry; the \c + ponger state will respond by posting a \c pong event; this will cause the + \c pinger state to post a new \c ping event; and so on. + + \snippet examples/statemachine/pingpong/main.cpp 0 + + Two custom events are defined, \c PingEvent and \c PongEvent. + + \snippet examples/statemachine/pingpong/main.cpp 1 + + The \c Pinger class defines a state that posts a \c PingEvent to the state + machine when the state is entered. + + \snippet examples/statemachine/pingpong/main.cpp 2 + + The \c PingTransition class defines a transition that is triggered by + events of type \c PingEvent, and that posts a \c PongEvent (with a delay + of 500 milliseconds) to the state machine when the transition is + triggered. + + \snippet examples/statemachine/pingpong/main.cpp 3 + + The \c PongTransition class defines a transition that is triggered by + events of type \c PongEvent, and that posts a \c PingEvent (with a delay + of 500 milliseconds) to the state machine when the transition is + triggered. + + \snippet examples/statemachine/pingpong/main.cpp 4 + + The main() function begins by creating a state machine and a parallel + state group. + + \snippet examples/statemachine/pingpong/main.cpp 5 + + Next, the \c pinger and \c ponger states are created, with the parallel + state group as their parent state. Note that the transitions are \e + targetless. When such a transition is triggered, the source state won't be + exited and re-entered; only the transition's onTransition() function will + be called, and the state machine's configuration will remain the same, + which is precisely what we want in this case. + + \snippet examples/statemachine/pingpong/main.cpp 6 + + Finally, the group is added to the state machine, the machine is started, + and the application event loop is entered. + + */ diff --git a/doc/src/examples/trafficlight.qdoc b/doc/src/examples/trafficlight.qdoc index 16ee8ad..ae62127 100644 --- a/doc/src/examples/trafficlight.qdoc +++ b/doc/src/examples/trafficlight.qdoc @@ -1,11 +1,41 @@ /**************************************************************************** ** -** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $TROLLTECH_DUAL_LICENSE$ +** $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$ ** ****************************************************************************/ @@ -26,30 +56,41 @@ \snippet examples/statemachine/trafficlight/main.cpp 0 The LightWidget class represents a single light of the traffic light. It - provides a setOn() function to turn the light on or off. It paints itself - in the color that's passed to the constructor. + provides an \c on property and two slots, turnOn() and turnOff(), to turn + the light on and off, respectively. The widget paints itself in the color + that's passed to the constructor. - \snippet examples/statemachine/trafficlight/main.cpp 2 + \snippet examples/statemachine/trafficlight/main.cpp 1 The TrafficLightWidget class represents the visual part of the traffic - light; it's a widget that contains three lights, and provides accessor - functions for these. + light; it's a widget that contains three lights arranged vertically, and + provides accessor functions for these. - \snippet examples/statemachine/trafficlight/main.cpp 1 + \snippet examples/statemachine/trafficlight/main.cpp 2 - The LightState class represents a state that turns a light on when the - state is entered, and off when the state is exited. The class is a timer, - and as we shall see the timeout is used to transition from one LightState - to another. + The createLightState() function creates a state that turns a light on when + the state is entered, and off when the state is exited. The state uses a + timer, and as we shall see the timeout is used to transition from one + LightState to another. Here is the statechart for the light state: + + \img trafficlight-example1.png + \omit + \caption This is a caption + \endomit \snippet examples/statemachine/trafficlight/main.cpp 3 - The TrafficLight class combines the TrafficLightWidget with control flow - based on the LightState class. The state graph has four states: - red-to-yellow, yellow-to-green, green-to-yellow and yellow-to-red. The - initial state is red-to-yellow; when the state's timer times out, the - state machine transitions to yellow-to-green. The same process repeats - through the other states. + The TrafficLight class combines the TrafficLightWidget with a state + machine. The state graph has four states: red-to-yellow, yellow-to-green, + green-to-yellow and yellow-to-red. The initial state is red-to-yellow; + when the state's timer times out, the state machine transitions to + yellow-to-green. The same process repeats through the other states. + This is what the statechart looks like: + + \img trafficlight-example2.png + \omit + \caption This is a caption + \endomit \snippet examples/statemachine/trafficlight/main.cpp 4 diff --git a/examples/statemachine/helloworld/main.cpp b/doc/src/examples/twowaybutton.qdoc index fbe34b5..87de2e8 100644 --- a/examples/statemachine/helloworld/main.cpp +++ b/doc/src/examples/twowaybutton.qdoc @@ -3,7 +3,7 @@ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -39,40 +39,44 @@ ** ****************************************************************************/ -#include <QtCore> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#endif +/*! + \example statemachine/twowaybutton + \title Two-way Button Example -class S0 : public QState -{ -public: - S0(QState *parent = 0) - : QState(parent) {} + The Two-way button example shows how to use \l{The State Machine + Framework} to implement a simple state machine that toggles the current + state when a button is clicked. - virtual void onEntry(QEvent *) - { - fprintf(stdout, "Hello world!\n"); - } -}; + \snippet examples/statemachine/twowaybutton/main.cpp 0 -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); + The application's main() function begins by constructing the application + object, a button and a state machine. - QStateMachine machine; - QState *s0 = new S0(); - QFinalState *s1 = new QFinalState(); - s0->addTransition(s1); + \snippet examples/statemachine/twowaybutton/main.cpp 1 - machine.addState(s0); - machine.addState(s1); - machine.setInitialState(s0); + The state machine has two states; \c on and \c off. When either state is + entered, the text of the button will be set accordingly. - QObject::connect(&machine, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit())); - machine.start(); + \snippet examples/statemachine/twowaybutton/main.cpp 2 - return app.exec(); -} + When the state machine is in the \c off state and the button is clicked, + it will transition to the \c on state; when the state machine is in the \c + on state and the button is clicked, it will transition to the \c off + state. + + \snippet examples/statemachine/twowaybutton/main.cpp 3 + + The states are added to the state machine; they become top-level (sibling) + states. + + \snippet examples/statemachine/twowaybutton/main.cpp 4 + + The initial state is \c off; this is the state the state machine will + immediately transition to once the state machine is started. + + \snippet examples/statemachine/twowaybutton/main.cpp 5 + + Finally, the button is resized and made visible, and the application event + loop is entered. + +*/ diff --git a/doc/src/images/pingpong-example.png b/doc/src/images/pingpong-example.png Binary files differnew file mode 100644 index 0000000..af707e4 --- /dev/null +++ b/doc/src/images/pingpong-example.png diff --git a/doc/src/images/trafficlight-example1.png b/doc/src/images/trafficlight-example1.png Binary files differnew file mode 100644 index 0000000..ec8c7ff --- /dev/null +++ b/doc/src/images/trafficlight-example1.png diff --git a/doc/src/images/trafficlight-example2.png b/doc/src/images/trafficlight-example2.png Binary files differnew file mode 100644 index 0000000..a12e4db --- /dev/null +++ b/doc/src/images/trafficlight-example2.png diff --git a/doc/src/statemachine.qdoc b/doc/src/statemachine.qdoc index 16eae39..27bd4f8 100644 --- a/doc/src/statemachine.qdoc +++ b/doc/src/statemachine.qdoc @@ -1,11 +1,41 @@ /**************************************************************************** ** -** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** -** This file is part of the $MODULE$ of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $TROLLTECH_DUAL_LICENSE$ +** $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$ ** ****************************************************************************/ @@ -395,4 +425,186 @@ machine.postEvent(new StringEvent("Hello")); machine.postEvent(new StringEvent("world")); \endcode + + \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, + not on restoring them when the state is no longer active. If you know that a property should + always be restored to its initial value when the machine enters a state that does not explicitly + give the property a value, you can set the global restore policy to + QStateMachine::RestoreProperties. + + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + \endcode + + When this restore policy is set, the machine will automatically restore all properties. If it + enters a state where a given property is not set, it will first search the hierarchy of ancestors + to see if the property is defined there. If it is, the property will be restored to the value + defined by the closest ancestor. If not, it will be restored to its initial value (i.e. the + value of the property before any property assignments in states were executed.) + + Take the following code: + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + + QState *s1 = new QState(); + s1->assignProperty(object, "fooBar", 1.0); + machine.addState(s1); + machine.setInitialState(s1); + + QState *s2 = new QState(); + machine.addState(s2); + \endcode + + Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state + \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the + machine is in state \c s2, no value is explicitly defined for the property, so it will implicitly + be restored to 0.0. + + If we are using nested states, the parent defines a value for the property which is inherited by + all descendants that do not explicitly assign a value to the property. + \code + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + + QState *s1 = new QState(); + s1->assignProperty(object, "fooBar", 1.0); + machine.addState(s1); + machine.setInitialState(s1); + + QState *s2 = new QState(s1); + s2->assignProperty(object, "fooBar", 2.0); + s1->setInitialState(s2); + + QState *s3 = new QState(s1); + \endcode + + Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar + will have the value 2.0, since this is explicitly defined for the state. When the machine is in + state \c s3, no value is defined for the state, but \c s1 defines the property to be 1.0, so this + is the value that will be assigned to \c fooBar. + + \section1 Animating Property Assignments + + The State Machine API connects with the Animation API in Qt to allow automatically animating + properties as they are assigned in states. + + Say we have the following code: + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); + + s1->addTransition(button, SIGNAL(clicked()), s2); + \endcode + + Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 + it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button + will be set immediately when a given state has been entered. If we want the transition to be + smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition + object. + + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); + + QSignalTransition *transition = s1->addTransition(button, SIGNAL(clicked()), s2); + transition->addAnimation(new QPropertyAnimation(button, "geometry")); + \endcode + + Adding an animation for the property in question means that the property assignment will no + longer take immediate effect when the state has been entered. Instead, the animation will start + playing when the state has been entered and smoothly animate the property assignment. Since we + do not set the start value or end value of the animation, these will be set implicitly. The + start value of the animation will be the property's current value when the animation starts, and + the end value will be set based on the property assignments defined for the state. + + If the global restore policy of the state machine is set to QStateMachine::RestoreProperties, + it is possible to also add animations for the property restorations. + + \section1 Detecting That All Properties Have Been Set In A State + + When animations are used to assign properties, a state no longer defines the exact values that a + property will have when the machine is in the given state. While the animation is running, the + property can potentially have any value, depending on the animation. + + In some cases, it can be useful to be able to detect when the property has actually been assigned + the value defined by a state. For this, we can use the state's polished() signal. + \code + QState *s1 = new QState(); + s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); + + QState *s2 = new QState(); + + s1->addTransition(s1, SIGNAL(polished()), s2); + \endcode + + The machine will be in state \c s1 until the \c geometry property has been set. Then it will + immediately transition into \c s2. If the transition into \c s1 has an animation for the \c + geometry property, then the machine will stay in \c s1 until the animation has finished. If there + is no animation, it will simply set the property and immediately enter state \c s2. + + Either way, when the machine is in state \c s2, the property \c geometry has been assigned the + defined value. + + If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit + the polished() signal until these have been executed as well. + + \section1 What happens if a state is exited before the animation has finished + + If a state has property assignments, and the transition into the state has animations for the + properties, the state can potentially be exited before the properties have been assigned to the + values defines by the state. This is true in particular when there are transitions out from the + state that do not depend on the state being polished, as described in the previous section. + + The State Machine API guarantees that a property assigned by the state machine either: + \list + \o Has a value explicitly assigned to the property. + \o Is currently being animated into a value explicitly assigned to the property. + \endlist + + When a state is exited prior to the animation finishing, the behavior of the state machine depends + on the target state of the transition. If the target state explicitly assigns a value to the + property, no additional action will be taken. The property will be assigned the value defined by + the target state. + + If the target state does not assign any value to the property, there are two + options: By default, the property will be assigned the value defined by the state it is leaving + (the value it would have been assigned if the animation had been permitted to finish playing.) If + a global restore policy is set, however, this will take precedence, and the property will be + restored as usual. + + \section1 Default Animations + + As described earlier, you can add animations to transitions to make sure property assignments + in the target state are animated. If you want a specific animation to be used for a given property + regardless of which transition is taken, you can add it as a default animation to the state + machine. This is in particular useful when the properties assigned (or restored) by specific + states is not known when the machine is constructed. + + \code + QState *s1 = new QState(); + QState *s2 = new QState(); + + s2->assignProperty(object, "fooBar", 2.0); + s1->addTransition(s2); + + QStateMachine machine; + machine.setInitialState(s1); + machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar")); + \endcode + + When the machine is in state \c s2, the machine will play the default animation for the + property \c fooBar since this property is assigned by \c s2. + + Note that animations explicitly set on transitions will take precedence over any default + animation for the given property. */ diff --git a/examples/statemachine/clockticking/clockticking.pro b/examples/statemachine/clockticking/clockticking.pro deleted file mode 100644 index bff9cb8..0000000 --- a/examples/statemachine/clockticking/clockticking.pro +++ /dev/null @@ -1,10 +0,0 @@ -QT = core -TEMPLATE = app -TARGET = -win32: CONFIG += console -mac:CONFIG -= app_bundle -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/clockticking/main.cpp b/examples/statemachine/clockticking/main.cpp deleted file mode 100644 index ea8e692..0000000 --- a/examples/statemachine/clockticking/main.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore> -#include <stdio.h> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qabstracttransition.h> -#endif - -class ClockEvent : public QEvent -{ -public: - ClockEvent() : QEvent(QEvent::Type(QEvent::User+2)) - {} -}; - -class ClockState : public QState -{ -public: - ClockState(QState *parent) - : QState(parent) {} - -protected: - virtual void onEntry(QEvent *) - { - fprintf(stdout, "ClockState entered; posting the initial tick\n"); - machine()->postEvent(new ClockEvent()); - } -}; - -class ClockTransition : public QAbstractTransition -{ -public: - ClockTransition() {} - -protected: - virtual bool eventTest(QEvent *e) const { - return (e->type() == QEvent::User+2); - } - virtual void onTransition(QEvent *) - { - fprintf(stdout, "ClockTransition triggered; posting another tick with a delay of 1 second\n"); - machine()->postEvent(new ClockEvent(), 1000); - } -}; - -class ClockListener : public QAbstractTransition -{ -public: - ClockListener() {} - -protected: - virtual bool eventTest(QEvent *e) const { - return (e->type() == QEvent::User+2); - } - virtual void onTransition(QEvent *) - { - fprintf(stdout, "ClockListener heard a tick!\n"); - } -}; - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - - QStateMachine machine; - QState *group = new QState(QState::ParallelStates); - group->setObjectName("group"); - - ClockState *clock = new ClockState(group); - clock->setObjectName("clock"); - clock->addTransition(new ClockTransition()); - - QState *listener = new QState(group); - listener->setObjectName("listener"); - listener->addTransition(new ClockListener()); - - machine.addState(group); - machine.setInitialState(group); - machine.start(); - - return app.exec(); -} diff --git a/examples/statemachine/composition/composition.pro b/examples/statemachine/composition/composition.pro deleted file mode 100644 index 6a976cb..0000000 --- a/examples/statemachine/composition/composition.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/composition/main.cpp b/examples/statemachine/composition/main.cpp deleted file mode 100644 index 0afff66..0000000 --- a/examples/statemachine/composition/main.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#endif - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - QLabel label; - label.setAlignment(Qt::AlignCenter); - - QStateMachine machine; - - QState *s1 = new QState(); - s1->setObjectName("s1"); - s1->assignProperty(&label, "text", "In S1, hang on..."); - s1->assignProperty(&label, "geometry", QRect(100, 100, 200, 100)); - - QState *s1_timer = new QState(s1); - s1_timer->setObjectName("s1_timer"); - QTimer t1; - t1.setInterval(2000); - QObject::connect(s1_timer, SIGNAL(entered()), &t1, SLOT(start())); - QFinalState *s1_done = new QFinalState(s1); - s1_done->setObjectName("s1_done"); - s1_timer->addTransition(&t1, SIGNAL(timeout()), s1_done); - s1->setInitialState(s1_timer); - - QState *s2 = new QState(); - s2->setObjectName("s2"); - s2->assignProperty(&label, "text", "In S2, I'm gonna quit on you..."); - s2->assignProperty(&label, "geometry", QRect(300, 300, 300, 100)); -// s2->invokeMethodOnEntry(&label, "setNum", QList<QVariant>() << 123); -// s2->invokeMethodOnEntry(&label, "showMaximized"); - - QState *s2_timer = new QState(s2); - s2_timer->setObjectName("s2_timer"); - QTimer t2; - t2.setInterval(2000); - QObject::connect(s2_timer, SIGNAL(entered()), &t2, SLOT(start())); - QFinalState *s2_done = new QFinalState(s2); - s2_done->setObjectName("s2_done"); - s2_timer->addTransition(&t2, SIGNAL(timeout()), s2_done); - s2->setInitialState(s2_timer); - - s1->addTransition(s1, SIGNAL(finished()), s2); - - QFinalState *s3 = new QFinalState(); - s3->setObjectName("s3"); - s2->addTransition(s2, SIGNAL(finished()), s3); - - machine.addState(s1); - machine.addState(s2); - machine.addState(s3); - machine.setInitialState(s1); - QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit())); - machine.start(); - - label.show(); - return app.exec(); -} diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro deleted file mode 100644 index 5b6b758..0000000 --- a/examples/statemachine/errorstateplugins/errorstateplugins.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = random_ai \ - spin_ai_with_error \ - spin_ai \ - seek_ai - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins -sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS errorstateplugins.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins -INSTALLS += target sources diff --git a/examples/statemachine/eventtransitions/main.cpp b/examples/statemachine/eventtransitions/main.cpp index f564b7e..aba0c73 100644 --- a/examples/statemachine/eventtransitions/main.cpp +++ b/examples/statemachine/eventtransitions/main.cpp @@ -46,6 +46,7 @@ #include <qeventtransition.h> #endif +//! [0] class Window : public QWidget { public: @@ -54,7 +55,9 @@ public: { QPushButton *button = new QPushButton(this); button->setGeometry(QRect(100, 100, 100, 100)); +//! [0] +//! [1] QStateMachine *machine = new QStateMachine(this); QState *s1 = new QState(); @@ -62,15 +65,21 @@ public: QState *s2 = new QState(); s2->assignProperty(button, "text", "Inside"); +//! [1] +//! [2] QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter); enterTransition->setTargetState(s2); s1->addTransition(enterTransition); +//! [2] +//! [3] QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave); leaveTransition->setTargetState(s1); s2->addTransition(leaveTransition); +//! [3] +//! [4] QState *s3 = new QState(); s3->assignProperty(button, "text", "Pressing..."); @@ -81,16 +90,20 @@ public: QEventTransition *releaseTransition = new QEventTransition(button, QEvent::MouseButtonRelease); releaseTransition->setTargetState(s2); s3->addTransition(releaseTransition); +//! [4] +//! [5] machine->addState(s1); machine->addState(s2); machine->addState(s3); + machine->setInitialState(s1); - QObject::connect(machine, SIGNAL(finished()), qApp, SLOT(quit())); machine->start(); } }; +//! [5] +//! [6] int main(int argc, char **argv) { QApplication app(argc, argv); @@ -100,3 +113,4 @@ int main(int argc, char **argv) return app.exec(); } +//! [6] diff --git a/examples/statemachine/helloworld/helloworld.pro b/examples/statemachine/helloworld/helloworld.pro deleted file mode 100644 index ac79117..0000000 --- a/examples/statemachine/helloworld/helloworld.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = app -TARGET = -QT = core -win32: CONFIG += console -mac:CONFIG -= app_bundle -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/pauseandresume/main.cpp b/examples/statemachine/pauseandresume/main.cpp deleted file mode 100644 index 5bacb41..0000000 --- a/examples/statemachine/pauseandresume/main.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui> -#ifdef QT_STATEMACHINE_SOLUTION -#include <qstatemachine.h> -#include <qstate.h> -#include <qfinalstate.h> -#include <qhistorystate.h> -#endif - -class Window : public QWidget -{ -public: - Window(QWidget *parent = 0) - : QWidget(parent) - { - QPushButton *pb = new QPushButton("Go"); - QPushButton *pauseButton = new QPushButton("Pause"); - QPushButton *quitButton = new QPushButton("Quit"); - QVBoxLayout *vbox = new QVBoxLayout(this); - vbox->addWidget(pb); - vbox->addWidget(pauseButton); - vbox->addWidget(quitButton); - - QStateMachine *machine = new QStateMachine(this); - - QState *process = new QState(machine->rootState()); - process->setObjectName("process"); - - QState *s1 = new QState(process); - s1->setObjectName("s1"); - QState *s2 = new QState(process); - s2->setObjectName("s2"); - s1->addTransition(pb, SIGNAL(clicked()), s2); - s2->addTransition(pb, SIGNAL(clicked()), s1); - - QHistoryState *h = new QHistoryState(process); - h->setDefaultState(s1); - - QState *interrupted = new QState(machine->rootState()); - interrupted->setObjectName("interrupted"); - QFinalState *terminated = new QFinalState(machine->rootState()); - terminated->setObjectName("terminated"); - interrupted->addTransition(pauseButton, SIGNAL(clicked()), h); - interrupted->addTransition(quitButton, SIGNAL(clicked()), terminated); - - process->addTransition(pauseButton, SIGNAL(clicked()), interrupted); - process->addTransition(quitButton, SIGNAL(clicked()), terminated); - - process->setInitialState(s1); - machine->setInitialState(process); - QObject::connect(machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit())); - machine->start(); - } -}; - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - Window win; - win.show(); - return app.exec(); -} diff --git a/examples/statemachine/pauseandresume/pauseandresume.pro b/examples/statemachine/pauseandresume/pauseandresume.pro deleted file mode 100644 index 6a976cb..0000000 --- a/examples/statemachine/pauseandresume/pauseandresume.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/examples/statemachine/pingpong/main.cpp b/examples/statemachine/pingpong/main.cpp index eb8fd5d..db66bfd 100644 --- a/examples/statemachine/pingpong/main.cpp +++ b/examples/statemachine/pingpong/main.cpp @@ -47,6 +47,7 @@ #include <qabstracttransition.h> #endif +//! [0] class PingEvent : public QEvent { public: @@ -60,7 +61,9 @@ public: PongEvent() : QEvent(QEvent::Type(QEvent::User+3)) {} }; +//! [0] +//! [1] class Pinger : public QState { public: @@ -74,7 +77,9 @@ protected: fprintf(stdout, "ping?\n"); } }; +//! [1] +//! [3] class PongTransition : public QAbstractTransition { public: @@ -90,7 +95,9 @@ protected: fprintf(stdout, "ping?\n"); } }; +//! [3] +//! [2] class PingTransition : public QAbstractTransition { public: @@ -106,7 +113,9 @@ protected: fprintf(stdout, "pong!\n"); } }; +//! [2] +//! [4] int main(int argc, char **argv) { QCoreApplication app(argc, argv); @@ -114,7 +123,9 @@ int main(int argc, char **argv) QStateMachine machine; QState *group = new QState(QState::ParallelStates); group->setObjectName("group"); +//! [4] +//! [5] Pinger *pinger = new Pinger(group); pinger->setObjectName("pinger"); pinger->addTransition(new PongTransition()); @@ -122,10 +133,13 @@ int main(int argc, char **argv) QState *ponger = new QState(group); ponger->setObjectName("ponger"); ponger->addTransition(new PingTransition()); +//! [5] +//! [6] machine.addState(group); machine.setInitialState(group); machine.start(); return app.exec(); } +//! [6] diff --git a/examples/statemachine/statemachine.pro b/examples/statemachine/statemachine.pro index ba32c12..5074a3c 100644 --- a/examples/statemachine/statemachine.pro +++ b/examples/statemachine/statemachine.pro @@ -1,14 +1,12 @@ TEMPLATE = subdirs SUBDIRS = \ - clockticking \ - composition \ eventtransitions \ factorial \ - helloworld \ - pauseandresume \ pingpong \ trafficlight \ - twowaybutton + twowaybutton \ + tankgame \ + tankgameplugins # install target.path = $$[QT_INSTALL_EXAMPLES]/statemachine diff --git a/examples/statemachine/errorstate/gameitem.cpp b/examples/statemachine/tankgame/gameitem.cpp index 1a2af71..1a2af71 100644 --- a/examples/statemachine/errorstate/gameitem.cpp +++ b/examples/statemachine/tankgame/gameitem.cpp diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/tankgame/gameitem.h index 43b8785..43b8785 100644 --- a/examples/statemachine/errorstate/gameitem.h +++ b/examples/statemachine/tankgame/gameitem.h diff --git a/examples/statemachine/errorstate/main.cpp b/examples/statemachine/tankgame/main.cpp index 26fc1bb..26fc1bb 100644 --- a/examples/statemachine/errorstate/main.cpp +++ b/examples/statemachine/tankgame/main.cpp diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/tankgame/mainwindow.cpp index 07719bc..3bc9bbe 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/tankgame/mainwindow.cpp @@ -140,7 +140,9 @@ void MainWindow::init() stoppedState->setInitialState(hs); +//! [0] m_runningState = new QState(QState::ParallelStates, m_machine->rootState()); +//! [0] m_runningState->setObjectName("runningState"); m_runningState->assignProperty(addTankAction, "enabled", false); m_runningState->assignProperty(runGameAction, "enabled", false); @@ -231,8 +233,10 @@ void MainWindow::addTank() } bool ok; +//! [1] QString selectedName = QInputDialog::getItem(this, "Select a tank type", "Tank types", itemNames, 0, false, &ok); +//! [1] if (ok && !selectedName.isEmpty()) { int idx = itemNames.indexOf(selectedName); @@ -244,9 +248,12 @@ void MainWindow::addTank() emit mapFull(); QState *region = new QState(m_runningState); +//! [2] QState *pluginState = plugin->create(region, tankItem); +//! [2] region->setInitialState(pluginState); + // If the plugin has an error it is disabled QState *errorState = new QState(region); errorState->assignProperty(tankItem, "enabled", false); diff --git a/examples/statemachine/errorstate/mainwindow.h b/examples/statemachine/tankgame/mainwindow.h index 622dabe..622dabe 100644 --- a/examples/statemachine/errorstate/mainwindow.h +++ b/examples/statemachine/tankgame/mainwindow.h diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/tankgame/plugin.h index 2b48d43..2b48d43 100644 --- a/examples/statemachine/errorstate/plugin.h +++ b/examples/statemachine/tankgame/plugin.h diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/tankgame/rocketitem.cpp index c324980..c324980 100644 --- a/examples/statemachine/errorstate/rocketitem.cpp +++ b/examples/statemachine/tankgame/rocketitem.cpp diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/tankgame/rocketitem.h index 189a1dd..189a1dd 100644 --- a/examples/statemachine/errorstate/rocketitem.h +++ b/examples/statemachine/tankgame/rocketitem.h diff --git a/examples/statemachine/errorstate/errorstate.pro b/examples/statemachine/tankgame/tankgame.pro index b93a691..f7b0760 100644 --- a/examples/statemachine/errorstate/errorstate.pro +++ b/examples/statemachine/tankgame/tankgame.pro @@ -5,7 +5,7 @@ TEMPLATE = app TARGET = DEPENDPATH += . -INCLUDEPATH += C:/dev/kinetic/examples/statemachine/errorstate/. . +INCLUDEPATH += C:/dev/kinetic/examples/statemachine/tankgame/. . # Input HEADERS += mainwindow.h plugin.h tankitem.h rocketitem.h gameitem.h diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/tankgame/tankitem.cpp index 5506a7e..5506a7e 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/tankgame/tankitem.cpp diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/tankgame/tankitem.h index cefed69..66f05aa 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/tankgame/tankitem.h @@ -35,6 +35,7 @@ public: qreal distanceToObstacle() const; qreal distanceToObstacle(QGraphicsItem **item) const; +//! [0] signals: void tankSpotted(qreal direction, qreal distance); void collision(const QLineF &collidedLine); @@ -48,6 +49,7 @@ public slots: void turnTo(qreal degrees = 0.0); void stop(); void fireCannon(); +//! [0] protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai.pro b/examples/statemachine/tankgameplugins/random_ai/random_ai.pro index f290250..5bc0b26 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai.pro +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = random_ai_plugin.h SOURCES = random_ai_plugin.cpp TARGET = $$qtLibraryTarget(random_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS random_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/random_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/random_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp index c196247..c196247 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.cpp diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.h index 10e6f48..f5e3b6f 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h +++ b/examples/statemachine/tankgameplugins/random_ai/random_ai_plugin.h @@ -4,7 +4,7 @@ #include <QObject> #include <QState> -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> class SelectActionState: public QState { diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.cpp index 2fb05d4..2fb05d4 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.cpp diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.h index a1b5749..2835988 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.h @@ -1,7 +1,7 @@ #ifndef SEEK_AI_H #define SEEK_AI_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QState> #include <QFinalState> diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.pro index 11bd242..0d8bf2e 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro +++ b/examples/statemachine/tankgameplugins/seek_ai/seek_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = seek_ai.h SOURCES = seek_ai.cpp TARGET = $$qtLibraryTarget(seek_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS seek_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/seek_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/seek_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.cpp index de95f41..de95f41 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.cpp diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.h index 6e220ed..a331a3e 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.h @@ -1,7 +1,7 @@ #ifndef SPIN_AI_H #define SPIN_AI_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QObject> #include <QState> diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.pro index c2fd937..8ab4da0 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro +++ b/examples/statemachine/tankgameplugins/spin_ai/spin_ai.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = spin_ai.h SOURCES = spin_ai.cpp TARGET = $$qtLibraryTarget(spin_ai) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/spin_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.cpp index 5499ba3..5499ba3 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.cpp diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.h index d520455..5cfb364 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.h @@ -1,7 +1,7 @@ #ifndef SPIN_AI_WITH_ERROR_H #define SPIN_AI_WITH_ERROR_H -#include <errorstate/plugin.h> +#include <tankgame/plugin.h> #include <QObject> #include <QState> diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.pro index 31f4c7f..124cf98 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro +++ b/examples/statemachine/tankgameplugins/spin_ai_with_error/spin_ai_with_error.pro @@ -4,10 +4,10 @@ INCLUDEPATH += ../.. HEADERS = spin_ai_with_error.h SOURCES = spin_ai_with_error.cpp TARGET = $$qtLibraryTarget(spin_ai_with_error) -DESTDIR = ../../errorstate/plugins +DESTDIR = ../../tankgame/plugins #! [0] # install -target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgame/plugins sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai_with_error.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai_with_error
\ No newline at end of file +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins/spin_ai_with_error
\ No newline at end of file diff --git a/examples/statemachine/tankgameplugins/tankgameplugins.pro b/examples/statemachine/tankgameplugins/tankgameplugins.pro new file mode 100644 index 0000000..a098e03 --- /dev/null +++ b/examples/statemachine/tankgameplugins/tankgameplugins.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs +SUBDIRS = random_ai \ + spin_ai_with_error \ + spin_ai \ + seek_ai + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS tankgameplugins.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/tankgameplugins +INSTALLS += target sources diff --git a/examples/statemachine/trafficlight/main.cpp b/examples/statemachine/trafficlight/main.cpp index 3c47a51..8a46fff 100644 --- a/examples/statemachine/trafficlight/main.cpp +++ b/examples/statemachine/trafficlight/main.cpp @@ -87,27 +87,6 @@ private: //! [0] //! [1] -class LightState : public QState -{ -public: - LightState(LightWidget *light, int duration, QState *parent = 0) - : QState(parent) - { - QTimer *timer = new QTimer(this); - timer->setInterval(duration); - timer->setSingleShot(true); - QState *timing = new QState(this); - QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn())); - QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start())); - QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff())); - QFinalState *done = new QFinalState(this); - timing->addTransition(timer, SIGNAL(timeout()), done); - setInitialState(timing); - } -}; -//! [1] - -//! [2] class TrafficLightWidget : public QWidget { public: @@ -139,6 +118,24 @@ private: LightWidget *m_yellow; LightWidget *m_green; }; +//! [1] + +//! [2] +QState *createLightState(LightWidget *light, int duration, QState *parent = 0) +{ + QState *lightState = new QState(parent); + QTimer *timer = new QTimer(lightState); + timer->setInterval(duration); + timer->setSingleShot(true); + QState *timing = new QState(lightState); + QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn())); + QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start())); + QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff())); + QFinalState *done = new QFinalState(lightState); + timing->addTransition(timer, SIGNAL(timeout()), done); + lightState->setInitialState(timing); + return lightState; +} //! [2] //! [3] @@ -154,15 +151,15 @@ public: vbox->setMargin(0); QStateMachine *machine = new QStateMachine(this); - LightState *redGoingYellow = new LightState(widget->redLight(), 3000); + QState *redGoingYellow = createLightState(widget->redLight(), 3000); redGoingYellow->setObjectName("redGoingYellow"); - LightState *yellowGoingGreen = new LightState(widget->yellowLight(), 1000); + QState *yellowGoingGreen = createLightState(widget->yellowLight(), 1000); yellowGoingGreen->setObjectName("yellowGoingGreen"); redGoingYellow->addTransition(redGoingYellow, SIGNAL(finished()), yellowGoingGreen); - LightState *greenGoingYellow = new LightState(widget->greenLight(), 3000); + QState *greenGoingYellow = createLightState(widget->greenLight(), 3000); greenGoingYellow->setObjectName("greenGoingYellow"); yellowGoingGreen->addTransition(yellowGoingGreen, SIGNAL(finished()), greenGoingYellow); - LightState *yellowGoingRed = new LightState(widget->yellowLight(), 1000); + QState *yellowGoingRed = createLightState(widget->yellowLight(), 1000); yellowGoingRed->setObjectName("yellowGoingRed"); greenGoingYellow->addTransition(greenGoingYellow, SIGNAL(finished()), yellowGoingRed); yellowGoingRed->addTransition(yellowGoingRed, SIGNAL(finished()), redGoingYellow); diff --git a/examples/statemachine/twowaybutton/main.cpp b/examples/statemachine/twowaybutton/main.cpp index 61a0f32..a2c6e45 100644 --- a/examples/statemachine/twowaybutton/main.cpp +++ b/examples/statemachine/twowaybutton/main.cpp @@ -45,34 +45,42 @@ #include <qstatemachine.h> #endif +//! [0] int main(int argc, char **argv) { QApplication app(argc, argv); - QPushButton button; - QStateMachine machine; - QState *first = new QState(); - first->setObjectName("first"); +//! [0] +//! [1] QState *off = new QState(); off->assignProperty(&button, "text", "Off"); off->setObjectName("off"); - first->addTransition(off); QState *on = new QState(); on->setObjectName("on"); on->assignProperty(&button, "text", "On"); +//! [1] + +//! [2] off->addTransition(&button, SIGNAL(clicked()), on); on->addTransition(&button, SIGNAL(clicked()), off); +//! [2] - machine.addState(first); +//! [3] machine.addState(off); machine.addState(on); - machine.setInitialState(first); +//! [3] + +//! [4] + machine.setInitialState(off); machine.start(); +//! [4] +//! [5] button.resize(100, 50); button.show(); return app.exec(); } +//! [5] diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 3a3bfc3..f1528b8 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -327,6 +327,8 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) } } transition->setParent(this); + if (machine() != 0 && machine()->configuration().contains(this)) + QStateMachinePrivate::get(machine())->registerTransitions(this); return transition; } diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 42e965a..52b0a89 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1341,8 +1341,10 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio sender->metaObject()->className(), signal.constData()); return; } - QList<int> &connectedSignalIndexes = connections[sender]; - if (!connectedSignalIndexes.contains(signalIndex)) { + QVector<int> &connectedSignalIndexes = connections[sender]; + if (connectedSignalIndexes.size() <= signalIndex) + connectedSignalIndexes.resize(signalIndex+1); + if (connectedSignalIndexes.at(signalIndex) == 0) { #ifndef QT_STATEMACHINE_SOLUTION if (!signalEventGenerator) signalEventGenerator = new QSignalEventGenerator(q); @@ -1359,8 +1361,8 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio #endif return; } - connectedSignalIndexes.append(signalIndex); } + ++connectedSignalIndexes[signalIndex]; QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex; #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": added signal transition from" << transition->sourceState() @@ -1375,17 +1377,20 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit if (signalIndex == -1) return; // not registered #ifndef QT_STATEMACHINE_SOLUTION + QSignalTransitionPrivate::get(transition)->signalIndex = -1; const QObject *sender = QSignalTransitionPrivate::get(transition)->sender; - QList<int> &connectedSignalIndexes = connections[sender]; - Q_ASSERT(connectedSignalIndexes.contains(signalIndex)); - Q_ASSERT(signalEventGenerator != 0); - bool ok = QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, - signalEventGenerator->metaObject()->methodOffset()); - if (ok) { - connectedSignalIndexes.removeOne(signalIndex); - if (connectedSignalIndexes.isEmpty()) + QVector<int> &connectedSignalIndexes = connections[sender]; + Q_ASSERT(connectedSignalIndexes.size() > signalIndex); + Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0); + if (--connectedSignalIndexes[signalIndex] == 0) { + Q_ASSERT(signalEventGenerator != 0); + QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, + signalEventGenerator->metaObject()->methodOffset()); + int sum = 0; + for (int i = 0; i < connectedSignalIndexes.size(); ++i) + sum += connectedSignalIndexes.at(i); + if (sum == 0) connections.remove(sender); - QSignalTransitionPrivate::get(transition)->signalIndex = -1; } #endif } @@ -1450,8 +1455,8 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex, void **argv) { - const QList<int> &connectedSignalIndexes = connections[sender]; - Q_ASSERT(connectedSignalIndexes.contains(signalIndex)); + const QVector<int> &connectedSignalIndexes = connections[sender]; + Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0); const QMetaObject *meta = sender->metaObject(); QMetaMethod method = meta->method(signalIndex); QList<QByteArray> parameterTypes = method.parameterTypes(); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 47b139c..4bf9ce2 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -61,6 +61,7 @@ #include <QtCore/qlist.h> #include <QtCore/qpair.h> #include <QtCore/qset.h> +#include <QtCore/qvector.h> #include "qstate.h" #include "qstate_p.h" @@ -202,7 +203,7 @@ public: #ifndef QT_STATEMACHINE_SOLUTION QSignalEventGenerator *signalEventGenerator; #endif - QHash<const QObject*, QList<int> > connections; + QHash<const QObject*, QVector<int> > connections; #ifndef QT_NO_STATEMACHINE_EVENTFILTER QHash<QObject*, QSet<QEvent::Type> > qobjectEvents; #endif diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index ce4b443..5ff2acf 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2791,7 +2791,6 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine) return; // Notify the item that the transformation matrix is changing. - // Notify the item that the matrix is changing. QVariant newTransformVariant(itemChange(ItemMatrixChange, qVariantFromValue<QMatrix>(newTransform.toAffine()))); newTransform = QTransform(qVariantValue<QMatrix>(newTransformVariant)); diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index d4552e3..d1fd0da 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -115,6 +115,7 @@ public: class QAccessibleLineEdit : public QAccessibleWidgetEx, public QAccessibleTextInterface, public QAccessibleSimpleEditableTextInterface { + Q_ACCESSIBLE_OBJECT public: explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 9058cb6..3f94ad9 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -1711,6 +1711,51 @@ void tst_QStateMachine::signalTransitions() QTRY_COMPARE(finishedSpy.count(), 1); } + // Multiple transitions for same (object,signal) + { + QStateMachine machine; + SignalEmitter emitter; + QState *s0 = new QState(machine.rootState()); + QState *s1 = new QState(machine.rootState()); + QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); + QSignalTransition *t1 = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s0); + + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + machine.setInitialState(s0); + machine.start(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + + s0->removeTransition(t0); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s1->removeTransition(t1); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s0)); + + s0->addTransition(t0); + s1->addTransition(t1); + emitter.emitSignalWithNoArg(); + QCoreApplication::processEvents(); + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + } } void tst_QStateMachine::eventTransitions() |