From 0f8de3b0b4ccccbeba97999635eb5716f561fb30 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 30 Apr 2009 09:13:44 +0200 Subject: Add two AIs: They are both designed to do the same. Spin until they see a tank and then fire. One of them has an error, which causes it to enter its error state. The errorstate example has been changed to handle this by disabling the tank. The rest of the tanks will keep working. --- examples/statemachine/errorstate/gameitem.h | 5 -- examples/statemachine/errorstate/mainwindow.cpp | 19 ++++++-- examples/statemachine/errorstate/plugin.h | 2 + examples/statemachine/errorstate/rocketitem.cpp | 9 ++-- examples/statemachine/errorstate/rocketitem.h | 5 +- examples/statemachine/errorstate/tankitem.cpp | 56 ++++++++++++++++++---- examples/statemachine/errorstate/tankitem.h | 10 ++++ .../errorstateplugins/errorstateplugins.pro | 10 ++++ .../errorstateplugins/spin_ai/spin_ai.cpp | 29 +++++++++++ .../errorstateplugins/spin_ai/spin_ai.h | 44 +++++++++++++++++ .../errorstateplugins/spin_ai/spin_ai.pro | 13 +++++ .../spin_ai_with_error/spin_ai_with_error.cpp | 29 +++++++++++ .../spin_ai_with_error/spin_ai_with_error.h | 44 +++++++++++++++++ .../spin_ai_with_error/spin_ai_with_error.pro | 13 +++++ 14 files changed, 262 insertions(+), 26 deletions(-) create mode 100644 examples/statemachine/errorstateplugins/errorstateplugins.pro create mode 100644 examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp create mode 100644 examples/statemachine/errorstateplugins/spin_ai/spin_ai.h create mode 100644 examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro create mode 100644 examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp create mode 100644 examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h create mode 100644 examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/errorstate/gameitem.h index 6ca32b7..9808706 100644 --- a/examples/statemachine/errorstate/gameitem.h +++ b/examples/statemachine/errorstate/gameitem.h @@ -7,13 +7,8 @@ class QLineF; class GameItem: public QGraphicsItem { public: - enum { Type = UserType + 1 }; - - int type() const { return Type; } virtual void idle(qreal elapsed) = 0; - virtual void hitByRocket() = 0; - protected: QPointF tryMove(const QPointF &requestedPosition, QLineF *collidedLine = 0, QGraphicsItem **collidedItem = 0) const; diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp index e04ca94..daf7be0 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/errorstate/mainwindow.cpp @@ -105,6 +105,7 @@ void MainWindow::init() QAction *addTankAction = menuBar()->addAction("&Add tank"); QAction *runGameAction = menuBar()->addAction("&Run game"); + runGameAction->setObjectName("runGameAction"); QAction *stopGameAction = menuBar()->addAction("&Stop game"); menuBar()->addSeparator(); QAction *quitAction = menuBar()->addAction("&Quit"); @@ -112,9 +113,7 @@ void MainWindow::init() connect(addTankAction, SIGNAL(triggered()), this, SLOT(addTank())); connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); - m_machine = new QStateMachine(this); - m_machine->setGlobalRestorePolicy(QStateMachine::RestoreProperties); - + m_machine = new QStateMachine(this); QState *stoppedState = new QState(m_machine->rootState()); stoppedState->setObjectName("stoppedState"); stoppedState->assignProperty(runGameAction, "enabled", true); @@ -168,7 +167,11 @@ void MainWindow::runStep() qreal elapsedSecs = elapsed / 1000.0; QList items = m_scene->items(); foreach (QGraphicsItem *item, items) { - GameItem *gameItem = qgraphicsitem_cast(item); + // ### + GameItem *gameItem = qgraphicsitem_cast(item); + if (gameItem == 0) + gameItem = qgraphicsitem_cast(item); + if (gameItem != 0) gameItem->idle(elapsedSecs); } @@ -206,7 +209,13 @@ void MainWindow::addTank() emit mapFull(); QState *region = new QState(m_runningState); - region->setInitialState(plugin->create(region, tankItem)); + QState *pluginState = plugin->create(region, tankItem); + region->setInitialState(pluginState); + + // If the plugin has an error it is disabled + QState *errorState = new QState(region); + errorState->assignProperty(tankItem, "enabled", false); + pluginState->setErrorState(errorState); } } diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/errorstate/plugin.h index 1ac7e0f..69b9574 100644 --- a/examples/statemachine/errorstate/plugin.h +++ b/examples/statemachine/errorstate/plugin.h @@ -1,6 +1,8 @@ #ifndef PLUGIN_H #define PLUGIN_H +#include + class QState; class Tank; class Plugin diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/errorstate/rocketitem.cpp index de9eef7..85d436b 100644 --- a/examples/statemachine/errorstate/rocketitem.cpp +++ b/examples/statemachine/errorstate/rocketitem.cpp @@ -1,4 +1,5 @@ #include "rocketitem.h" +#include "tankitem.h" #include #include @@ -25,10 +26,6 @@ void RocketItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWid painter->drawEllipse(boundingRect()); } -void RocketItem::hitByRocket() -{ -} - void RocketItem::idle(qreal elapsed) { qreal dist = elapsed * speed(); @@ -51,8 +48,8 @@ void RocketItem::idle(qreal elapsed) if (requestedPosition == nextPosition) { setPos(nextPosition); } else { - if (GameItem *gameItem = qgraphicsitem_cast(collidedItem)) - gameItem->hitByRocket(); + if (TankItem *tankItem = qgraphicsitem_cast(collidedItem)) + tankItem->hitByRocket(); scene()->removeItem(this); delete this; diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/errorstate/rocketitem.h index 9805a8a..b055b0a 100644 --- a/examples/statemachine/errorstate/rocketitem.h +++ b/examples/statemachine/errorstate/rocketitem.h @@ -6,13 +6,14 @@ class RocketItem: public GameItem { public: + enum { Type = UserType + 2 }; + RocketItem(); + int type() const { return Type; } virtual void idle(qreal elapsed); qreal speed() const { return 100.0; } void setDirection(qreal direction) { m_direction = direction; } - - void hitByRocket(); protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index 814de2b..705623c 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -85,17 +85,25 @@ private: bool m_reverse; }; -TankItem::TankItem(QObject *parent) : Tank(parent), m_currentAction(0), m_currentDirection(0.0) +TankItem::TankItem(QObject *parent) + : Tank(parent), m_currentAction(0), m_currentDirection(0.0), m_enabled(true) { connect(this, SIGNAL(fireCannon()), this, SIGNAL(actionCompleted())); } void TankItem::idle(qreal elapsed) { - if (m_currentAction != 0) { - if (!m_currentAction->apply(elapsed)) { - setAction(0); - emit actionCompleted(); + if (m_enabled) { + if (m_currentAction != 0) { + if (!m_currentAction->apply(elapsed)) { + setAction(0); + emit actionCompleted(); + } + + QGraphicsItem *item = 0; + qreal distance = distanceToObstacle(&item); + if (TankItem *tankItem = qgraphicsitem_cast(item)) + emit tankSpotted(tankItem->direction(), distance); } } } @@ -176,6 +184,17 @@ void TankItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge QPointF(brect.right() - 2.0, brect.bottom())); painter->fillRect(rightTrackRect, Qt::darkYellow); painter->drawRect(rightTrackRect); + + if (!m_enabled) { + painter->setPen(QPen(Qt::red, 5)); + + painter->drawEllipse(brect); + + QPainterPath path; + path.addEllipse(brect); + painter->setClipPath(path); + painter->drawLine(brect.topRight(), brect.bottomLeft()); + } } QRectF TankItem::boundingRect() const @@ -195,11 +214,32 @@ void TankItem::setDirection(qreal newDirection) rotate(diff); } -qreal TankItem::distanceToObstacle() const +qreal TankItem::distanceToObstacle(QGraphicsItem **obstacle) const { - // ### + qreal dist = sqrt(pow(scene()->sceneRect().width(), 2) + pow(scene()->sceneRect().height(), 2)); + + qreal a = m_currentDirection * M_PI / 180.0; + + qreal yd = dist * sin(a); + qreal xd = dist * sin(M_PI / 2.0 - a); - return 0.0; + QPointF requestedPosition = pos() + QPointF(xd, yd); + QGraphicsItem *collidedItem = 0; + QPointF nextPosition = tryMove(requestedPosition, 0, &collidedItem); + if (collidedItem != 0) { + if (obstacle != 0) + *obstacle = collidedItem; + + QPointF d = nextPosition - pos(); + return sqrt(pow(d.x(), 2) + pow(d.y(), 2)); + } else { + return 0.0; + } +} + +qreal TankItem::distanceToObstacle() const +{ + return distanceToObstacle(0); } diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h index c9e0d22..e598cfd 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/errorstate/tankitem.h @@ -10,8 +10,13 @@ class Action; class TankItem: public Tank, public GameItem { Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) public: + enum { Type = UserType + 1 }; + TankItem(QObject *parent = 0); + + int type() const { return Type; } virtual void moveForwards(qreal length); virtual void moveBackwards(qreal length); @@ -19,6 +24,7 @@ public: virtual void stop(); virtual qreal direction() const; virtual qreal distanceToObstacle() const; + virtual qreal distanceToObstacle(QGraphicsItem **item) const; void setColor(const QColor &color) { m_color = color; } QColor color() const { return m_color; } @@ -33,6 +39,9 @@ public: void hitByRocket(); + void setEnabled(bool b) { m_enabled = b; } + bool enabled() const { return m_enabled; } + signals: virtual void fireCannon(); @@ -46,6 +55,7 @@ private: Action *m_currentAction; qreal m_currentDirection; QColor m_color; + bool m_enabled; }; #endif diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro new file mode 100644 index 0000000..e7718a9 --- /dev/null +++ b/examples/statemachine/errorstateplugins/errorstateplugins.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs +SUBDIRS = random_ai \ + spin_ai_with_error \ + spin_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/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp new file mode 100644 index 0000000..8452523 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp @@ -0,0 +1,29 @@ +#include "spin_ai.h" + +#include + +QState *SpinAi::create(QState *parentState, Tank *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + fireState->setInitialState(fireOnce); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai, SpinAi) diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h new file mode 100644 index 0000000..7336640 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_H +#define SPIN_AI_H + +#include +#include + +#include +#include + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->turn(90.0); + } + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + Tank *m_tank; + +}; + +class SpinAi: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, Tank *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro new file mode 100644 index 0000000..c2fd937 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai.h +SOURCES = spin_ai.cpp +TARGET = $$qtLibraryTarget(spin_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/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 diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp new file mode 100644 index 0000000..dd73270 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp @@ -0,0 +1,29 @@ +#include "spin_ai_with_error.h" + +#include + +QState *SpinAiWithError::create(QState *parentState, Tank *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + // (no initial state set for fireState will lead to run-time error in machine) + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai_with_error, SpinAiWithError) diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h new file mode 100644 index 0000000..26def66 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_WITH_ERROR_H +#define SPIN_AI_WITH_ERROR_H + +#include +#include + +#include +#include + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->turn(90.0); + } + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + Tank *m_tank; + +}; + +class SpinAiWithError: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, Tank *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro new file mode 100644 index 0000000..31f4c7f --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai_with_error.h +SOURCES = spin_ai_with_error.cpp +TARGET = $$qtLibraryTarget(spin_ai_with_error) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/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 -- cgit v0.12 From 0d33e6e464c324d1b43b08ce7ac0dcd4c216d17e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 30 Apr 2009 09:43:13 +0200 Subject: Make design better. Remove the Tank interface. This is now an implicit interface based on the meta-object system. --- examples/statemachine/errorstate/errorstate.pro | 2 +- examples/statemachine/errorstate/gameitem.cpp | 4 +++ examples/statemachine/errorstate/gameitem.h | 8 ++++- examples/statemachine/errorstate/mainwindow.cpp | 9 ++---- examples/statemachine/errorstate/plugin.h | 3 +- examples/statemachine/errorstate/rocketitem.cpp | 11 ++++--- examples/statemachine/errorstate/rocketitem.h | 7 ++-- examples/statemachine/errorstate/tank.h | 31 ------------------ examples/statemachine/errorstate/tankitem.cpp | 9 ++++-- examples/statemachine/errorstate/tankitem.h | 37 ++++++++++++---------- .../random_ai/random_ai_plugin.cpp | 4 +-- .../errorstateplugins/random_ai/random_ai_plugin.h | 2 +- .../errorstateplugins/spin_ai/spin_ai.cpp | 2 +- .../errorstateplugins/spin_ai/spin_ai.h | 10 +++--- .../spin_ai_with_error/spin_ai_with_error.cpp | 2 +- .../spin_ai_with_error/spin_ai_with_error.h | 10 +++--- 16 files changed, 65 insertions(+), 86 deletions(-) delete mode 100644 examples/statemachine/errorstate/tank.h diff --git a/examples/statemachine/errorstate/errorstate.pro b/examples/statemachine/errorstate/errorstate.pro index c159f94..b93a691 100644 --- a/examples/statemachine/errorstate/errorstate.pro +++ b/examples/statemachine/errorstate/errorstate.pro @@ -8,6 +8,6 @@ DEPENDPATH += . INCLUDEPATH += C:/dev/kinetic/examples/statemachine/errorstate/. . # Input -HEADERS += mainwindow.h plugin.h tank.h tankitem.h rocketitem.h gameitem.h +HEADERS += mainwindow.h plugin.h tankitem.h rocketitem.h gameitem.h SOURCES += main.cpp mainwindow.cpp tankitem.cpp rocketitem.cpp gameitem.cpp CONFIG += console diff --git a/examples/statemachine/errorstate/gameitem.cpp b/examples/statemachine/errorstate/gameitem.cpp index 786cf51..d286df4 100644 --- a/examples/statemachine/errorstate/gameitem.cpp +++ b/examples/statemachine/errorstate/gameitem.cpp @@ -2,6 +2,10 @@ #include +GameItem::GameItem(QObject *parent) : QObject(parent) +{ +} + QPointF GameItem::tryMove(const QPointF &requestedPosition, QLineF *collidedLine, QGraphicsItem **collidedItem) const { diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/errorstate/gameitem.h index 9808706..43b8785 100644 --- a/examples/statemachine/errorstate/gameitem.h +++ b/examples/statemachine/errorstate/gameitem.h @@ -4,9 +4,15 @@ #include class QLineF; -class GameItem: public QGraphicsItem +class GameItem: public QObject, public QGraphicsItem { + Q_OBJECT public: + enum { Type = UserType + 1 }; + int type() const { return Type; } + + GameItem(QObject *parent = 0); + virtual void idle(qreal elapsed) = 0; protected: diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp index daf7be0..4d9b88e 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/errorstate/mainwindow.cpp @@ -167,12 +167,7 @@ void MainWindow::runStep() qreal elapsedSecs = elapsed / 1000.0; QList items = m_scene->items(); foreach (QGraphicsItem *item, items) { - // ### - GameItem *gameItem = qgraphicsitem_cast(item); - if (gameItem == 0) - gameItem = qgraphicsitem_cast(item); - - if (gameItem != 0) + if (GameItem *gameItem = qgraphicsitem_cast(item)) gameItem->idle(elapsedSecs); } } @@ -204,7 +199,7 @@ void MainWindow::addTank() if (plugin != 0) { TankItem *tankItem = m_spawns.takeLast(); m_scene->addItem(tankItem); - connect(tankItem, SIGNAL(fireCannon()), this, SLOT(addRocket())); + connect(tankItem, SIGNAL(cannonFired()), this, SLOT(addRocket())); if (m_spawns.isEmpty()) emit mapFull(); diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/errorstate/plugin.h index 69b9574..2b48d43 100644 --- a/examples/statemachine/errorstate/plugin.h +++ b/examples/statemachine/errorstate/plugin.h @@ -4,13 +4,12 @@ #include class QState; -class Tank; class Plugin { public: virtual ~Plugin() {} - virtual QState *create(QState *parentState, Tank *tank) = 0; + virtual QState *create(QState *parentState, QObject *tank) = 0; }; Q_DECLARE_INTERFACE(Plugin, "TankPlugin") diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/errorstate/rocketitem.cpp index 85d436b..c324980 100644 --- a/examples/statemachine/errorstate/rocketitem.cpp +++ b/examples/statemachine/errorstate/rocketitem.cpp @@ -10,8 +10,8 @@ #define M_PI 3.14159265358979323846 #endif -RocketItem::RocketItem() - : m_direction(0.0), m_distance(300.0) +RocketItem::RocketItem(QObject *parent) + : GameItem(parent), m_direction(0.0), m_distance(300.0) { } @@ -48,8 +48,11 @@ void RocketItem::idle(qreal elapsed) if (requestedPosition == nextPosition) { setPos(nextPosition); } else { - if (TankItem *tankItem = qgraphicsitem_cast(collidedItem)) - tankItem->hitByRocket(); + if (GameItem *gameItem = qgraphicsitem_cast(collidedItem)) { + TankItem *tankItem = qobject_cast(gameItem); + if (tankItem != 0) + tankItem->hitByRocket(); + } scene()->removeItem(this); delete this; diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/errorstate/rocketitem.h index b055b0a..189a1dd 100644 --- a/examples/statemachine/errorstate/rocketitem.h +++ b/examples/statemachine/errorstate/rocketitem.h @@ -5,12 +5,10 @@ class RocketItem: public GameItem { + Q_OBJECT public: - enum { Type = UserType + 2 }; + RocketItem(QObject *parent = 0); - RocketItem(); - - int type() const { return Type; } virtual void idle(qreal elapsed); qreal speed() const { return 100.0; } void setDirection(qreal direction) { m_direction = direction; } @@ -19,7 +17,6 @@ protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); QRectF boundingRect() const; - private: qreal m_direction; qreal m_distance; diff --git a/examples/statemachine/errorstate/tank.h b/examples/statemachine/errorstate/tank.h deleted file mode 100644 index 49c5daf..0000000 --- a/examples/statemachine/errorstate/tank.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef TANK_H -#define TANK_H - -#include -#include - -class Tank: public QObject -{ - Q_OBJECT - Q_PROPERTY(qreal direction READ direction) - Q_PROPERTY(qreal distanceToObstacle READ distanceToObstacle) -public: - Tank(QObject *parent = 0) : QObject(parent) {} - - virtual qreal direction() const = 0; - virtual qreal distanceToObstacle() const = 0; - -signals: - void collision(const QLineF &collidedLine) const; - void actionCompleted(); - void tankSpotted(qreal otherTankDirection, qreal distance); - -public slots: - virtual void moveForwards(qreal length) = 0; - virtual void moveBackwards(qreal length) = 0; - virtual void turn(qreal degrees) = 0; - virtual void stop() = 0; - virtual void fireCannon() = 0; -}; - -#endif diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index 705623c..ae338fe 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -86,9 +86,9 @@ private: }; TankItem::TankItem(QObject *parent) - : Tank(parent), m_currentAction(0), m_currentDirection(0.0), m_enabled(true) + : GameItem(parent), m_currentAction(0), m_currentDirection(0.0), m_enabled(true) { - connect(this, SIGNAL(fireCannon()), this, SIGNAL(actionCompleted())); + connect(this, SIGNAL(cannonFired()), this, SIGNAL(actionCompleted())); } void TankItem::idle(qreal elapsed) @@ -121,6 +121,11 @@ void TankItem::setAction(Action *newAction) m_currentAction = newAction; } +void TankItem::fireCannon() +{ + emit cannonFired(); +} + void TankItem::moveForwards(qreal length) { setAction(new MoveAction(this, length)); diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h index e598cfd..45016ec 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/errorstate/tankitem.h @@ -1,31 +1,20 @@ #ifndef TANKITEM_H #define TANKITEM_H -#include "tank.h" #include "gameitem.h" #include class Action; -class TankItem: public Tank, public GameItem +class TankItem: public GameItem { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) -public: - enum { Type = UserType + 1 }; - + Q_PROPERTY(qreal direction READ direction WRITE turn) + Q_PROPERTY(qreal distanceToObstacle READ distanceToObstacle) +public: TankItem(QObject *parent = 0); - - int type() const { return Type; } - - virtual void moveForwards(qreal length); - virtual void moveBackwards(qreal length); - virtual void turn(qreal newDirection); - virtual void stop(); - virtual qreal direction() const; - virtual qreal distanceToObstacle() const; - virtual qreal distanceToObstacle(QGraphicsItem **item) const; - + void setColor(const QColor &color) { m_color = color; } QColor color() const { return m_color; } @@ -42,8 +31,22 @@ public: void setEnabled(bool b) { m_enabled = b; } bool enabled() const { return m_enabled; } + qreal direction() const; + qreal distanceToObstacle() const; + qreal distanceToObstacle(QGraphicsItem **item) const; + signals: - virtual void fireCannon(); + void tankSpotted(qreal direction, qreal distance); + void collision(const QLineF &collidedLine); + void actionCompleted(); + void cannonFired(); + +public slots: + void moveForwards(qreal length); + void moveBackwards(qreal length); + void turn(qreal newDirection); + void stop(); + void fireCannon(); protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp index 135c7b6..c196247 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp @@ -1,13 +1,11 @@ #include "random_ai_plugin.h" -#include - #include #include #include -QState *RandomAiPlugin::create(QState *parentState, Tank *tank) +QState *RandomAiPlugin::create(QState *parentState, QObject *tank) { qsrand(uint(time(NULL))); diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h index 758b3e8..d3670bd 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h @@ -56,7 +56,7 @@ class RandomAiPlugin: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: - virtual QState *create(QState *parentState, Tank *tank); + virtual QState *create(QState *parentState, QObject *tank); }; #endif // RANDOM_AI_PLUGIN_H diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp index 8452523..de95f41 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp @@ -2,7 +2,7 @@ #include -QState *SpinAi::create(QState *parentState, Tank *tank) +QState *SpinAi::create(QState *parentState, QObject *tank) { QState *topLevel = new QState(parentState); QState *spinState = new SpinState(tank, topLevel); diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h index 7336640..309ba14 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h @@ -2,23 +2,23 @@ #define SPIN_AI_H #include -#include #include #include +#include class SpinState: public QState { Q_OBJECT public: - SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + SpinState(QObject *tank, QState *parent) : QState(parent), m_tank(tank) { } public slots: void spin() { - m_tank->turn(90.0); + m_tank->setProperty("direction", 90.0); } protected: @@ -29,7 +29,7 @@ protected: } private: - Tank *m_tank; + QObject *m_tank; }; @@ -38,7 +38,7 @@ class SpinAi: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: - virtual QState *create(QState *parentState, Tank *tank); + virtual QState *create(QState *parentState, QObject *tank); }; #endif diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp index dd73270..5499ba3 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp @@ -2,7 +2,7 @@ #include -QState *SpinAiWithError::create(QState *parentState, Tank *tank) +QState *SpinAiWithError::create(QState *parentState, QObject *tank) { QState *topLevel = new QState(parentState); QState *spinState = new SpinState(tank, topLevel); diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h index 26def66..fa06d10 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h @@ -2,23 +2,23 @@ #define SPIN_AI_WITH_ERROR_H #include -#include #include #include +#include class SpinState: public QState { Q_OBJECT public: - SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + SpinState(QObject *tank, QState *parent) : QState(parent), m_tank(tank) { } public slots: void spin() { - m_tank->turn(90.0); + m_tank->setProperty("direction", 90.0); } protected: @@ -29,7 +29,7 @@ protected: } private: - Tank *m_tank; + QObject *m_tank; }; @@ -38,7 +38,7 @@ class SpinAiWithError: public QObject, public Plugin Q_OBJECT Q_INTERFACES(Plugin) public: - virtual QState *create(QState *parentState, Tank *tank); + virtual QState *create(QState *parentState, QObject *tank); }; #endif -- cgit v0.12 From 9e6311a7fd23a9fb7bb3a8a8edc78cddddc3f807 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 30 Apr 2009 09:49:09 +0200 Subject: The intuitive interpretation of RestoreProperties is that a value is potentially restored once the state that set it is exited. So if you have a parent state P which sets 'foo' and then several child states of P, the property should not be restored as long as P is active, regardless of which transitions are taken inside P and what properties are being assigned there. Before, we would restore the property when we entered a state that did not assign it, ignoring what properties where being assigned in the parent. --- src/corelib/statemachine/qstatemachine.cpp | 11 +++++ tests/auto/qstatemachine/tst_qstatemachine.cpp | 56 +++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 9060f0e..81d65d5 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -656,6 +656,17 @@ void QStateMachinePrivate::applyProperties(const QList &tr pendingRestorables.remove(RestorableId(assn.object, assn.propertyName)); propertyAssignmentsForState[s].append(assn); } + + // Remove pending restorables for all parent states to avoid restoring properties + // before the state that assigned them is exited. + QState *parentState = s; + while (parentState = parentState->parentState()) { + assignments = QStatePrivate::get(parentState)->propertyAssignments; + for (int j=0; jsetProperty("foo", 1); + propertyHolder->setProperty("bar", 2); + + QState *s1 = new QState(machine.rootState()); + machine.setInitialState(s1); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(propertyHolder, "foo", 3); + + QState *s21 = new QState(s2); + s21->assignProperty(propertyHolder, "bar", 4); + s2->setInitialState(s21); + + QState *s22 = new QState(s2); + s22->assignProperty(propertyHolder, "bar", 5); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + s21->addTransition(new EventTransition(QEvent::User, s22)); + + machine.start(); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + QCOMPARE(propertyHolder->property("foo").toInt(), 1); + QCOMPARE(propertyHolder->property("bar").toInt(), 2); + + machine.postEvent(new QEvent(QEvent::User)); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 2); + QVERIFY(machine.configuration().contains(s2)); + QVERIFY(machine.configuration().contains(s21)); + QCOMPARE(propertyHolder->property("foo").toInt(), 3); + QCOMPARE(propertyHolder->property("bar").toInt(), 4); + + machine.postEvent(new QEvent(QEvent::User)); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 2); + QVERIFY(machine.configuration().contains(s2)); + QVERIFY(machine.configuration().contains(s22)); + QCOMPARE(propertyHolder->property("foo").toInt(), 3); + QCOMPARE(propertyHolder->property("bar").toInt(), 5); +} + + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" -- cgit v0.12 From 18e848faad9289f6052249ef4fe6a20f0654b786 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 30 Apr 2009 10:09:09 +0200 Subject: When restoring properties in descendants of a state which assigns it a value, the property should be restored to the value assigned by the ancestor state. When restoreProperties is on, assigning a value in a state means it will have that value as long as the state is active, unless an active state deeper in the hierarchy assigns it a different value. This is basically a stack of "initial" values, but implemented using the parent hierarchy of the state instead. --- src/corelib/statemachine/qstatemachine.cpp | 7 ++- tests/auto/qstatemachine/tst_qstatemachine.cpp | 64 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 81d65d5..0ebc993 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -658,13 +658,16 @@ void QStateMachinePrivate::applyProperties(const QList &tr } // Remove pending restorables for all parent states to avoid restoring properties - // before the state that assigned them is exited. + // before the state that assigned them is exited. If state does not explicitly + // assign a property which is assigned by the parent, it inherits the parent's assignment. QState *parentState = s; while (parentState = parentState->parentState()) { assignments = QStatePrivate::get(parentState)->propertyAssignments; for (int j=0; j 0) + propertyAssignmentsForState[s].append(assn); } } } diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index fa4c233..80bf674 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -141,6 +141,7 @@ private slots: void parallelStateTransition(); void parallelStateAssignmentsDone(); void nestedRestoreProperties(); + void nestedRestoreProperties2(); void simpleAnimation(); void twoAnimations(); @@ -3162,6 +3163,69 @@ void tst_QStateMachine::nestedRestoreProperties() QCOMPARE(propertyHolder->property("bar").toInt(), 5); } +void tst_QStateMachine::nestedRestoreProperties2() +{ + QStateMachine machine; + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); + + QObject *propertyHolder = new QObject(&machine); + propertyHolder->setProperty("foo", 1); + propertyHolder->setProperty("bar", 2); + + QState *s1 = new QState(machine.rootState()); + machine.setInitialState(s1); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(propertyHolder, "foo", 3); + + QState *s21 = new QState(s2); + s21->assignProperty(propertyHolder, "bar", 4); + s2->setInitialState(s21); + + QState *s22 = new QState(s2); + s22->assignProperty(propertyHolder, "foo", 6); + s22->assignProperty(propertyHolder, "bar", 5); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + s21->addTransition(new EventTransition(QEvent::User, s22)); + s22->addTransition(new EventTransition(QEvent::User, s21)); + + machine.start(); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 1); + QVERIFY(machine.configuration().contains(s1)); + QCOMPARE(propertyHolder->property("foo").toInt(), 1); + QCOMPARE(propertyHolder->property("bar").toInt(), 2); + + machine.postEvent(new QEvent(QEvent::User)); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 2); + QVERIFY(machine.configuration().contains(s2)); + QVERIFY(machine.configuration().contains(s21)); + QCOMPARE(propertyHolder->property("foo").toInt(), 3); + QCOMPARE(propertyHolder->property("bar").toInt(), 4); + + machine.postEvent(new QEvent(QEvent::User)); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 2); + QVERIFY(machine.configuration().contains(s2)); + QVERIFY(machine.configuration().contains(s22)); + QCOMPARE(propertyHolder->property("foo").toInt(), 6); + QCOMPARE(propertyHolder->property("bar").toInt(), 5); + + machine.postEvent(new QEvent(QEvent::User)); + QCoreApplication::processEvents(); + + QCOMPARE(machine.configuration().size(), 2); + QVERIFY(machine.configuration().contains(s2)); + QVERIFY(machine.configuration().contains(s21)); + QCOMPARE(propertyHolder->property("foo").toInt(), 3); + QCOMPARE(propertyHolder->property("bar").toInt(), 4); + +} QTEST_MAIN(tst_QStateMachine) -- cgit v0.12 From 1e4e05144dd8a0c642b6a7f77aa53fa6975d89d9 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 30 Apr 2009 12:49:14 +0200 Subject: Add unfinished "more advanced" AI for errorstate. --- examples/statemachine/errorstate/tankitem.cpp | 5 + examples/statemachine/errorstate/tankitem.h | 9 +- .../errorstateplugins/errorstateplugins.pro | 3 +- .../errorstateplugins/seek_ai/seek_ai.cpp | 42 ++++++++ .../errorstateplugins/seek_ai/seek_ai.h | 117 +++++++++++++++++++++ .../errorstateplugins/seek_ai/seek_ai.pro | 13 +++ 6 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.h create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index ae338fe..1e02171 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -141,6 +141,11 @@ void TankItem::turn(qreal degrees) setAction(new TurnAction(this, degrees)); } +void TankItem::turnTo(qreal degrees) +{ + setAction(new TurnAction(this, degrees - direction())); +} + void TankItem::stop() { setAction(0); diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h index 45016ec..cefed69 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/errorstate/tankitem.h @@ -10,7 +10,7 @@ class TankItem: public GameItem { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) - Q_PROPERTY(qreal direction READ direction WRITE turn) + Q_PROPERTY(qreal direction READ direction WRITE turnTo) Q_PROPERTY(qreal distanceToObstacle READ distanceToObstacle) public: TankItem(QObject *parent = 0); @@ -42,9 +42,10 @@ signals: void cannonFired(); public slots: - void moveForwards(qreal length); - void moveBackwards(qreal length); - void turn(qreal newDirection); + void moveForwards(qreal length = 10.0); + void moveBackwards(qreal length = 10.0); + void turn(qreal degrees = 30.0); + void turnTo(qreal degrees = 0.0); void stop(); void fireCannon(); diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro index e7718a9..5b6b758 100644 --- a/examples/statemachine/errorstateplugins/errorstateplugins.pro +++ b/examples/statemachine/errorstateplugins/errorstateplugins.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs SUBDIRS = random_ai \ spin_ai_with_error \ - spin_ai + spin_ai \ + seek_ai # install target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp new file mode 100644 index 0000000..229f83a --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp @@ -0,0 +1,42 @@ +#include "seek_ai.h" + +QState *SeekAi::create(QState *parentState, QObject *tank) +{ + QState *topLevel = new QState(parentState); + topLevel->setObjectName("topLevel"); + + QState *seek = new QState(topLevel); + seek->setObjectName("seek"); + topLevel->setInitialState(seek); + + QState *lookForNearestWall = new SearchState(tank, seek); + lookForNearestWall->setObjectName("lookForNearestWall"); + seek->setInitialState(lookForNearestWall); + + QState *driveToFirstObstacle = new QState(seek); + driveToFirstObstacle->setObjectName("driveToFirstObstacle"); + lookForNearestWall->addTransition(lookForNearestWall, SIGNAL(nearestObstacleStraightAhead()), + driveToFirstObstacle); + + QState *drive = new QState(driveToFirstObstacle); + drive->setObjectName("drive"); + driveToFirstObstacle->setInitialState(drive); + connect(drive, SIGNAL(entered()), tank, SLOT(moveForwards())); + connect(drive, SIGNAL(exited()), tank, SLOT(stop())); + + // Go in loop + QState *finishedDriving = new QState(driveToFirstObstacle); + finishedDriving->setObjectName("finishedDriving"); + drive->addTransition(tank, SIGNAL(actionCompleted()), finishedDriving); + finishedDriving->addTransition(drive); + + QState *turnTo = new QState(seek); + turnTo->setObjectName("turnTo"); + driveToFirstObstacle->addTransition(new CollisionTransition(tank, turnTo)); + + turnTo->addTransition(tank, SIGNAL(actionCompleted()), driveToFirstObstacle); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(seek_ai, SeekAi) diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h new file mode 100644 index 0000000..f96a68f --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -0,0 +1,117 @@ +#ifndef SEEK_AI_H +#define SEEK_AI_H + +#include + +#include +#include +#include +#include +#include + +class SearchState: public QState +{ + Q_OBJECT +public: + SearchState(QObject *tank, QState *parentState = 0) + : QState(parentState), + m_tank(tank), + m_distanceToTurn(360.0), + m_nearestDistance(-1.0), + m_directionOfNearestObstacle(0.0) + { + } + +public slots: + void turnAlittle() + { + qreal dist = m_tank->property("distanceToObstacle").toDouble(); + + if (m_nearestDistance < 0.0 || dist < m_nearestDistance) { + m_nearestDistance = dist; + m_directionOfNearestObstacle = m_tank->property("direction").toDouble(); + } + + m_distanceToTurn -= 10.0; + if (m_distanceToTurn < 0.0) { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + connect(m_tank, SIGNAL(actionCompleted()), this, SIGNAL(nearestObstacleStraightAhead())); + m_tank->setProperty("direction", m_directionOfNearestObstacle); + } + + qreal currentDirection = m_tank->property("direction").toDouble(); + m_tank->setProperty("direction", currentDirection + 10.0); + } + +signals: + void nearestObstacleStraightAhead(); + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + turnAlittle(); + } + + void onExit() + { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(nearestObstacleStraightAhead())); + } + +private: + QObject *m_tank; + + qreal m_distanceToTurn; + qreal m_nearestDistance; + qreal m_directionOfNearestObstacle; +}; + +class CollisionTransition: public QSignalTransition +{ +public: + CollisionTransition(QObject *tank, QState *turnTo) + : QSignalTransition(tank, SIGNAL(collision(QLineF)), turnTo), + m_tank(tank), + m_turnTo(turnTo) + { + } + +protected: + bool eventTest(QEvent *event) + { + QSignalEvent *se = static_cast(event); + m_lastLine = se->arguments().at(0).toLineF(); + + return QSignalTransition::eventTest(event); + } + + void onTransition() + { + qreal currentDirection = m_tank->property("direction").toDouble(); + qreal angleOfWall = m_lastLine.angle(); + + qreal newDirection; + if (qAbs(currentDirection - angleOfWall) < qAbs(angleOfWall - currentDirection)) + newDirection = angleOfWall; + else + newDirection = -angleOfWall; + + m_turnTo->assignProperty(m_tank, "direction", newDirection); + } + +private: + QLineF m_lastLine; + QObject *m_tank; + QState *m_turnTo; +}; + +class SeekAi: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, QObject *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro new file mode 100644 index 0000000..11bd242 --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = seek_ai.h +SOURCES = seek_ai.cpp +TARGET = $$qtLibraryTarget(seek_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/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 -- cgit v0.12 From e2cb1fe3f71a0fd74c49af2fc451a1e05ed2742b Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 4 May 2009 15:44:39 +0200 Subject: ignore QState::assignProperty() calls where the target object is 0 --- src/corelib/statemachine/qstate.cpp | 4 ++++ tests/auto/qstatemachine/tst_qstatemachine.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 2d59ab8..a431888 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -235,6 +235,10 @@ void QState::assignProperty(QObject *object, const char *name, const QVariant &value) { Q_D(QState); + if (!object) { + qWarning("QState::assignProperty: cannot assign property '%s' of null object", name); + return; + } for (int i = 0; i < d->propertyAssignments.size(); ++i) { QPropertyAssignment &assn = d->propertyAssignments[i]; if ((assn.object == object) && (assn.propertyName == name)) { diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 80bf674..5dfc758 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -1194,6 +1194,10 @@ void tst_QStateMachine::assignProperty() { QStateMachine machine; QState *s1 = new QState(machine.rootState()); + + QTest::ignoreMessage(QtWarningMsg, "QState::assignProperty: cannot assign property 'foo' of null object"); + s1->assignProperty(0, "foo", QVariant()); + s1->assignProperty(s1, "objectName", "s1"); QFinalState *s2 = new QFinalState(machine.rootState()); s1->addTransition(s2); -- cgit v0.12 From d388730da773c46f228894186c29d330a774b72b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 13:48:24 +0200 Subject: Fix support reverse actions. Logic was broken and would always return false immediately for reverse actions, thus immediately stopping them. --- examples/statemachine/errorstate/tankitem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index 1e02171..fc71ef9 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -41,7 +41,7 @@ public: m_distance -= dist; if (m_reverse && m_distance > 0.0) return false; - else if (m_distance < 0.0) + else if (!m_reverse && m_distance < 0.0) return false; qreal a = item()->direction() * M_PI / 180.0; @@ -73,7 +73,7 @@ public: m_distance -= dist; if (m_reverse && m_distance > 0.0) return false; - else if (m_distance < 0.0) + else if (!m_reverse && m_distance < 0.0) return false; item()->setDirection(item()->direction() + dist); -- cgit v0.12 From 8b4daee4bd6c6dd3da7b7e71b6c468059cf53ea0 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 14:18:55 +0200 Subject: Make sure the correct position/direction is actually set at the end of a loop. Also make sure we set the direction to an angle within 360 degrees. --- examples/statemachine/errorstate/tankitem.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index fc71ef9..5506a7e 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -38,11 +39,12 @@ public: { qreal dist = timeDelta * item()->speed() * (m_reverse ? -1.0 : 1.0); + bool done = false; + if (qAbs(m_distance) < qAbs(dist)) { + done = true; + dist = m_distance; + } m_distance -= dist; - if (m_reverse && m_distance > 0.0) - return false; - else if (!m_reverse && m_distance < 0.0) - return false; qreal a = item()->direction() * M_PI / 180.0; @@ -50,7 +52,7 @@ public: qreal xd = dist * sin(M_PI / 2.0 - a); item()->setPos(item()->pos() + QPointF(xd, yd)); - return true; + return !done; } private: @@ -70,14 +72,15 @@ public: bool apply(qreal timeDelta) { qreal dist = timeDelta * item()->angularSpeed() * (m_reverse ? -1.0 : 1.0); + bool done = false; + if (qAbs(m_distance) < qAbs(dist)) { + done = true; + dist = m_distance; + } m_distance -= dist; - if (m_reverse && m_distance > 0.0) - return false; - else if (!m_reverse && m_distance < 0.0) - return false; item()->setDirection(item()->direction() + dist); - return true; + return !done; } private: @@ -219,6 +222,9 @@ qreal TankItem::direction() const void TankItem::setDirection(qreal newDirection) { + int fullRotations = int(newDirection) / 360; + newDirection -= fullRotations * 360.0; + qreal diff = newDirection - m_currentDirection; m_currentDirection = newDirection; rotate(diff); -- cgit v0.12 From 6de0b13042f39b7570588eb5615cc1e16a71eced Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 14:50:56 +0200 Subject: Set collidedLine for the implicit walls around the scene to allow for collision response. --- examples/statemachine/errorstate/gameitem.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/examples/statemachine/errorstate/gameitem.cpp b/examples/statemachine/errorstate/gameitem.cpp index d286df4..1a2af71 100644 --- a/examples/statemachine/errorstate/gameitem.cpp +++ b/examples/statemachine/errorstate/gameitem.cpp @@ -1,6 +1,7 @@ #include "gameitem.h" #include +#include GameItem::GameItem(QObject *parent) : QObject(parent) { @@ -56,15 +57,31 @@ QPointF GameItem::tryMove(const QPointF &requestedPosition, QLineF *collidedLine } } + // Don't go outside of map - if (nextPoint.x() < sceneRect.left()) + if (nextPoint.x() < sceneRect.left()) { nextPoint.rx() = sceneRect.left(); - if (nextPoint.x() > sceneRect.right()) + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().bottomLeft()); + } + + if (nextPoint.x() > sceneRect.right()) { nextPoint.rx() = sceneRect.right(); - if (nextPoint.y() < sceneRect.top()) + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topRight(), scene()->sceneRect().bottomRight()); + } + + if (nextPoint.y() < sceneRect.top()) { nextPoint.ry() = sceneRect.top(); - if (nextPoint.y() > sceneRect.bottom()) + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().topRight()); + } + + if (nextPoint.y() > sceneRect.bottom()) { nextPoint.ry() = sceneRect.bottom(); + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().bottomLeft(), scene()->sceneRect().bottomRight()); + } return nextPoint; } -- cgit v0.12 From ef2c9e7e6ea543a7ca1ee23b5bbaa9dee5f77b8a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 14:54:04 +0200 Subject: Make sure target state is set correctly. Also make sure eventTest() actually overrides the virtual function. --- examples/statemachine/errorstateplugins/seek_ai/seek_ai.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h index f96a68f..7f108a1 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -8,6 +8,7 @@ #include #include #include +#include class SearchState: public QState { @@ -75,14 +76,16 @@ public: m_tank(tank), m_turnTo(turnTo) { + setTargetState(turnTo); } protected: - bool eventTest(QEvent *event) + bool eventTest(QEvent *event) const { - QSignalEvent *se = static_cast(event); - m_lastLine = se->arguments().at(0).toLineF(); - + if (event->type() == QEvent::Signal) { + QSignalEvent *se = static_cast(event); + m_lastLine = se->arguments().at(0).toLineF(); + } return QSignalTransition::eventTest(event); } @@ -101,7 +104,7 @@ protected: } private: - QLineF m_lastLine; + mutable QLineF m_lastLine; QObject *m_tank; QState *m_turnTo; }; -- cgit v0.12 From 6eae8aedd14acbc4ea73f336124b0243e9ebb9c0 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 15:24:03 +0200 Subject: Add randomness. --- examples/statemachine/errorstateplugins/seek_ai/seek_ai.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h index 7f108a1..83f50a7 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -95,10 +95,10 @@ protected: qreal angleOfWall = m_lastLine.angle(); qreal newDirection; - if (qAbs(currentDirection - angleOfWall) < qAbs(angleOfWall - currentDirection)) + if (qrand() % 2 == 0) newDirection = angleOfWall; else - newDirection = -angleOfWall; + newDirection = angleOfWall - 180.0; m_turnTo->assignProperty(m_tank, "direction", newDirection); } -- cgit v0.12 From 2e0430832d3656753f73b09765769d10aa51add3 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 5 May 2009 18:17:43 +0200 Subject: add event as argument to onEntry(), onExit() and onTransition() Accessing the event can be useful. E.g., onEntry() can do some common event processing regardless of which transition caused the state to be entered; onTransition() can be used in combination with eventTest(), where eventTest() would first check that the input matches some criteria, and then the actual processing of that input would be done in onTransition. --- examples/animation/moveblocks/main.cpp | 6 ++-- examples/animation/sub-attaq/boat_p.h | 12 +++---- examples/animation/sub-attaq/qanimationstate.cpp | 4 +-- examples/animation/sub-attaq/qanimationstate.h | 4 +-- examples/animation/sub-attaq/states.cpp | 16 ++++----- examples/animation/sub-attaq/states.h | 14 ++++---- examples/animation/sub-attaq/submarine_p.h | 12 +++---- examples/statemachine/clockticking/main.cpp | 6 ++-- .../errorstateplugins/random_ai/random_ai_plugin.h | 4 +-- .../errorstateplugins/seek_ai/seek_ai.h | 6 ++-- .../errorstateplugins/spin_ai/spin_ai.h | 2 +- .../spin_ai_with_error/spin_ai_with_error.h | 2 +- examples/statemachine/factorial/main.cpp | 4 +-- examples/statemachine/helloworld/main.cpp | 2 +- examples/statemachine/pingpong/main.cpp | 6 ++-- src/corelib/statemachine/qabstractstate.cpp | 22 ++++++------ src/corelib/statemachine/qabstractstate.h | 4 +-- src/corelib/statemachine/qabstractstate_p.h | 4 +-- src/corelib/statemachine/qabstracttransition.cpp | 11 +++--- src/corelib/statemachine/qabstracttransition.h | 2 +- src/corelib/statemachine/qabstracttransition_p.h | 2 +- src/corelib/statemachine/qeventtransition.cpp | 3 +- src/corelib/statemachine/qeventtransition.h | 2 +- src/corelib/statemachine/qfinalstate.cpp | 6 ++-- src/corelib/statemachine/qfinalstate.h | 4 +-- src/corelib/statemachine/qhistorystate.cpp | 4 +-- src/corelib/statemachine/qhistorystate.h | 4 +-- src/corelib/statemachine/qsignaltransition.cpp | 3 +- src/corelib/statemachine/qsignaltransition.h | 2 +- src/corelib/statemachine/qstate.cpp | 8 +++-- src/corelib/statemachine/qstate.h | 4 +-- src/corelib/statemachine/qstatemachine.cpp | 41 +++++++++++----------- src/corelib/statemachine/qstatemachine_p.h | 8 ++--- src/gui/statemachine/qbasickeyeventtransition.cpp | 2 +- src/gui/statemachine/qbasickeyeventtransition_p.h | 2 +- .../statemachine/qbasicmouseeventtransition.cpp | 2 +- .../statemachine/qbasicmouseeventtransition_p.h | 2 +- src/gui/statemachine/qkeyeventtransition.cpp | 4 +-- src/gui/statemachine/qkeyeventtransition.h | 2 +- src/gui/statemachine/qmouseeventtransition.cpp | 4 +-- src/gui/statemachine/qmouseeventtransition.h | 2 +- tests/auto/qstatemachine/tst_qstatemachine.cpp | 16 ++++----- 42 files changed, 140 insertions(+), 130 deletions(-) diff --git a/examples/animation/moveblocks/main.cpp b/examples/animation/moveblocks/main.cpp index eb23bd5..06ed3dd 100644 --- a/examples/animation/moveblocks/main.cpp +++ b/examples/animation/moveblocks/main.cpp @@ -101,7 +101,7 @@ protected: && (static_cast(event)->rand() == m_rand); } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} private: int m_rand; @@ -116,7 +116,7 @@ public: m_stateCount(0), m_lastIndex(0) { } - virtual void onEntry() + virtual void onEntry(QEvent *) { int n; while ((n = (qrand() % m_stateCount + 1)) == m_lastIndex) @@ -124,7 +124,7 @@ public: m_lastIndex = n; m_machine->postEvent(new StateSwitchEvent(n)); } - virtual void onExit() {} + virtual void onExit(QEvent *) {} void addState(QState *state, QAbstractAnimation *animation) { StateSwitchTransition *trans = new StateSwitchTransition(++m_stateCount); diff --git a/examples/animation/sub-attaq/boat_p.h b/examples/animation/sub-attaq/boat_p.h index 855b10f..17fbe5c 100644 --- a/examples/animation/sub-attaq/boat_p.h +++ b/examples/animation/sub-attaq/boat_p.h @@ -104,7 +104,7 @@ protected: return false; } - void onTransition() + void onTransition(QEvent *) { //We decrease the speed if needed if (key == Qt::Key_Left && boat->currentDirection() == Boat::Right) @@ -156,7 +156,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentDirection(Boat::Right); boat->updateBoatMovement(); @@ -174,7 +174,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentDirection(Boat::Left); boat->updateBoatMovement(); @@ -192,7 +192,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentSpeed(0); boat->setCurrentDirection(Boat::None); @@ -211,7 +211,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { Bomb *b = new Bomb(); b->setPos(boat->x()+boat->size().width(),boat->y()); @@ -233,7 +233,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { Bomb *b = new Bomb(); b->setPos(boat->x() - b->size().width(), boat->y()); diff --git a/examples/animation/sub-attaq/qanimationstate.cpp b/examples/animation/sub-attaq/qanimationstate.cpp index 3659657..0f30ac2 100644 --- a/examples/animation/sub-attaq/qanimationstate.cpp +++ b/examples/animation/sub-attaq/qanimationstate.cpp @@ -146,7 +146,7 @@ QAbstractAnimation* QAnimationState::animation() const /*! \reimp */ -void QAnimationState::onEntry() +void QAnimationState::onEntry(QEvent *) { Q_D(QAnimationState); if (d->animation) @@ -156,7 +156,7 @@ void QAnimationState::onEntry() /*! \reimp */ -void QAnimationState::onExit() +void QAnimationState::onExit(QEvent *) { Q_D(QAnimationState); if (d->animation) diff --git a/examples/animation/sub-attaq/qanimationstate.h b/examples/animation/sub-attaq/qanimationstate.h index ddf5681..88c0a6d 100644 --- a/examples/animation/sub-attaq/qanimationstate.h +++ b/examples/animation/sub-attaq/qanimationstate.h @@ -74,8 +74,8 @@ Q_SIGNALS: void animationFinished(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *); + void onExit(QEvent *); bool event(QEvent *e); private: diff --git a/examples/animation/sub-attaq/states.cpp b/examples/animation/sub-attaq/states.cpp index 0b98016..c6af924 100644 --- a/examples/animation/sub-attaq/states.cpp +++ b/examples/animation/sub-attaq/states.cpp @@ -76,7 +76,7 @@ PlayState::~PlayState() { } -void PlayState::onEntry() +void PlayState::onEntry(QEvent *) { //We are now playing? if (machine) { @@ -159,7 +159,7 @@ void PlayState::onEntry() LevelState::LevelState(GraphicsScene *scene, PlayState *game, QState *parent) : QState(parent), scene(scene), game(game) { } -void LevelState::onEntry() +void LevelState::onEntry(QEvent *) { initializeLevel(); } @@ -202,12 +202,12 @@ void LevelState::initializeLevel() PauseState::PauseState(GraphicsScene *scene, QState *parent) : QState(parent),scene(scene) { } -void PauseState::onEntry() +void PauseState::onEntry(QEvent *) { AnimationManager::self()->pauseAll(); scene->boat->setEnabled(false); } -void PauseState::onExit() +void PauseState::onExit(QEvent *) { AnimationManager::self()->resumeAll(); scene->boat->setEnabled(true); @@ -219,7 +219,7 @@ LostState::LostState(GraphicsScene *scene, PlayState *game, QState *parent) : QS { } -void LostState::onEntry() +void LostState::onEntry(QEvent *) { //The message to display QString message = QString("You lose on level %1. Your score is %2.").arg(game->currentLevel+1).arg(game->score); @@ -242,7 +242,7 @@ WinState::WinState(GraphicsScene *scene, PlayState *game, QState *parent) : QSta { } -void WinState::onEntry() +void WinState::onEntry(QEvent *) { //We clear the scene scene->clearScene(); @@ -269,9 +269,9 @@ UpdateScoreState::UpdateScoreState(PlayState *game, QState *parent) : QState(par { this->game = game; } -void UpdateScoreState::onEntry() +void UpdateScoreState::onEntry(QEvent *e) { - QState::onEntry(); + QState::onEntry(e); } /** Win transition */ diff --git a/examples/animation/sub-attaq/states.h b/examples/animation/sub-attaq/states.h index ec69ae7..27beb71 100644 --- a/examples/animation/sub-attaq/states.h +++ b/examples/animation/sub-attaq/states.h @@ -68,7 +68,7 @@ public: ~PlayState(); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; @@ -91,7 +91,7 @@ class LevelState : public QState public: LevelState(GraphicsScene *scene, PlayState *game, QState *parent = 0); protected: - void onEntry(); + void onEntry(QEvent *); private : void initializeLevel(); GraphicsScene *scene; @@ -104,8 +104,8 @@ public: PauseState(GraphicsScene *scene, QState *parent = 0); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *); + void onExit(QEvent *); private : GraphicsScene *scene; Boat *boat; @@ -117,7 +117,7 @@ public: LostState(GraphicsScene *scene, PlayState *game, QState *parent = 0); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; PlayState *game; @@ -129,7 +129,7 @@ public: WinState(GraphicsScene *scene, PlayState *game, QState *parent = 0); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; PlayState *game; @@ -140,7 +140,7 @@ class UpdateScoreState : public QState public: UpdateScoreState(PlayState *game, QState *parent); protected: - void onEntry(); + void onEntry(QEvent *); private: QPropertyAnimation *scoreAnimation; PlayState *game; diff --git a/examples/animation/sub-attaq/submarine_p.h b/examples/animation/sub-attaq/submarine_p.h index 918e7f5..c76d991 100644 --- a/examples/animation/sub-attaq/submarine_p.h +++ b/examples/animation/sub-attaq/submarine_p.h @@ -77,7 +77,7 @@ protected slots: } protected: - void onEntry() + void onEntry(QEvent *e) { if (submarine->currentDirection() == SubMarine::Left) { movementAnimation->setEndValue(QPointF(0,submarine->y())); @@ -88,7 +88,7 @@ protected: movementAnimation->setDuration((submarine->scene()->width()-submarine->size().width()-submarine->x())/submarine->currentSpeed()*12); } movementAnimation->setStartValue(submarine->pos()); - QAnimationState::onEntry(); + QAnimationState::onEntry(e); } private: @@ -109,19 +109,19 @@ public: } protected: - void onEntry() + void onEntry(QEvent *e) { returnAnimation->stop(); returnAnimation->setStartValue(submarine->yRotation()); returnAnimation->setEndValue(submarine->currentDirection() == SubMarine::Right ? 360. : 180.); returnAnimation->setDuration(500); - QAnimationState::onEntry(); + QAnimationState::onEntry(e); } - void onExit() + void onExit(QEvent *e) { submarine->currentDirection() == SubMarine::Right ? submarine->setCurrentDirection(SubMarine::Left) : submarine->setCurrentDirection(SubMarine::Right); - QAnimationState::onExit(); + QAnimationState::onExit(e); } private: diff --git a/examples/statemachine/clockticking/main.cpp b/examples/statemachine/clockticking/main.cpp index 9b54f29..ea8e692 100644 --- a/examples/statemachine/clockticking/main.cpp +++ b/examples/statemachine/clockticking/main.cpp @@ -61,7 +61,7 @@ public: : QState(parent) {} protected: - virtual void onEntry() + virtual void onEntry(QEvent *) { fprintf(stdout, "ClockState entered; posting the initial tick\n"); machine()->postEvent(new ClockEvent()); @@ -77,7 +77,7 @@ protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "ClockTransition triggered; posting another tick with a delay of 1 second\n"); machine()->postEvent(new ClockEvent(), 1000); @@ -93,7 +93,7 @@ protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "ClockListener heard a tick!\n"); } diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h index d3670bd..3db464b 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h @@ -21,7 +21,7 @@ signals: void turnSelected(); protected: - void onEntry() + void onEntry(QEvent *) { int rand = qrand() % 4; switch (rand) { @@ -45,7 +45,7 @@ signals: void distanceComputed(qreal distance); protected: - void onEntry() + void onEntry(QEvent *) { emit distanceComputed(qreal(qrand() % 180)); } diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h index 83f50a7..7d8aa68 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -48,13 +48,13 @@ signals: void nearestObstacleStraightAhead(); protected: - void onEntry() + void onEntry(QEvent *) { connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); turnAlittle(); } - void onExit() + void onExit(QEvent *) { disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(nearestObstacleStraightAhead())); @@ -89,7 +89,7 @@ protected: return QSignalTransition::eventTest(event); } - void onTransition() + void onTransition(QEvent *) { qreal currentDirection = m_tank->property("direction").toDouble(); qreal angleOfWall = m_lastLine.angle(); diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h index 309ba14..4b4629c 100644 --- a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h @@ -22,7 +22,7 @@ public slots: } protected: - void onEntry() + void onEntry(QEvent *) { connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); spin(); diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h index fa06d10..9a96a8b 100644 --- a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h @@ -22,7 +22,7 @@ public slots: } protected: - void onEntry() + void onEntry(QEvent *) { connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); spin(); diff --git a/examples/statemachine/factorial/main.cpp b/examples/statemachine/factorial/main.cpp index 9e39ced..2b63690 100644 --- a/examples/statemachine/factorial/main.cpp +++ b/examples/statemachine/factorial/main.cpp @@ -104,7 +104,7 @@ public: return m_fact->property("x").toInt() > 1; } - virtual void onTransition() + virtual void onTransition(QEvent *) { int x = m_fact->property("x").toInt(); int fac = m_fact->property("fac").toInt(); @@ -128,7 +128,7 @@ public: return m_fact->property("x").toInt() <= 1; } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "%d\n", m_fact->property("fac").toInt()); } diff --git a/examples/statemachine/helloworld/main.cpp b/examples/statemachine/helloworld/main.cpp index 13486d4..fbe34b5 100644 --- a/examples/statemachine/helloworld/main.cpp +++ b/examples/statemachine/helloworld/main.cpp @@ -52,7 +52,7 @@ public: S0(QState *parent = 0) : QState(parent) {} - virtual void onEntry() + virtual void onEntry(QEvent *) { fprintf(stdout, "Hello world!\n"); } diff --git a/examples/statemachine/pingpong/main.cpp b/examples/statemachine/pingpong/main.cpp index 68f7115..eb8fd5d 100644 --- a/examples/statemachine/pingpong/main.cpp +++ b/examples/statemachine/pingpong/main.cpp @@ -68,7 +68,7 @@ public: : QState(parent) {} protected: - virtual void onEntry() + virtual void onEntry(QEvent *) { machine()->postEvent(new PingEvent()); fprintf(stdout, "ping?\n"); @@ -84,7 +84,7 @@ protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+3); } - virtual void onTransition() + virtual void onTransition(QEvent *) { machine()->postEvent(new PingEvent(), 500); fprintf(stdout, "ping?\n"); @@ -100,7 +100,7 @@ protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { machine()->postEvent(new PongEvent(), 500); fprintf(stdout, "pong!\n"); diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp index cc6f0f9..3f84314 100644 --- a/src/corelib/statemachine/qabstractstate.cpp +++ b/src/corelib/statemachine/qabstractstate.cpp @@ -101,16 +101,16 @@ QStateMachine *QAbstractStatePrivate::machine() const return 0; } -void QAbstractStatePrivate::callOnEntry() +void QAbstractStatePrivate::callOnEntry(QEvent *e) { Q_Q(QAbstractState); - q->onEntry(); + q->onEntry(e); } -void QAbstractStatePrivate::callOnExit() +void QAbstractStatePrivate::callOnExit(QEvent *e) { Q_Q(QAbstractState); - q->onExit(); + q->onExit(e); } void QAbstractStatePrivate::emitEntered() @@ -190,17 +190,19 @@ QStateMachine *QAbstractState::machine() const } /*! - \fn QAbstractState::onExit() + \fn QAbstractState::onExit(QEvent *event) - This function is called when the state is exited. Reimplement this function - to perform custom processing when the state is exited. + This function is called when the state is exited. The given \a event is what + caused the state to be exited. Reimplement this function to perform custom + processing when the state is exited. */ /*! - \fn QAbstractState::onEntry() + \fn QAbstractState::onEntry(QEvent *event) - This function is called when the state is entered. Reimplement this function - to perform custom processing when the state is entered. + This function is called when the state is entered. The given \a event is + what caused the state to be entered. Reimplement this function to perform + custom processing when the state is entered. */ /*! diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h index 30a68ff..f6b4b21 100644 --- a/src/corelib/statemachine/qabstractstate.h +++ b/src/corelib/statemachine/qabstractstate.h @@ -70,8 +70,8 @@ Q_SIGNALS: protected: QAbstractState(QState *parent = 0); - virtual void onEntry() = 0; - virtual void onExit() = 0; + virtual void onEntry(QEvent *event) = 0; + virtual void onExit(QEvent *event) = 0; bool event(QEvent *e); diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h index bbe12d6..6c09696 100644 --- a/src/corelib/statemachine/qabstractstate_p.h +++ b/src/corelib/statemachine/qabstractstate_p.h @@ -77,8 +77,8 @@ public: QStateMachine *machine() const; - void callOnEntry(); - void callOnExit(); + void callOnEntry(QEvent *e); + void callOnExit(QEvent *e); void emitEntered(); void emitExited(); diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 5fa1742..1897aa6 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -131,10 +131,10 @@ bool QAbstractTransitionPrivate::callEventTest(QEvent *e) const return q->eventTest(e); } -void QAbstractTransitionPrivate::callOnTransition() +void QAbstractTransitionPrivate::callOnTransition(QEvent *e) { Q_Q(QAbstractTransition); - q->onTransition(); + q->onTransition(e); } QState *QAbstractTransitionPrivate::sourceState() const @@ -353,10 +353,11 @@ QList QAbstractTransition::animations() const */ /*! - \fn QAbstractTransition::onTransition() + \fn QAbstractTransition::onTransition(QEvent *event) - This function is called when the transition is triggered. Reimplement this - function to perform custom processing when the transition is triggered. + This function is called when the transition is triggered. The given \a event + is what caused the transition to trigger. Reimplement this function to + perform custom processing when the transition is triggered. */ /*! diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h index 79ab808..e207944 100644 --- a/src/corelib/statemachine/qabstracttransition.h +++ b/src/corelib/statemachine/qabstracttransition.h @@ -90,7 +90,7 @@ public: protected: virtual bool eventTest(QEvent *event) const = 0; - virtual void onTransition() = 0; + virtual void onTransition(QEvent *event) = 0; bool event(QEvent *e); diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h index a48a09c..b4e1c88 100644 --- a/src/corelib/statemachine/qabstracttransition_p.h +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -79,7 +79,7 @@ public: static const QAbstractTransitionPrivate *get(const QAbstractTransition *q); bool callEventTest(QEvent *e) const; - void callOnTransition(); + void callOnTransition(QEvent *e); QState *sourceState() const; QStateMachine *machine() const; diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp index cbd03bd..86259e4 100644 --- a/src/corelib/statemachine/qeventtransition.cpp +++ b/src/corelib/statemachine/qeventtransition.cpp @@ -270,8 +270,9 @@ bool QEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QEventTransition::onTransition() +void QEventTransition::onTransition(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h index 484602c..a128cee 100644 --- a/src/corelib/statemachine/qeventtransition.h +++ b/src/corelib/statemachine/qeventtransition.h @@ -78,7 +78,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp index 6a1b608..772ec87 100644 --- a/src/corelib/statemachine/qfinalstate.cpp +++ b/src/corelib/statemachine/qfinalstate.cpp @@ -108,15 +108,17 @@ QFinalState::~QFinalState() /*! \reimp */ -void QFinalState::onEntry() +void QFinalState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! \reimp */ -void QFinalState::onExit() +void QFinalState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h index 726a399..eb8aa0f 100644 --- a/src/corelib/statemachine/qfinalstate.h +++ b/src/corelib/statemachine/qfinalstate.h @@ -63,8 +63,8 @@ public: ~QFinalState(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index 4e3db08..fd6f53d 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -200,14 +200,14 @@ void QHistoryState::setHistoryType(HistoryType type) /*! \reimp */ -void QHistoryState::onEntry() +void QHistoryState::onEntry(QEvent *event) { } /*! \reimp */ -void QHistoryState::onExit() +void QHistoryState::onExit(QEvent *event) { } diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h index c7648bc..d0f75de 100644 --- a/src/corelib/statemachine/qhistorystate.h +++ b/src/corelib/statemachine/qhistorystate.h @@ -78,8 +78,8 @@ public: void setHistoryType(HistoryType type); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index e9e248f..d5833bd 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -245,8 +245,9 @@ bool QSignalTransition::eventTest(QEvent *event) const /*! \reimp */ -void QSignalTransition::onTransition() +void QSignalTransition::onTransition(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h index b8e8fc6..98a9ae7 100644 --- a/src/corelib/statemachine/qsignaltransition.h +++ b/src/corelib/statemachine/qsignaltransition.h @@ -77,7 +77,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index a431888..3220619 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -339,7 +339,7 @@ public: UnconditionalTransition(QAbstractState *target) : QAbstractTransition(QList() << target) {} protected: - void onTransition() {} + void onTransition(QEvent *) {} bool eventTest(QEvent *) const { return true; } }; @@ -384,15 +384,17 @@ void QState::removeTransition(QAbstractTransition *transition) /*! \reimp */ -void QState::onEntry() +void QState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! \reimp */ -void QState::onExit() +void QState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h index 9faef26..73955d7 100644 --- a/src/corelib/statemachine/qstate.h +++ b/src/corelib/statemachine/qstate.h @@ -97,8 +97,8 @@ Q_SIGNALS: void polished(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 0ebc993..8b0b4f3 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -369,18 +369,18 @@ QSet QStateMachinePrivate::selectTransitions(QEvent *event return enabledTransitions; } -void QStateMachinePrivate::microstep(const QList &enabledTransitions) +void QStateMachinePrivate::microstep(QEvent *event, const QList &enabledTransitions) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ")"; qDebug() << q_func() << ": configuration before exiting states:" << configuration; #endif - QList exitedStates = exitStates(enabledTransitions); + QList exitedStates = exitStates(event, enabledTransitions); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": configuration after exiting states:" << configuration; #endif - executeTransitionContent(enabledTransitions); - QList enteredStates = enterStates(enabledTransitions); + executeTransitionContent(event, enabledTransitions); + QList enteredStates = enterStates(event, enabledTransitions); applyProperties(enabledTransitions, exitedStates, enteredStates); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": configuration after entering states:" << configuration; @@ -388,7 +388,7 @@ void QStateMachinePrivate::microstep(const QList &enabledT #endif } -QList QStateMachinePrivate::exitStates(const QList &enabledTransitions) +QList QStateMachinePrivate::exitStates(QEvent *event, const QList &enabledTransitions) { // qDebug() << "exitStates(" << enabledTransitions << ")"; QSet statesToExit; @@ -440,25 +440,25 @@ QList QStateMachinePrivate::exitStates(const QListcallOnExit(); + QAbstractStatePrivate::get(s)->callOnExit(event); configuration.remove(s); QAbstractStatePrivate::get(s)->emitExited(); } return statesToExit_sorted; } -void QStateMachinePrivate::executeTransitionContent(const QList &enabledTransitions) +void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList &enabledTransitions) { for (int i = 0; i < enabledTransitions.size(); ++i) { QAbstractTransition *t = enabledTransitions.at(i); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": triggering" << t; #endif - QAbstractTransitionPrivate::get(t)->callOnTransition(); + QAbstractTransitionPrivate::get(t)->callOnTransition(event); } } -QList QStateMachinePrivate::enterStates(const QList &enabledTransitions) +QList QStateMachinePrivate::enterStates(QEvent *event, const QList &enabledTransitions) { #ifdef QSTATEMACHINE_DEBUG Q_Q(QStateMachine); @@ -506,7 +506,7 @@ QList QStateMachinePrivate::enterStates(const QListcallOnEntry(); + QAbstractStatePrivate::get(s)->callOnEntry(event); QAbstractStatePrivate::get(s)->emitEntered(); if (statesForDefaultEntry.contains(s)) { // ### executeContent(s.initial.transition.children()) @@ -1067,8 +1067,8 @@ public: StartState(QState *parent) : QState(parent) {} protected: - void onEntry() {} - void onExit() {} + void onEntry(QEvent *) {} + void onExit(QEvent *) {} }; class InitialTransition : public QAbstractTransition @@ -1078,7 +1078,7 @@ public: : QAbstractTransition(QList() << target) {} protected: virtual bool eventTest(QEvent *) const { return true; } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} }; } // namespace @@ -1113,8 +1113,9 @@ void QStateMachinePrivate::_q_start() start->addTransition(initialTransition); QList transitions; transitions.append(initialTransition); - executeTransitionContent(transitions); - enterStates(transitions); + QEvent nullEvent(QEvent::None); + executeTransitionContent(&nullEvent, transitions); + enterStates(&nullEvent, transitions); applyProperties(transitions, QList() << start, QList() << initial); delete start; @@ -1180,7 +1181,7 @@ void QStateMachinePrivate::_q_process() } if (!enabledTransitions.isEmpty()) { q->beginMicrostep(e); - microstep(enabledTransitions.toList()); + microstep(e, enabledTransitions.toList()); q->endMicrostep(e); } #ifdef QSTATEMACHINE_DEBUG @@ -1455,7 +1456,7 @@ public: setObjectName(QString::fromLatin1("DefaultErrorState")); } - void onEntry() + void onEntry(QEvent *) { QAbstractStatePrivate *d = QAbstractStatePrivate::get(this); QStateMachine *machine = d->machine(); @@ -1464,7 +1465,7 @@ public: qPrintable(machine->errorString())); } - void onExit() {} + void onExit(QEvent *) {} }; class RootState : public QState @@ -1475,8 +1476,8 @@ public: { } - void onEntry() {} - void onExit() {} + void onEntry(QEvent *) {} + void onExit(QEvent *) {} }; } // namespace diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index b3707ea..bb4a78c 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -120,12 +120,12 @@ public: void _q_animationFinished(); #endif - void microstep(const QList &transitionList); + void microstep(QEvent *event, const QList &transitionList); bool isPreempted(const QAbstractState *s, const QSet &transitions) const; QSet selectTransitions(QEvent *event) const; - QList exitStates(const QList &transitionList); - void executeTransitionContent(const QList &transitionList); - QList enterStates(const QList &enabledTransitions); + QList exitStates(QEvent *event, const QList &transitionList); + void executeTransitionContent(QEvent *event, const QList &transitionList); + QList enterStates(QEvent *event, const QList &enabledTransitions); void addStatesToEnter(QAbstractState *s, QState *root, QSet &statesToEnter, QSet &statesForDefaultEntry); diff --git a/src/gui/statemachine/qbasickeyeventtransition.cpp b/src/gui/statemachine/qbasickeyeventtransition.cpp index 4e3fa11..7821feb 100644 --- a/src/gui/statemachine/qbasickeyeventtransition.cpp +++ b/src/gui/statemachine/qbasickeyeventtransition.cpp @@ -170,7 +170,7 @@ bool QBasicKeyEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QBasicKeyEventTransition::onTransition() +void QBasicKeyEventTransition::onTransition(QEvent *) { } diff --git a/src/gui/statemachine/qbasickeyeventtransition_p.h b/src/gui/statemachine/qbasickeyeventtransition_p.h index de49eac..0d08da0 100644 --- a/src/gui/statemachine/qbasickeyeventtransition_p.h +++ b/src/gui/statemachine/qbasickeyeventtransition_p.h @@ -56,7 +56,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *); private: Q_DISABLE_COPY(QBasicKeyEventTransition) diff --git a/src/gui/statemachine/qbasicmouseeventtransition.cpp b/src/gui/statemachine/qbasicmouseeventtransition.cpp index 83254dc..0cb727e 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition.cpp +++ b/src/gui/statemachine/qbasicmouseeventtransition.cpp @@ -174,7 +174,7 @@ bool QBasicMouseEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QBasicMouseEventTransition::onTransition() +void QBasicMouseEventTransition::onTransition(QEvent *) { } diff --git a/src/gui/statemachine/qbasicmouseeventtransition_p.h b/src/gui/statemachine/qbasicmouseeventtransition_p.h index 77fbd58..20c7f8f 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition_p.h +++ b/src/gui/statemachine/qbasicmouseeventtransition_p.h @@ -59,7 +59,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *); private: Q_DISABLE_COPY(QBasicMouseEventTransition) diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp index 37f4dd9..e6ab11b 100644 --- a/src/gui/statemachine/qkeyeventtransition.cpp +++ b/src/gui/statemachine/qkeyeventtransition.cpp @@ -153,9 +153,9 @@ bool QKeyEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QKeyEventTransition::onTransition() +void QKeyEventTransition::onTransition(QEvent *event) { - QEventTransition::onTransition(); + QEventTransition::onTransition(event); } QT_END_NAMESPACE diff --git a/src/gui/statemachine/qkeyeventtransition.h b/src/gui/statemachine/qkeyeventtransition.h index fa95c1b..3f797f1 100644 --- a/src/gui/statemachine/qkeyeventtransition.h +++ b/src/gui/statemachine/qkeyeventtransition.h @@ -45,7 +45,7 @@ public: void setModifiersMask(Qt::KeyboardModifiers modifiers); protected: - void onTransition(); + void onTransition(QEvent *event); bool eventTest(QEvent *event) const; private: diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp index 353b833..3191a2f 100644 --- a/src/gui/statemachine/qmouseeventtransition.cpp +++ b/src/gui/statemachine/qmouseeventtransition.cpp @@ -183,9 +183,9 @@ bool QMouseEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QMouseEventTransition::onTransition() +void QMouseEventTransition::onTransition(QEvent *event) { - QEventTransition::onTransition(); + QEventTransition::onTransition(event); } QT_END_NAMESPACE diff --git a/src/gui/statemachine/qmouseeventtransition.h b/src/gui/statemachine/qmouseeventtransition.h index d5fb565..eee971e 100644 --- a/src/gui/statemachine/qmouseeventtransition.h +++ b/src/gui/statemachine/qmouseeventtransition.h @@ -51,7 +51,7 @@ public: void setPath(const QPainterPath &path); protected: - void onTransition(); + void onTransition(QEvent *event); bool eventTest(QEvent *event) const; private: diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 5dfc758..94afe51 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -186,10 +186,10 @@ public: : QState(parent) {} QList > events; protected: - virtual void onEntry() { + virtual void onEntry(QEvent *) { events.append(qMakePair(globalTick++, Entry)); } - virtual void onExit() { + virtual void onExit(QEvent *) { events.append(qMakePair(globalTick++, Exit)); } }; @@ -204,7 +204,7 @@ protected: virtual bool eventTest(QEvent *) const { return true; } - virtual void onTransition() { + virtual void onTransition(QEvent *) { triggers.append(globalTick++); } }; @@ -246,7 +246,7 @@ protected: virtual bool eventTest(QEvent *e) const { return (e->type() == m_type); } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} private: QEvent::Type m_type; }; @@ -380,7 +380,7 @@ public: { } - void onEntry() + void onEntry(QEvent *) { error = m_machine->error(); errorString = m_machine->errorString(); @@ -1367,7 +1367,7 @@ protected: StringEvent *se = static_cast(e); return (m_value == se->value) && (!m_cond.isValid() || (m_cond.indexIn(m_value) != -1)); } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} private: QString m_value; @@ -1384,11 +1384,11 @@ public: { m_value = value; } protected: - virtual void onEntry() + virtual void onEntry(QEvent *) { m_machine->postEvent(new StringEvent(m_value)); } - virtual void onExit() {} + virtual void onExit(QEvent *) {} private: QStateMachine *m_machine; -- cgit v0.12 From b8a4216f2fb5bc6e5fd5b54c661344e60fc9093c Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 5 May 2009 18:30:47 +0200 Subject: get rid of warnings --- src/corelib/statemachine/qhistorystate.cpp | 2 ++ src/corelib/statemachine/qstatemachine.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index fd6f53d..b6ec471 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -202,6 +202,7 @@ void QHistoryState::setHistoryType(HistoryType type) */ void QHistoryState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! @@ -209,6 +210,7 @@ void QHistoryState::onEntry(QEvent *event) */ void QHistoryState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 8b0b4f3..232d801 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -661,7 +661,7 @@ void QStateMachinePrivate::applyProperties(const QList &tr // before the state that assigned them is exited. If state does not explicitly // assign a property which is assigned by the parent, it inherits the parent's assignment. QState *parentState = s; - while (parentState = parentState->parentState()) { + while ((parentState = parentState->parentState()) != 0) { assignments = QStatePrivate::get(parentState)->propertyAssignments; for (int j=0; j Date: Tue, 5 May 2009 19:45:06 +0200 Subject: doc improvements --- src/corelib/statemachine/qfinalstate.cpp | 8 +++++--- src/corelib/statemachine/qhistorystate.cpp | 12 +++++++---- src/corelib/statemachine/qstate.cpp | 22 +++++++++++++++----- src/corelib/statemachine/qstatemachine.cpp | 32 ++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp index 772ec87..0980336 100644 --- a/src/corelib/statemachine/qfinalstate.cpp +++ b/src/corelib/statemachine/qfinalstate.cpp @@ -55,9 +55,9 @@ QT_BEGIN_NAMESPACE A final state is used to communicate that (part of) a QStateMachine has finished its work. When a final top-level state is entered, the state machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In - general, when a final substate (a child of a QState) is entered, a - QStateFinishedEvent is generated for the final state's parent - state. QFinalState is part of \l{The State Machine Framework}. + general, when a final substate (a child of a QState) is entered, the parent + state's \l{QState::finished()}{finished}() signal is emitted. QFinalState + is part of \l{The State Machine Framework}. To use a final state, you create a QFinalState object and add a transition to it from another state. Example: @@ -76,6 +76,8 @@ QT_BEGIN_NAMESPACE machine.setInitialState(s1); machine.start(); \endcode + + \sa QStateMachine::finished(), QState::finished() */ class QFinalStatePrivate : public QAbstractStatePrivate diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index b6ec471..d1b2391 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -58,9 +58,8 @@ QT_BEGIN_NAMESPACE other child states of the parent state. QHistoryState is part of \l{The State Machine Framework}. - Use QState::addHistoryState() to construct a history state. Use the - setDefaultState() function to set the state that should be entered if the - parent state has never been entered. Example: + Use the setDefaultState() function to set the state that should be entered + if the parent state has never been entered. Example: \code QStateMachine machine; @@ -69,7 +68,7 @@ QT_BEGIN_NAMESPACE QState *s11 = new QState(s1); QState *s12 = new QState(s1); - QState *s1h = s1->addHistoryState(); + QHistoryState *s1h = new QHistoryState(s1); s1h->setDefaultState(s11); machine.addState(s1); @@ -83,6 +82,9 @@ QT_BEGIN_NAMESPACE // state if s1 has never been entered. s1->addTransition(button, SIGNAL(clicked()), s1h); \endcode + + By default a history state is shallow, meaning that it won't remember nested + states. This can be configured through the historyType property. */ /*! @@ -95,6 +97,8 @@ QT_BEGIN_NAMESPACE \property QHistoryState::historyType \brief the type of history that this history state records + + The default value of this property is QHistoryState::ShallowHistory. */ /*! diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 3220619..4c9e033 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -68,22 +68,30 @@ QT_BEGIN_NAMESPACE The assignProperty() function is used for defining property assignments that should be performed when a state is entered. + Top-level states must be passed QStateMachine::rootState() as their parent + state, or added to a state machine using QStateMachine::addState(). + \section1 States with Child States - For non-parallel state groups, the setInitialState() function must be called - to set the initial state. The child states are mutually exclusive states, - and the state machine needs to know which child state to enter when the - parent state is the target of a transition. + The childMode property determines how child states are treated. For + non-parallel state groups, the setInitialState() function must be called to + set the initial state. The child states are mutually exclusive states, and + the state machine needs to know which child state to enter when the parent + state is the target of a transition. + + The state emits the QState::finished() signal when a final child state + (QFinalState) is entered. The setErrorState() sets the state's error state. The error state is the state that the state machine will transition to if an error is detected when attempting to enter the state (e.g. because no initial state has been set). + */ /*! \property QState::initialState - \brief the initial state of this state + \brief the initial state of this state (one of its child states) */ /*! @@ -96,6 +104,8 @@ QT_BEGIN_NAMESPACE \property QState::childMode \brief the child mode of this state + + The default value of this property is QState::ExclusiveStates. */ /*! @@ -456,6 +466,8 @@ bool QState::event(QEvent *e) \fn QState::finished() This signal is emitted when a final child state of this state is entered. + + \sa QFinalState */ /*! diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 232d801..6f626f5 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -163,6 +163,8 @@ QT_BEGIN_NAMESPACE \property QStateMachine::initialState \brief the initial state of this state machine + + The initial state must be one of the rootState()'s child states. */ /*! @@ -181,6 +183,9 @@ QT_BEGIN_NAMESPACE \property QStateMachine::globalRestorePolicy \brief the restore policy for states of this state machine. + + The default value of this property is + QStateMachine::DoNotRestoreProperties. */ #ifndef QT_NO_ANIMATION @@ -188,6 +193,10 @@ QT_BEGIN_NAMESPACE \property QStateMachine::animationsEnabled \brief whether animations are enabled + + The default value of this property is true. + + \sa QAbstractTransition::addAnimation() */ #endif @@ -1663,7 +1672,7 @@ void QStateMachine::setInitialState(QAbstractState *state) If the state is already in a different machine, it will first be removed from its old machine, and then added to this machine. - \sa removeState(), rootState() + \sa removeState(), rootState(), setInitialState() */ void QStateMachine::addState(QAbstractState *state) { @@ -1700,10 +1709,9 @@ void QStateMachine::removeState(QAbstractState *state) } /*! - Starts this state machine. - The machine will reset its configuration and transition to the initial - state. When a final top-level state is entered, the machine will emit the - finished() signal. + Starts this state machine. The machine will reset its configuration and + transition to the initial state. When a final top-level state (QFinalState) + is entered, the machine will emit the finished() signal. \sa started(), finished(), stop(), initialState() */ @@ -1730,9 +1738,10 @@ void QStateMachine::start() } /*! - Stops this state machine. + Stops this state machine. The state machine will stop processing events and + then emit the stopped() signal. - \sa stopped() + \sa stopped(), start() */ void QStateMachine::stop() { @@ -1813,7 +1822,8 @@ QSet QStateMachine::configuration() const /*! \fn QStateMachine::started() - This signal is emitted when the state machine has entered its initial state. + This signal is emitted when the state machine has entered its initial state + (QStateMachine::initialState). \sa QStateMachine::finished(), QStateMachine::start() */ @@ -1822,7 +1832,7 @@ QSet QStateMachine::configuration() const \fn QStateMachine::finished() This signal is emitted when the state machine has reached a top-level final - state. + state (QFinalState). \sa QStateMachine::started() */ @@ -1832,7 +1842,7 @@ QSet QStateMachine::configuration() const This signal is emitted when the state machine has stopped. - \sa QStateMachine::stop() + \sa QStateMachine::stop(), QStateMachine::finished() */ /*! @@ -2110,7 +2120,7 @@ QSignalEvent::~QSignalEvent() Returns the index of the signal. - \sa QMetaObject::indexOfSignal() + \sa QMetaObject::indexOfSignal(), QMetaObject::method() */ /*! -- cgit v0.12 From ce44510d932c0fc77c368f45848a0fc751f5a18b Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 5 May 2009 20:08:47 +0200 Subject: get rid of margin --- examples/statemachine/trafficlight/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/statemachine/trafficlight/main.cpp b/examples/statemachine/trafficlight/main.cpp index ed0eeea..3c47a51 100644 --- a/examples/statemachine/trafficlight/main.cpp +++ b/examples/statemachine/trafficlight/main.cpp @@ -151,6 +151,7 @@ public: QVBoxLayout *vbox = new QVBoxLayout(this); TrafficLightWidget *widget = new TrafficLightWidget(); vbox->addWidget(widget); + vbox->setMargin(0); QStateMachine *machine = new QStateMachine(this); LightState *redGoingYellow = new LightState(widget->redLight(), 3000); @@ -182,7 +183,7 @@ int main(int argc, char **argv) QApplication app(argc, argv); TrafficLight widget; - widget.resize(120, 300); + widget.resize(110, 300); widget.show(); return app.exec(); -- cgit v0.12 From 7f3b4bdc97e155f84d5294fa822481b8e16e4fc1 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 15:33:28 +0200 Subject: Avoid passage where the walls meet the edge of the scene rect. --- examples/statemachine/errorstate/mainwindow.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp index 4d9b88e..39b8663 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/errorstate/mainwindow.cpp @@ -88,18 +88,19 @@ void MainWindow::init() } QPointF centerOfMap = sceneRect.center(); + addWall(QRectF(centerOfMap + QPointF(-50.0, -60.0), centerOfMap + QPointF(50.0, -50.0))); addWall(QRectF(centerOfMap - QPointF(-50.0, -60.0), centerOfMap - QPointF(50.0, -50.0))); addWall(QRectF(centerOfMap + QPointF(-50.0, -50.0), centerOfMap + QPointF(-40.0, 50.0))); addWall(QRectF(centerOfMap - QPointF(-50.0, -50.0), centerOfMap - QPointF(-40.0, 50.0))); - - addWall(QRectF(sceneRect.topLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, 0.0), + + addWall(QRectF(sceneRect.topLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, -10.0), sceneRect.topLeft() + QPointF(sceneRect.width() / 2.0 + 5.0, 100.0))); - addWall(QRectF(sceneRect.bottomLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, 0.0), + addWall(QRectF(sceneRect.bottomLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, 10.0), sceneRect.bottomLeft() + QPointF(sceneRect.width() / 2.0 + 5.0, -100.0))); - addWall(QRectF(sceneRect.topLeft() + QPointF(0.0, sceneRect.height() / 2.0 - 5.0), + addWall(QRectF(sceneRect.topLeft() + QPointF(-10.0, sceneRect.height() / 2.0 - 5.0), sceneRect.topLeft() + QPointF(100.0, sceneRect.height() / 2.0 + 5.0))); - addWall(QRectF(sceneRect.topRight() + QPointF(0.0, sceneRect.height() / 2.0 - 5.0), + addWall(QRectF(sceneRect.topRight() + QPointF(10.0, sceneRect.height() / 2.0 - 5.0), sceneRect.topRight() + QPointF(-100.0, sceneRect.height() / 2.0 + 5.0))); -- cgit v0.12 From a9fd7d6881107b7e06362076c587530124fb1484 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 5 May 2009 16:38:53 +0200 Subject: Add chase state and ability to detect and fire at other tanks. This reveals an assert in the state machine which needs to be debugged. --- .../errorstateplugins/seek_ai/seek_ai.cpp | 6 ++ .../errorstateplugins/seek_ai/seek_ai.h | 90 +++++++++++++++++++++- 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp index 229f83a..2fb05d4 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp @@ -36,6 +36,12 @@ QState *SeekAi::create(QState *parentState, QObject *tank) turnTo->addTransition(tank, SIGNAL(actionCompleted()), driveToFirstObstacle); + ChaseState *chase = new ChaseState(tank, topLevel); + chase->setObjectName("chase"); + seek->addTransition(new TankSpottedTransition(tank, chase)); + chase->addTransition(chase, SIGNAL(finished()), driveToFirstObstacle); + chase->addTransition(new TankSpottedTransition(tank, chase)); + return topLevel; } diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h index 7d8aa68..34d203e 100644 --- a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -72,7 +73,7 @@ class CollisionTransition: public QSignalTransition { public: CollisionTransition(QObject *tank, QState *turnTo) - : QSignalTransition(tank, SIGNAL(collision(QLineF)), turnTo), + : QSignalTransition(tank, SIGNAL(collision(QLineF))), m_tank(tank), m_turnTo(turnTo) { @@ -82,16 +83,16 @@ public: protected: bool eventTest(QEvent *event) const { - if (event->type() == QEvent::Signal) { + bool b = QSignalTransition::eventTest(event); + if (b) { QSignalEvent *se = static_cast(event); m_lastLine = se->arguments().at(0).toLineF(); } - return QSignalTransition::eventTest(event); + return b; } void onTransition(QEvent *) { - qreal currentDirection = m_tank->property("direction").toDouble(); qreal angleOfWall = m_lastLine.angle(); qreal newDirection; @@ -109,6 +110,87 @@ private: QState *m_turnTo; }; +class ChaseState: public QState +{ + class GoToLocationState: public QState + { + public: + GoToLocationState(QObject *tank, QState *parentState = 0) + : QState(parentState), m_tank(tank), m_distance(0.0) + { + } + + void setDistance(qreal distance) { m_distance = distance; } + + protected: + void onEntry() + { + QMetaObject::invokeMethod(m_tank, "moveForwards", Q_ARG(qreal, m_distance)); + } + + private: + QObject *m_tank; + qreal m_distance; + }; + +public: + ChaseState(QObject *tank, QState *parentState = 0) : QState(parentState), m_tank(tank) + { + QState *fireCannon = new QState(this); + connect(fireCannon, SIGNAL(entered()), tank, SLOT(fireCannon())); + setInitialState(fireCannon); + + m_goToLocation = new GoToLocationState(this); + fireCannon->addTransition(tank, SIGNAL(actionCompleted()), m_goToLocation); + + m_turnToDirection = new QState(this); + m_goToLocation->addTransition(tank, SIGNAL(actionCompleted()), m_turnToDirection); + + QFinalState *finalState = new QFinalState(this); + m_turnToDirection->addTransition(tank, SIGNAL(actionCompleted()), finalState); + } + + void setDirection(qreal direction) + { + m_turnToDirection->assignProperty(m_tank, "direction", direction); + } + + void setDistance(qreal distance) + { + m_goToLocation->setDistance(distance); + } + +private: + QObject *m_tank; + GoToLocationState *m_goToLocation; + QState *m_turnToDirection; + +}; + +class TankSpottedTransition: public QSignalTransition +{ +public: + TankSpottedTransition(QObject *tank, ChaseState *target) : QSignalTransition(tank, SIGNAL(tankSpotted(qreal,qreal))), m_chase(target) + { + setTargetState(target); + } + +protected: + bool eventTest(QEvent *event) const + { + bool b = QSignalTransition::eventTest(event); + if (b) { + QSignalEvent *se = static_cast(event); + m_chase->setDirection(se->arguments().at(0).toDouble()); + m_chase->setDistance(se->arguments().at(1).toDouble()); + } + return b; + } + +private: + ChaseState *m_chase; +}; + class SeekAi: public QObject, public Plugin { Q_OBJECT -- cgit v0.12 From 48ca4182e518a6439264f87b54e691deecc59e20 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 6 May 2009 10:25:41 +0200 Subject: Instead of adding animations for all properties to all transitions, we use the default animation concept, since this is its intended use. --- examples/animation/appchooser/main.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/animation/appchooser/main.cpp b/examples/animation/appchooser/main.cpp index 02302d9..1c63aba 100644 --- a/examples/animation/appchooser/main.cpp +++ b/examples/animation/appchooser/main.cpp @@ -90,15 +90,16 @@ void createStates(const QObjectList &objects, for (int i = 0; i < objects.size(); ++i) { QState *state = new QState(parent); state->assignProperty(objects.at(i), "geometry", selectedRect); - QAbstractTransition *trans = parent->addTransition(objects.at(i), SIGNAL(clicked()), state); - for (int j = 0; j < objects.size(); ++j) { - QPropertyAnimation *animation = new QPropertyAnimation(objects.at(j), "geometry"); - animation->setDuration(2000); - trans->addAnimation(animation); - } + parent->addTransition(objects.at(i), SIGNAL(clicked()), state); } } +void createAnimations(const QObjectList &objects, QStateMachine *machine) +{ + for (int i=0; iaddDefaultAnimation(new QPropertyAnimation(objects.at(i), "geometry")); +} + int main(int argc, char **argv) { Q_INIT_RESOURCE(appchooser); @@ -143,7 +144,10 @@ int main(int argc, char **argv) QState *idleState = new QState(group); group->setInitialState(idleState); - createStates(QObjectList() << p1 << p2 << p3 << p4, selectedRect, group); + QObjectList objects; + objects << p1 << p2 << p3 << p4; + createStates(objects, selectedRect, group); + createAnimations(objects, &machine); machine.setInitialState(group); machine.start(); -- cgit v0.12 From d2c34394b7105e26612c1fe2b2bb22be4bd8e097 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 6 May 2009 10:29:20 +0200 Subject: Fix bogus default start value when interrupting an animation that has an implicit end value. We need to stop the animation prior to setting the end value to an invalid variant, otherwise the current value of the property will be updated based on the new end value and randomness will occur. --- src/corelib/statemachine/qstatemachine.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 6f626f5..98aa9f2 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -698,6 +698,13 @@ void QStateMachinePrivate::applyProperties(const QList &tr QAbstractAnimation *anim = animations.at(j); QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished())); stateForAnimation.remove(anim); + + // Stop the (top-level) animation. + // ### Stopping nested animation has weird behavior. + while (QAnimationGroup *group = anim->group()) + anim = group; + anim->stop(); + if (resetAnimationEndValues.contains(anim)) { qobject_cast(anim)->setEndValue(QVariant()); // ### generalize resetAnimationEndValues.remove(anim); @@ -721,11 +728,6 @@ void QStateMachinePrivate::applyProperties(const QList &tr if (!found) { assn.object->setProperty(assn.propertyName, assn.value); } - // Stop the (top-level) animation. - // ### Stopping nested animation has weird behavior. - while (QAnimationGroup *group = anim->group()) - anim = group; - anim->stop(); } } -- cgit v0.12 From 612e0d23938b37907f3f4fdf9733732e4b7b8a7e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 6 May 2009 10:33:46 +0200 Subject: Remove superfluous code We have gone back to the old definition of implicit start values where the a new default start value is sniffed every time the animation is restarted, so we do not need to emulate this behavior ourselves anymore. Behavior should be identical. --- src/corelib/statemachine/qstatemachine.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 98aa9f2..7d6616a 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1019,13 +1019,6 @@ QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, && prop.object == animation->targetObject() && prop.propertyName == animation->propertyName()) { - if (!animation->startValue().isValid()) { - QByteArray propertyName = animation->propertyName(); - QVariant currentValue = animation->targetObject()->property(propertyName); - - QVariantAnimationPrivate::get(animation)->setDefaultStartValue(currentValue); - } - // Only change end value if it is undefined if (!animation->endValue().isValid()) { animation->setEndValue(prop.value); -- cgit v0.12 From ed900ca77ad3c3e337054346213dc38a58137818 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 10:05:05 +0200 Subject: Compile with new API addHistoryState() is gone and onTransition() now takes an argument. --- tests/auto/qstate/tst_qstate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qstate/tst_qstate.cpp b/tests/auto/qstate/tst_qstate.cpp index f082caf..bb7de20 100644 --- a/tests/auto/qstate/tst_qstate.cpp +++ b/tests/auto/qstate/tst_qstate.cpp @@ -260,7 +260,7 @@ protected: return e->type() == m_type; } - void onTransition() {} + void onTransition(QEvent *) {} private: QEvent::Type m_type; @@ -274,7 +274,7 @@ void tst_QState::historyInitialState() QState *s1 = new QState(machine.rootState()); QState *s2 = new QState(machine.rootState()); - QHistoryState *h1 = s2->addHistoryState(); + QHistoryState *h1 = new QHistoryState(s2); s2->setInitialState(h1); -- cgit v0.12 From 7bfe66e825e98b049dfdb0b6008e3f334909eec7 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 10:20:25 +0200 Subject: Make sure machine enters error state if history state has no default state Keep searching the parent hierarchy for error states even if a state in the hierarchy cannot be cast to QState. Also make currentErrorState==0 an assert, since there should always be an error state (we default to the special initialErrorState if we are unable to find anything else), otherwise the machine might get into an undefined state (e.g. configuration is empty) --- src/corelib/statemachine/qstatemachine.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 7d6616a..41d4c6c 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -582,6 +582,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, QList hlst; if (QHistoryStatePrivate::get(h)->defaultState) hlst.append(QHistoryStatePrivate::get(h)->defaultState); + if (hlst.isEmpty()) { setError(QStateMachine::NoDefaultStateInHistoryState, h); } else { @@ -946,15 +947,15 @@ QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context) // Find error state recursively in parent hierarchy if not set explicitly for context state QAbstractState *errorState = 0; + QState *s = qobject_cast(context); - if (s) { + if (s) errorState = s->errorState(); - if (!errorState) - errorState = findErrorState(s->parentState()); - return errorState; - } - return errorState; + if (!errorState) + errorState = findErrorState(context->parentState()); + + return errorState; } void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext) @@ -990,10 +991,9 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta currentErrorState = initialErrorStateForRoot; } - if (currentErrorState) { - QState *lca = findLCA(QList() << currentErrorState << currentContext); - addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); - } + Q_ASSERT(currentErrorState != 0); + QState *lca = findLCA(QList() << currentErrorState << currentContext); + addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); } #ifndef QT_NO_ANIMATION -- cgit v0.12 From 74cdd7c31e91e15d5941ece11a6bdf1c4e1b2309 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 10:24:00 +0200 Subject: Fix tests for history state and entering root state Change expectation for entering the root state. We should never have the root state in the configuration. Also fix the expected error message in historyStateHasNowhereToGo since this has changed along with the API. --- tests/auto/qstatemachine/tst_qstatemachine.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 94afe51..8026d6e 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -264,16 +264,14 @@ void tst_QStateMachine::transitionToRootState() machine.start(); QCoreApplication::processEvents(); - QCOMPARE(machine.configuration().count(), 2); + QCOMPARE(machine.configuration().count(), 1); QVERIFY(machine.configuration().contains(initialState)); - QVERIFY(machine.configuration().contains(machine.rootState())); machine.postEvent(new QEvent(QEvent::User)); QCoreApplication::processEvents(); - QCOMPARE(machine.configuration().count(), 2); + QCOMPARE(machine.configuration().count(), 1); QVERIFY(machine.configuration().contains(initialState)); - QVERIFY(machine.configuration().contains(machine.rootState())); } void tst_QStateMachine::transitionEntersParent() @@ -880,7 +878,7 @@ void tst_QStateMachine::historyStateHasNowhereToGo() QCOMPARE(machine.configuration().count(), 1); QVERIFY(machine.configuration().contains(machine.errorState())); QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryState); - QCOMPARE(machine.errorString(), QString::fromLatin1("Missing transition from history state 'historyState'")); + QCOMPARE(machine.errorString(), QString::fromLatin1("Missing default state in history state 'historyState'")); } void tst_QStateMachine::brokenStateIsNeverEntered() -- cgit v0.12 From 0db46b7a592017a4ec541ce703b787458eeb8287 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 7 May 2009 11:25:35 +0200 Subject: Provide a way in private API to have a consistent timer for animations. This allows for better testing because from now on we can rely on the results to be always the same and not rely on timer accuracy any more. Task-number: 251764 Reviewed-by: leo --- src/corelib/animation/qabstractanimation.cpp | 16 +++++++++++++--- src/corelib/animation/qabstractanimation_p.h | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 440a37d..93ecc73 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -162,7 +162,7 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QThreadStorage, unifiedTimer); -QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0) +QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), consistentTimingInterval(0) { } @@ -189,12 +189,22 @@ void QUnifiedTimer::updateRecentlyStartedAnimations() animationsToStart.clear(); } +/* + this allows to haeve a consistent timer interval at each tick from the timer + not taking the real time that passed into account. + Just set this to 0 if you want to get back to a time-driven behaviour. + */ +void QUnifiedTimer::setConsitentTiming(int interval) +{ + consistentTimingInterval = interval; +} + void QUnifiedTimer::timerEvent(QTimerEvent *event) { //this is simply the time we last received a tick - int oldLastTick = lastTick; + const int oldLastTick = lastTick; if (time.isValid()) - lastTick = time.elapsed(); + lastTick = consistentTimingInterval > 0 ? oldLastTick + consistentTimingInterval : time.elapsed(); //we transfer the waiting animations into the "really running" state updateRecentlyStartedAnimations(); diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 666e6a7..0e10b9a 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -123,6 +123,8 @@ public: void registerAnimation(QAbstractAnimation *animation); void unregisterAnimation(QAbstractAnimation *animation); + void setConsitentTiming(int interval); + private: void updateRecentlyStartedAnimations(); @@ -130,6 +132,7 @@ private: QBasicTimer animationTimer, startStopAnimationTimer; QTime time; int lastTick; + int consistentTimingInterval; QList animations, animationsToStart; }; -- cgit v0.12 From 576dca0086b1566eafe9a24cf5946f46f4e857bf Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 11:40:40 +0200 Subject: Fix infinite loop when source and target of transition are in different trees The SCXML algorithm depends on the guarantee that there is always an LCA regardless of the state list. The case where the targets are in a different tree than the source (e.g. if you have not given the target state a parent) is a bug. The fix is to set an error when this happens in exitStates() and exit states as if the pending error states were the target states. In enterStates we will detect the error and skip the step of selecting states to enter, and instead just enter the pending error states. This breaks transitions to and from the root state, which is not supported by the SCXML algorithm. --- src/corelib/statemachine/qstatemachine.cpp | 48 ++++++++++++++++++-------- src/corelib/statemachine/qstatemachine.h | 1 + tests/auto/qstatemachine/tst_qstatemachine.cpp | 5 ++- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 41d4c6c..efcf707 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -409,6 +409,15 @@ QList QStateMachinePrivate::exitStates(QEvent *event, const QLi continue; lst.prepend(t->sourceState()); QAbstractState *lca = findLCA(lst); + if (lca == 0) { + setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); + lst = pendingErrorStates.toList(); + lst.prepend(t->sourceState()); + + lca = findLCA(lst); + Q_ASSERT(lca != 0); + } + { QSet::const_iterator it; for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { @@ -476,21 +485,23 @@ QList QStateMachinePrivate::enterStates(QEvent *event, const QL QSet statesToEnter; QSet statesForDefaultEntry; - for (int i = 0; i < enabledTransitions.size(); ++i) { - QAbstractTransition *t = enabledTransitions.at(i); - QList lst = t->targetStates(); - if (lst.isEmpty()) - continue; - lst.prepend(t->sourceState()); - QState *lca = findLCA(lst); - for (int j = 1; j < lst.size(); ++j) { - QAbstractState *s = lst.at(j); - addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); - if (isParallel(lca)) { - QList lcac = QStatePrivate::get(lca)->childStates(); - foreach (QAbstractState* child,lcac) { - if (!statesToEnter.contains(child)) - addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); + if (pendingErrorStates.isEmpty()) { + for (int i = 0; i < enabledTransitions.size(); ++i) { + QAbstractTransition *t = enabledTransitions.at(i); + QList lst = t->targetStates(); + if (lst.isEmpty()) + continue; + lst.prepend(t->sourceState()); + QState *lca = findLCA(lst); + for (int j = 1; j < lst.size(); ++j) { + QAbstractState *s = lst.at(j); + addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); + if (isParallel(lca)) { + QList lcac = QStatePrivate::get(lca)->childStates(); + foreach (QAbstractState* child,lcac) { + if (!statesToEnter.contains(child)) + addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); + } } } } @@ -976,6 +987,13 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta errorString = QStateMachine::tr("Missing default state in history state '%1'") .arg(currentContext->objectName()); break; + + case QStateMachine::NoCommonAncestorForTransitionError: + Q_ASSERT(currentContext != 0); + + errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'") + .arg(currentContext->objectName()); + break; default: errorString = QStateMachine::tr("Unknown error"); }; diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 10bd443..d0927a3 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -87,6 +87,7 @@ public: NoError, NoInitialStateError, NoDefaultStateInHistoryState, + NoCommonAncestorForTransitionError }; QStateMachine(QObject *parent = 0); diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 8026d6e..e7ea403 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -919,8 +919,6 @@ void tst_QStateMachine::brokenStateIsNeverEntered() void tst_QStateMachine::transitionToStateNotInGraph() { - QSKIP("Hangs", SkipAll); - s_countWarnings = false; QStateMachine machine; @@ -930,13 +928,14 @@ void tst_QStateMachine::transitionToStateNotInGraph() machine.setInitialState(initialState); QState *independentState = new QState(); + independentState->setObjectName("independentState"); initialState->addTransition(independentState); machine.start(); QCoreApplication::processEvents(); QCOMPARE(machine.configuration().count(), 1); - QVERIFY(machine.configuration().contains(initialState)); + QVERIFY(machine.configuration().contains(qobject_cast(machine.rootState())->errorState())); } void tst_QStateMachine::customErrorStateNotInGraph() -- cgit v0.12 From a99a849dffc51a76256e880a81e6829c76199559 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 7 May 2009 11:41:34 +0200 Subject: Addeed a warning if one is trying to animate a property that's not part of the object Task-number: 251763 --- src/corelib/animation/qpropertyanimation.cpp | 2 ++ tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 9a0c5bc..65e2f57 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -97,6 +97,8 @@ void QPropertyAnimationPrivate::updateMetaProperty() property = mo->property(propertyIndex); propertyType = property.userType(); } else { + if (!target->dynamicPropertyNames().contains(propertyName)) + qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData()); hasMetaProperty = 2; } } diff --git a/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp index f0deab5..2e5fd00 100644 --- a/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp +++ b/tests/auto/qpropertyanimation/tst_qpropertyanimation.cpp @@ -624,6 +624,7 @@ QVariant xaxisQPointInterpolator(const QPointF &f, const QPointF &t, qreal progr void tst_QPropertyAnimation::interpolated() { QObject o; + o.setProperty("point", QPointF()); //this will avoid warnings o.setProperty("number", qVariantFromValue(Number(42))); QCOMPARE(qVariantValue(o.property("number")), Number(42)); { @@ -649,9 +650,9 @@ void tst_QPropertyAnimation::interpolated() anim.start(); anim.pause(); anim.setCurrentTime(100); - QCOMPARE(o.property("point").toPointF(), QPointF(10, 0)); + QCOMPARE(o.property("point"), QVariant(QPointF(10, 0))); anim.setCurrentTime(500); - QCOMPARE(o.property("point").toPointF(), QPointF(50, 0)); + QCOMPARE(o.property("point"), QVariant(QPointF(50, 0))); } { // unregister it and see if we get back the default behaviour -- cgit v0.12 From 56d27b54e2fe64782250e8e39012f345588cfad5 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 11:45:19 +0200 Subject: Rename NoDefaultStateInHistoryState -> NoDefaultStateInHistoryStateError for consistency The other error values have Error in the name for namespacing purposes. --- src/corelib/statemachine/qstatemachine.cpp | 8 ++++---- src/corelib/statemachine/qstatemachine.h | 2 +- tests/auto/qstatemachine/tst_qstatemachine.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index efcf707..dcdf5ed 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -595,7 +595,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, hlst.append(QHistoryStatePrivate::get(h)->defaultState); if (hlst.isEmpty()) { - setError(QStateMachine::NoDefaultStateInHistoryState, h); + setError(QStateMachine::NoDefaultStateInHistoryStateError, h); } else { for (int k = 0; k < hlst.size(); ++k) { QAbstractState *s0 = hlst.at(k); @@ -981,7 +981,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta .arg(currentContext->objectName()); break; - case QStateMachine::NoDefaultStateInHistoryState: + case QStateMachine::NoDefaultStateInHistoryStateError: Q_ASSERT(currentContext != 0); errorString = QStateMachine::tr("Missing default state in history state '%1'") @@ -1568,9 +1568,9 @@ void QStateMachine::setErrorState(QAbstractState *state) \value NoInitialStateError The machine has entered a QState with children which does not have an initial state set. The context of this error is the state which is missing an initial state. - \value NoDefaultStateInHistoryState The machine has entered a QHistoryState which does not have + \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have a default state set. The context of this error is the QHistoryState which is missing a - default state. + default state. \sa setErrorState() */ diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index d0927a3..d73404a 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -86,7 +86,7 @@ public: enum Error { NoError, NoInitialStateError, - NoDefaultStateInHistoryState, + NoDefaultStateInHistoryStateError, NoCommonAncestorForTransitionError }; diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index e7ea403..3876a20 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -877,7 +877,7 @@ void tst_QStateMachine::historyStateHasNowhereToGo() QCOMPARE(machine.configuration().count(), 1); QVERIFY(machine.configuration().contains(machine.errorState())); - QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryState); + QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryStateError); QCOMPARE(machine.errorString(), QString::fromLatin1("Missing default state in history state 'historyState'")); } -- cgit v0.12 From 2edb7ce649bba7221f02aeae021645e219e25f70 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 7 May 2009 11:51:16 +0200 Subject: doc: Add documentation for NoCommonAncestorForTransitionError enum --- src/corelib/statemachine/qstatemachine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index dcdf5ed..7f2132d 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1571,6 +1571,11 @@ void QStateMachine::setErrorState(QAbstractState *state) \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have a default state set. The context of this error is the QHistoryState which is missing a default state. + \value NoCommonAncestorForTransitionError The machine has selected a transition whose source + and targets are not part of the same tree of states, and thus are not part of the same + state machine. Commonly, this could mean that one of the states has not been given + any parent or added to any machine. The context of this error is the source state of + the transition. \sa setErrorState() */ -- cgit v0.12 From 1e404bcb6df5127a1d0e24ed11cce1c0260a57e9 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Thu, 7 May 2009 09:17:37 +0200 Subject: store top-level animation in dedicated variable The animation itself is used by subsequent code, so we mustn't change it. --- src/corelib/statemachine/qstatemachine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 7f2132d..4533115 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -713,9 +713,10 @@ void QStateMachinePrivate::applyProperties(const QList &tr // Stop the (top-level) animation. // ### Stopping nested animation has weird behavior. - while (QAnimationGroup *group = anim->group()) - anim = group; - anim->stop(); + QAbstractAnimation *topLevelAnim = anim; + while (QAnimationGroup *group = topLevelAnim->group()) + topLevelAnim = group; + topLevelAnim->stop(); if (resetAnimationEndValues.contains(anim)) { qobject_cast(anim)->setEndValue(QVariant()); // ### generalize -- cgit v0.12 From 81eebfbe01edb002d55c3504cc2558689cf0f936 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Thu, 7 May 2009 12:40:38 +0200 Subject: add QStateMachine::isRunning() --- src/corelib/statemachine/qstatemachine.cpp | 11 +++++++ src/corelib/statemachine/qstatemachine.h | 2 ++ tests/auto/qstatemachine/tst_qstatemachine.cpp | 42 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 4533115..21e564c 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1728,6 +1728,17 @@ void QStateMachine::removeState(QAbstractState *state) } /*! + Returns whether this state machine is running. + + start(), stop() +*/ +bool QStateMachine::isRunning() const +{ + Q_D(const QStateMachine); + return (d->state == QStateMachinePrivate::Running); +} + +/*! Starts this state machine. The machine will reset its configuration and transition to the initial state. When a final top-level state (QFinalState) is entered, the machine will emit the finished() signal. diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index d73404a..5dc6c0b 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -108,6 +108,8 @@ public: QString errorString() const; void clearError(); + bool isRunning() const; + #ifndef QT_NO_ANIMATION bool animationsEnabled() const; void setAnimationsEnabled(bool enabled); diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 3876a20..edd6459 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -104,6 +104,7 @@ private slots: void signalTransitions(); void eventTransitions(); void historyStates(); + void startAndStop(); void transitionToRootState(); void transitionEntersParent(); @@ -1094,14 +1095,17 @@ void tst_QStateMachine::stateEntryAndExit() s2->addTransition(s3); QSignalSpy startedSpy(&machine, SIGNAL(started())); + QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); QSignalSpy finishedSpy(&machine, SIGNAL(finished())); machine.setInitialState(s1); QVERIFY(machine.configuration().isEmpty()); globalTick = 0; + QVERIFY(!machine.isRunning()); machine.start(); QTRY_COMPARE(startedSpy.count(), 1); QTRY_COMPARE(finishedSpy.count(), 1); + QTRY_COMPARE(stoppedSpy.count(), 0); QCOMPARE(machine.configuration().count(), 1); QVERIFY(machine.configuration().contains(s3)); @@ -1826,6 +1830,44 @@ void tst_QStateMachine::historyStates() QTRY_COMPARE(finishedSpy.count(), 1); } +void tst_QStateMachine::startAndStop() +{ + QStateMachine machine; + QSignalSpy startedSpy(&machine, SIGNAL(started())); + QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + QVERIFY(!machine.isRunning()); + QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start."); + machine.start(); + QCOMPARE(startedSpy.count(), 0); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + QVERIFY(!machine.isRunning()); + machine.stop(); + QCOMPARE(startedSpy.count(), 0); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + + QState *s1 = new QState(machine.rootState()); + machine.setInitialState(s1); + machine.start(); + QTRY_COMPARE(machine.isRunning(), true); + QTRY_COMPARE(startedSpy.count(), 1); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(machine.configuration().count(), 1); + QVERIFY(machine.configuration().contains(s1)); + + machine.stop(); + QTRY_COMPARE(machine.isRunning(), false); + QTRY_COMPARE(stoppedSpy.count(), 1); + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 0); + + QCOMPARE(machine.configuration().count(), 1); + QVERIFY(machine.configuration().contains(s1)); +} + void tst_QStateMachine::defaultGlobalRestorePolicy() { QStateMachine machine; -- cgit v0.12 From 8b57ae82ef507db1912a35fbe5d60f2cc3668cdb Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 7 May 2009 14:44:22 +0200 Subject: change the API of private class for QAbstractAnimation to allow setting the timer interval. We also export the private clas so it can be used by other modules --- src/corelib/animation/qabstractanimation.cpp | 34 ++++++++++++++++++++-------- src/corelib/animation/qabstractanimation_p.h | 15 ++++++++---- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 93ecc73..6a824b6 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -156,13 +156,13 @@ #include #include -#define TIMER_INTERVAL 16 +#define DEFAULT_TIMER_INTERVAL 16 QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QThreadStorage, unifiedTimer); -QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), consistentTimingInterval(0) +QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), consistentTiming(false) { } @@ -190,13 +190,29 @@ void QUnifiedTimer::updateRecentlyStartedAnimations() } /* - this allows to haeve a consistent timer interval at each tick from the timer + defines the timing interval. Default is DEFAULT_TIMER_INTERVAL +*/ +void QUnifiedTimer::setTimingInterval(int interval) +{ + timingInterval = interval; + if (animationTimer.isActive()) { + //we changed the timing interval + animationTimer.start(timingInterval, this); + } +} + +/* + this allows to have a consistent timer interval at each tick from the timer not taking the real time that passed into account. - Just set this to 0 if you want to get back to a time-driven behaviour. - */ -void QUnifiedTimer::setConsitentTiming(int interval) +*/ +void QUnifiedTimer::setConsitentTiming(bool b) +{ + consistentTiming = b; +} + +int QUnifiedTimer::elapsedTime() const { - consistentTimingInterval = interval; + return lastTick; } void QUnifiedTimer::timerEvent(QTimerEvent *event) @@ -204,7 +220,7 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event) //this is simply the time we last received a tick const int oldLastTick = lastTick; if (time.isValid()) - lastTick = consistentTimingInterval > 0 ? oldLastTick + consistentTimingInterval : time.elapsed(); + lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed(); //we transfer the waiting animations into the "really running" state updateRecentlyStartedAnimations(); @@ -215,7 +231,7 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event) animationTimer.stop(); time = QTime(); } else { - animationTimer.start(TIMER_INTERVAL, this); + animationTimer.start(timingInterval, this); lastTick = 0; time.start(); } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 0e10b9a..49c0195 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -110,7 +110,7 @@ private: }; -class QUnifiedTimer : public QObject +class Q_CORE_EXPORT QUnifiedTimer : public QObject { private: QUnifiedTimer(); @@ -118,13 +118,17 @@ private: public: static QUnifiedTimer *instance(); - void timerEvent(QTimerEvent *); - void updateTimer(); void registerAnimation(QAbstractAnimation *animation); void unregisterAnimation(QAbstractAnimation *animation); - void setConsitentTiming(int interval); + void setTimingInterval(int interval); + void setConsitentTiming(bool consistent); + + int elapsedTime() const; +protected: + void timerEvent(QTimerEvent *); + void updateTimer(); private: void updateRecentlyStartedAnimations(); @@ -132,7 +136,8 @@ private: QBasicTimer animationTimer, startStopAnimationTimer; QTime time; int lastTick; - int consistentTimingInterval; + int timingInterval; + bool consistentTiming; QList animations, animationsToStart; }; -- cgit v0.12