qstatemachine: add methods detect when a machine has processed an event

currently when adding an event it is not possible to know when processing
it has finished.
In particular if the event is ignored no method is called.
Adding virtual methods to the private implementation (binary compatibility).
These methods allow for extended automatic testing of the state machines.

Change-Id: Ib2d4caccc90ecc126e362d52c3558f5f9f846452
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
bb10
Fawzi Mohamed 2015-02-17 17:37:32 +01:00 committed by Erik Verbruggen
parent dcf0ececbf
commit e7feb95628
2 changed files with 53 additions and 2 deletions

View File

@ -1430,9 +1430,11 @@ void QStateMachinePrivate::_q_process()
Q_ASSERT(!processing);
processing = true;
processingScheduled = false;
beginMacrostep();
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": starting the event processing loop";
#endif
bool didChange = false;
while (processing) {
if (stop) {
processing = false;
@ -1473,15 +1475,17 @@ void QStateMachinePrivate::_q_process()
}
}
if (!enabledTransitions.isEmpty()) {
didChange = true;
q->beginMicrostep(e);
microstep(e, enabledTransitions.toList());
q->endMicrostep(e);
}
#ifdef QSTATEMACHINE_DEBUG
else {
noMicrostep();
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": no transitions enabled";
}
#endif
}
delete e;
}
#ifdef QSTATEMACHINE_DEBUG
@ -1494,6 +1498,7 @@ void QStateMachinePrivate::_q_process()
switch (stopProcessingReason) {
case EventQueueEmpty:
processedPendingEvents(didChange);
break;
case Finished:
state = NotRunning;
@ -1510,6 +1515,7 @@ void QStateMachinePrivate::_q_process()
emit q->runningChanged(false);
break;
}
endMacrostep(didChange);
}
void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
@ -1619,6 +1625,47 @@ void QStateMachinePrivate::cancelAllDelayedEvents()
delayedEvents.clear();
}
/*
This function is called when the state machine is performing no
microstep because no transition is enabled (i.e. an event is ignored).
The default implementation does nothing.
*/
void QStateMachinePrivate::noMicrostep()
{ }
/*
This function is called when the state machine has reached a stable
state (no pending events), and has not finished yet.
For each event the state machine receives it is guaranteed that
1) beginMacrostep is called
2) selectTransition is called at least once
3) begin/endMicrostep is called at least once or noMicrostep is called
at least once (possibly both, but at least one)
4) the state machine either enters an infinite loop, or stops (runningChanged(false),
and either finished or stopped are emitted), or processedPendingEvents() is called.
5) if the machine is not in an infinite loop endMacrostep is called
didChange is set to true if at least one microstep was performed, it is possible
that the machine returned to exactly the same state as before, but some transitions
were triggered.
The default implementation does nothing.
*/
void QStateMachinePrivate::processedPendingEvents(bool didChange)
{
Q_UNUSED(didChange);
}
void QStateMachinePrivate::beginMacrostep()
{ }
void QStateMachinePrivate::endMacrostep(bool didChange)
{
Q_UNUSED(didChange);
}
namespace _QStateMachine_Internal{
class GoToStateTransition : public QAbstractTransition

View File

@ -123,6 +123,10 @@ public:
QAbstractTransition *createInitialTransition() const;
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
virtual void noMicrostep();
virtual void processedPendingEvents(bool didChange);
virtual void beginMacrostep();
virtual void endMacrostep(bool didChange);
bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,