Commit 29d08c50 authored by Emmanuel Promayon's avatar Emmanuel Promayon

FIXED action state machine autonext now really simulate the user behaviour + XML output bug

parent 1222f74c
......@@ -43,6 +43,7 @@
* @brief
* The state (in a state machine point of view) corresponding to the current processed action.
*
* By default an ActionState is not defined as being the initial state.
*/
class ActionState : public QState {
......@@ -69,30 +70,33 @@ public:
virtual camitk::Action::ApplyStatus applyAction();
/// Adds a possible transition from this action
ActionTransition* addActionTransition(QString buttonText, QAbstractState* nextState,
ActionTransition* addActionTransition(QString transitionName, QAbstractState* nextState,
bool applyAction = true, QVector<camitk::Action::ApplyStatus> disableConditions = QVector<camitk::Action::ApplyStatus>());
// get the whole action state widget (used by the ActionStateViewer)
ActionStateWidget* getWidget();
// set the status of previous action and modify description/possible action accordingly
void setPreviousActionStatus(camitk::Action::ApplyStatus status);
void setFinal();
/// get the names and type of all input components
const QMap<QString, QString>& getInputComponents();
/// get the names and type of all output components
const QMap<QString, QString>& getOutputComponents();
/// manually trigger the state
void trigger();
/// programmatically call the onEntry() method (used during autonext)
void autoNextEntry();
/// programmatically call the onExit() method (used during autonext)
void autoNextExit();
protected:
/// Reimplemented from QState
/// @{
virtual void onEntry ( QEvent* event );
virtual void onEntry(QEvent* event);
virtual void onExit ( QEvent* event );
virtual void onExit(QEvent* event);
///@}
/// Name of the state action (may not be the same as the action's name)
......@@ -136,6 +140,5 @@ protected:
/// Keep track of time...
QTime* startTime;
};
#endif // ACTIONSTATE_H
......@@ -120,52 +120,37 @@ ActionStateMachine::ActionStateMachine(int& argc, char** argv, QString inputFile
// ---------------------- destructor ----------------------------
ActionStateMachine::~ActionStateMachine() {
QTime endTime = QTime::currentTime();
(*logStream) << "\t<endTime>" << endTime.toString("hh:mm:ss:zzz") << "</endTime>" << endl;
(*logStream) << "\t<timeEnlapsed unit='ms'>" << (startTime->elapsed()) << "</timeEnlapsed>" << endl;
(*logStream) << "</application>" << endl;
logFile->close();
}
// ---------------------- autoNext ----------------------------
void ActionStateMachine::autoNext() {
ActionState* currentState;
ActionState* nextState;
void ActionStateMachine::autoNext() {
// if autonext is called, then this is an automatic test, there won't be any user to close the dialog
setProperty("Message Box Level", InterfaceLogger::NONE);
CAMITK_INFO(tr("Starting autonext..."))
// get the first initial state (there should only be one)
currentState = dynamic_cast<ActionState*>(machine.configuration().toList().first());
// machine.configuration() returns all the current state, the first on is the active state
ActionState* currentState = dynamic_cast<ActionState*>(machine.configuration().toList().first());
// loop until no more state is available
while (currentState) {
CAMITK_INFO(tr("Entering state \"%1\"").arg(currentState->getName()))
nextState = nullptr;
// get the next state by looking for the "Next" transition
foreach (QAbstractTransition* currentStateTransition, currentState->transitions()) {
ActionTransition* currentActionTransition = dynamic_cast<ActionTransition*>(currentStateTransition);
if (currentActionTransition->getButtonText() == "Next" || currentActionTransition->getButtonText() == "Quit") {
// "Next" or "Quit" is found, activate the transition
CAMITK_INFO(tr("Activating Transition \"%1\"").arg(currentActionTransition->getButtonText()))
currentActionTransition->onTransition(nullptr);
// update the next state to enter
nextState = dynamic_cast<ActionState*>(currentActionTransition->targetState());
while (currentState!=nullptr && currentState->transitions().size()>0) {
// look for the "Next" or "Quit" transition
auto it = currentState->transitions().begin();
bool foundNextState = false;
while (it!=currentState->transitions().end() && !foundNextState) { // && nextState==nullptr) {
// all transition in this state machine are ActionTransition instances...
ActionTransition* currentActionTransition = dynamic_cast<ActionTransition*>(*it);
//... in which we can look for the "Next" or "Quit" transition
if (currentActionTransition->isNamed("Next") || currentActionTransition->isNamed("Quit")) {
// activate the transition (simulate a click on the button)
currentActionTransition->autoNext(); // activating the "Quit" transition enter the final state, which make the state machine to emit the finished() signal
foundNextState = true;
}
++it;
}
// activate currentState
if (currentState) {
CAMITK_INFO(tr("Triggering state"))
currentState->trigger();
}
// next state
currentState = nextState;
}
CAMITK_INFO(tr("Quitting autonext and application"))
quit();
// get the new current active state
currentState = dynamic_cast<ActionState*>(machine.configuration().toList().first());
} while (currentState!=nullptr);
}
// ---------------------- initMainWindow ----------------------------
......@@ -253,7 +238,10 @@ QString ActionStateMachine::parseSCXMLTree() throw(AbortException) {
// Connect the end of the machine with the end of the application
QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
// and connect the about to quit with some final cleanup method (recommended instead using destructor to cleanup)
QObject::connect(this, SIGNAL(aboutToQuit()), this, SLOT(finished()));
// Ok, Actions and Wizard are created. We do not need the file any more.
// Clean up:
delete statesMap;
......@@ -261,6 +249,16 @@ QString ActionStateMachine::parseSCXMLTree() throw(AbortException) {
return applicationName;
}
// ---------------------- finished ----------------------------
void ActionStateMachine::finished() {
QTime endTime = QTime::currentTime();
(*logStream) << "\t<endTime>" << endTime.toString("hh:mm:ss:zzz") << "</endTime>" << endl;
(*logStream) << "\t<timeEnlapsed unit='ms'>" << (startTime->elapsed()) << "</timeEnlapsed>" << endl;
(*logStream) << "</application>" << endl;
logFile->close();
}
// ---------------------- createAllActionStates ----------------------------
void ActionStateMachine::createAllActionStates(QDomNodeList nodeList) throw(AbortException) {
int nbStates = nodeList.size();
......@@ -306,7 +304,8 @@ void ActionStateMachine::createAllActionStates(QDomNodeList nodeList) throw(Abor
}
}
// Do not forget the final state
theEnd = new QFinalState(&machine);
finalState = new QFinalState();
machine.addState(finalState);
//-- check that all input component exists as output components
// 1. build the map
......@@ -361,7 +360,6 @@ void ActionStateMachine::createTransitions(QDomNodeList nodeList) throw(AbortExc
// Check if this state is final
bool isFinal = (element.attribute("final", "false").toLower() == QString("true"));
// Find its transitions (transition children nodes)
QDomNodeList transitionsList = element.elementsByTagName("transition");
for (int transNb = 0; transNb < transitionsList.size(); transNb++) {
......@@ -411,7 +409,7 @@ void ActionStateMachine::createTransitions(QDomNodeList nodeList) throw(AbortExc
}
if (isFinal) {
state->addActionTransition("Quit", theEnd, false);
state->addActionTransition("Quit", finalState, false);
}
}
......
......@@ -72,8 +72,11 @@ public slots:
/// Automatically loop to apply to next state for all states
void autoNext();
private slots:
/// finish everything properly when the state machine entered the final state and quit
void finished();
protected:
/// initialized main window
void initMainWindow();
......@@ -102,7 +105,7 @@ protected:
QMap<QString, ActionState*>* statesMap;
/// Final State
QFinalState* theEnd;
QFinalState* finalState;
/// Where to save all files
QDir saveDirectory;
......
......@@ -27,11 +27,14 @@
#include <Application.h>
#include <Component.h>
#include <Log.h>
using namespace camitk;
// --------------- constructor --------------
ActionTransition::ActionTransition(QObject* sender, const char* signal, QState* sourceState, QString buttonText, bool applyPreviousAction, QTextStream* logStream) : QSignalTransition(sender, signal, sourceState) {
this->buttonText = buttonText;
ActionTransition::ActionTransition(QPushButton* sender, const char* signal, QState* sourceState, bool applyPreviousAction, QTextStream* logStream) : QSignalTransition(sender, signal, sourceState) {
myButton = sender;
this->applyPreviousAction = applyPreviousAction;
this->logStream = logStream;
}
......@@ -41,7 +44,21 @@ void ActionTransition::onTransition(QEvent* e) {
if (logStream != NULL) {
startTime = new QTime();
startTime->start();
(*logStream) << "\t<transition>" << endl;
ActionState* asS = dynamic_cast<ActionState*>(sourceState());
if (asS!=nullptr) {
QString comment;
comment = "\t<!-- ActionTransition::onTransition source:" + asS->getName();
ActionState* asD = dynamic_cast<ActionState*>(targetState());
if (asD!=nullptr) {
comment += " dest:" + asD->getName();
}
else {
comment += " dest: none";
}
comment += " -->";
(*logStream) << comment << endl;
}
(*logStream) << "\t<transition>" << endl;
(*logStream) << "\t\t<startTime>" << startTime->toString("hh:mm:ss:zzz") << "</startTime>" << endl;
}
......@@ -51,6 +68,7 @@ void ActionTransition::onTransition(QEvent* e) {
QAbstractState* previousState = this->sourceState();
ActionState* previousActionState = dynamic_cast<ActionState*> (previousState);
// if previous is initialState, then just call "onExit()"
if ((previousState) && (applyPreviousAction)) {
status = previousActionState->applyAction();
}
......@@ -126,14 +144,9 @@ void ActionTransition::onTransition(QEvent* e) {
}
}
// --------------- setButtonText --------------
void ActionTransition::setButtonText(QString buttonText) {
this->buttonText = buttonText;
}
// --------------- getButtonText --------------
QString ActionTransition::getButtonText() {
return this->buttonText;
// --------------- isNamed --------------
bool ActionTransition::isNamed(QString name) const {
return (myButton->text() == name);
}
// --------------- addComponentToClose --------------
......@@ -143,3 +156,9 @@ void ActionTransition::addComponentToClose(QString compName, QString compType, b
componentsToForceClose.append(compName);
}
}
// --------------- autoNext --------------
void ActionTransition::autoNext() {
// simulate the click
myButton->clicked();
}
......@@ -31,6 +31,7 @@
#include <QMap>
#include <QTextStream>
#include <QStringList>
#include <QPushButton>
class ActionState;
/**
......@@ -39,7 +40,9 @@ class ActionState;
* @brief
* This class handle a transition between two states (including previous/next buttons).
* Specific things can happen for CamiTK SCXML transition (e.g., apply the selected action before going to the next, closing components...)
*
*
* The transition's name is set as the button's text.
*
* Example:
* \code
* <camitk:onTransition>
......@@ -58,7 +61,7 @@ class ActionTransition : public QSignalTransition {
public:
/// constructor: takes at least the state and signal considered for the transition
ActionTransition(QObject* sender, const char* signal, QState* sourceState = 0, QString buttonText = "", bool applyPreviousAction = true, QTextStream* logStream = NULL);
ActionTransition(QPushButton* sender, const char* signal, QState* sourceState = 0, bool applyPreviousAction = true, QTextStream* logStream = NULL);
/// add a component's name and type to the list of component to close during the transition.
/// Set force to "true" in order to close the component independently of its modified flag.
......@@ -67,16 +70,13 @@ public:
/// called during the transition
virtual void onTransition(QEvent* e);
/// the transition button's text
void setButtonText(QString buttonText);
/// Check the name of the transition (i.e. text of the button)
bool isNamed(QString) const;
/// get the transition button's text
QString getButtonText();
/// programmatically activate the transition (during autoNext), i.e. call "click" on the button
void autoNext();
private:
/// the text of the push button displayed in the ASM
QString buttonText;
/// should the action be applied during the transition (default set to true)
bool applyPreviousAction;
......@@ -91,5 +91,8 @@ private:
/// Keep track of time (needed for the log)
QTime* startTime;
/// the button that controls this transition
QPushButton* myButton;
};
#endif // ACTIONTRANSITION_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment