summaryrefslogtreecommitdiffstats
path: root/src/corelib/statemachine/qstatemachine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/statemachine/qstatemachine.cpp')
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp188
1 files changed, 60 insertions, 128 deletions
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index e5d019dc8b..687f676819 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -160,6 +160,8 @@ QT_BEGIN_NAMESPACE
\since 5.4
\brief the running state of this state machine
+
+ \sa start(), stop(), started(), stopped(), runningChanged()
*/
#ifndef QT_NO_ANIMATION
@@ -365,9 +367,9 @@ static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tra
if (!historyConfiguration.isEmpty()) {
// There is a saved history, so apply that.
targets.unite(historyConfiguration.toSet());
- } else if (QAbstractState *defaultState = historyState->defaultState()) {
- // Qt does not support initial transitions, but uses the default state of the history state for this.
- targets.insert(defaultState);
+ } else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) {
+ // No saved history, take all default transition targets.
+ targets.unite(defaultTransition->targetStates().toSet());
} else {
// Woops, we found a history state without a default state. That's not valid!
QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine());
@@ -383,10 +385,6 @@ static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tra
return targetsList;
}
-template <class T>
-static uint qHash(const QPointer<T> &p)
-{ return qHash(p.data()); }
-
QStateMachinePrivate::QStateMachinePrivate()
{
isMachine = true;
@@ -410,13 +408,6 @@ QStateMachinePrivate::~QStateMachinePrivate()
qDeleteAll(externalEventQueue);
}
-QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q)
-{
- if (q)
- return q->d_func();
- return 0;
-}
-
QState *QStateMachinePrivate::rootState() const
{
return const_cast<QStateMachine*>(q_func());
@@ -684,7 +675,7 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransit
qDebug() << q_func() << ": computed entry set:" << enteredStates;
#endif
- QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForEnteredStates =
+ QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForEnteredStates =
computePropertyAssignments(enteredStates, pendingRestorables);
if (!pendingRestorables.isEmpty()) {
// Add "implicit" assignments for restored properties to the first
@@ -795,7 +786,7 @@ QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTr
}
void QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractState*> &statesToExit_sorted,
- const QHash<QAbstractState*, QList<QPropertyAssignment> > &assignmentsForEnteredStates)
+ const QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
{
for (int i = 0; i < statesToExit_sorted.size(); ++i) {
QAbstractState *s = statesToExit_sorted.at(i);
@@ -943,7 +934,7 @@ QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t
void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
const QList<QAbstractState*> &statesToEnter_sorted,
const QSet<QAbstractState*> &statesForDefaultEntry,
- QHash<QAbstractState*, QList<QPropertyAssignment> > &propertyAssignmentsForState
+ QHash<QAbstractState*, QVector<QPropertyAssignment> > &propertyAssignmentsForState
#ifndef QT_NO_ANIMATION
, const QList<QAbstractAnimation *> &selectedAnimations
#endif
@@ -966,7 +957,7 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
// Immediately set the properties that are not animated.
{
- QList<QPropertyAssignment> assignments = propertyAssignmentsForState.value(s);
+ QVector<QPropertyAssignment> assignments = propertyAssignmentsForState.value(s);
for (int i = 0; i < assignments.size(); ++i) {
const QPropertyAssignment &assn = assignments.at(i);
if (globalRestorePolicy == QState::RestoreProperties) {
@@ -989,9 +980,16 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
QAbstractStatePrivate::get(s)->callOnEntry(event);
QAbstractStatePrivate::get(s)->emitEntered();
- if (statesForDefaultEntry.contains(s)) {
- // ### executeContent(s.initial.transition.children())
- }
+
+ // FIXME:
+ // See the "initial transitions" comment in addDescendantStatesToEnter first, then implement:
+// if (statesForDefaultEntry.contains(s)) {
+// // ### executeContent(s.initial.transition.children())
+// }
+ Q_UNUSED(statesForDefaultEntry);
+
+ if (QHistoryState *h = toHistoryState(s))
+ QAbstractTransitionPrivate::get(h->defaultTransition())->callOnTransition(event);
// Emit propertiesAssigned signal if the state has no animated properties.
{
@@ -1052,69 +1050,6 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
// qDebug() << "configuration:" << configuration.toList();
}
-void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
- QSet<QAbstractState*> &statesToEnter,
- QSet<QAbstractState*> &statesForDefaultEntry)
-{
- if (QHistoryState *h = toHistoryState(s)) {
- QList<QAbstractState*> hconf = QHistoryStatePrivate::get(h)->configuration;
- if (!hconf.isEmpty()) {
- for (int k = 0; k < hconf.size(); ++k) {
- QAbstractState *s0 = hconf.at(k);
- addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry);
- }
-#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q_func() << ": restoring"
- << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
- << "history from" << s << ':' << hconf;
-#endif
- } else {
- QList<QAbstractState*> hlst;
- if (QHistoryStatePrivate::get(h)->defaultState)
- hlst.append(QHistoryStatePrivate::get(h)->defaultState);
-
- if (hlst.isEmpty()) {
- setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
- } else {
- for (int k = 0; k < hlst.size(); ++k) {
- QAbstractState *s0 = hlst.at(k);
- addStatesToEnter(s0, root, statesToEnter, statesForDefaultEntry);
- }
-#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q_func() << ": initial history targets for" << s << ':' << hlst;
-#endif
- }
- }
- } else {
- if (s == rootState()) {
- // Error has already been set by exitStates().
- Q_ASSERT(error != QStateMachine::NoError);
- return;
- }
- statesToEnter.insert(s);
- if (isParallel(s)) {
- QState *grp = toStandardState(s);
- QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
- for (int i = 0; i < lst.size(); ++i) {
- QAbstractState *child = lst.at(i);
- addStatesToEnter(child, grp, statesToEnter, statesForDefaultEntry);
- }
- } else if (isCompound(s)) {
- statesForDefaultEntry.insert(s);
- QState *grp = toStandardState(s);
- QAbstractState *initial = grp->initialState();
- if (initial != 0) {
- Q_ASSERT(initial->machine() == q_func());
- addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry);
- } else {
- setError(QStateMachine::NoInitialStateError, grp);
- return;
- }
- }
- addAncestorStatesToEnter(s, root, statesToEnter, statesForDefaultEntry);
- }
-}
-
/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. See
* QTBUG-44963 for details. The algorithm here is as described in
* http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm as of Friday March 13, 2015.
@@ -1165,8 +1100,8 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state,
#endif
} else {
QList<QAbstractState*> defaultHistoryContent;
- if (QHistoryStatePrivate::get(h)->defaultState)
- defaultHistoryContent.append(QHistoryStatePrivate::get(h)->defaultState);
+ if (QAbstractTransition *t = QHistoryStatePrivate::get(h)->defaultTransition)
+ defaultHistoryContent = t->targetStates();
if (defaultHistoryContent.isEmpty()) {
setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
@@ -1192,8 +1127,10 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state,
if (QAbstractState *initial = toStandardState(state)->initialState()) {
Q_ASSERT(initial->machine() == q_func());
+ // FIXME:
// Qt does not support initial transitions (which is a problem for parallel states).
// The way it simulates this for other states, is by having a single initial state.
+ // See also the FIXME in enterStates.
statesForDefaultEntry.insert(initial);
addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry);
@@ -1413,9 +1350,9 @@ void QStateMachinePrivate::unregisterRestorables(const QList<QAbstractState *> &
}
}
-QList<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const
+QVector<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const
{
- QList<QPropertyAssignment> result;
+ QVector<QPropertyAssignment> result;
QHash<RestorableId, QVariant>::const_iterator it;
for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) {
const RestorableId &id = it.key();
@@ -1470,16 +1407,16 @@ QHash<QStateMachinePrivate::RestorableId, QVariant> QStateMachinePrivate::comput
properties that should not be restored because they are assigned by an
entered state).
*/
-QHash<QAbstractState*, QList<QPropertyAssignment> > QStateMachinePrivate::computePropertyAssignments(
+QHash<QAbstractState*, QVector<QPropertyAssignment> > QStateMachinePrivate::computePropertyAssignments(
const QList<QAbstractState*> &statesToEnter_sorted, QHash<RestorableId, QVariant> &pendingRestorables) const
{
- QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForState;
+ QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForState;
for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
QState *s = toStandardState(statesToEnter_sorted.at(i));
if (!s)
continue;
- QList<QPropertyAssignment> &assignments = QStatePrivate::get(s)->propertyAssignments;
+ QVector<QPropertyAssignment> &assignments = QStatePrivate::get(s)->propertyAssignments;
for (int j = 0; j < assignments.size(); ++j) {
const QPropertyAssignment &assn = assignments.at(j);
if (assn.objectDeleted()) {
@@ -1556,8 +1493,11 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": entering error state" << currentErrorState << "from" << currentContext;
#endif
- QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
- addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ pendingErrorStates.insert(currentErrorState);
+ addDescendantStatesToEnter(currentErrorState, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ addAncestorStatesToEnter(currentErrorState, rootState(), pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ foreach (QAbstractState *s, configuration)
+ pendingErrorStates.remove(s);
} else {
qWarning("Unrecoverable error detected in running state machine: %s",
qPrintable(errorString));
@@ -1652,7 +1592,7 @@ QList<QAbstractAnimation *> QStateMachinePrivate::selectAnimations(const QList<Q
}
void QStateMachinePrivate::terminateActiveAnimations(QAbstractState *state,
- const QHash<QAbstractState*, QList<QPropertyAssignment> > &assignmentsForEnteredStates)
+ const QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
{
Q_Q(QStateMachine);
QList<QAbstractAnimation*> animations = animationsForState.take(state);
@@ -1677,9 +1617,9 @@ void QStateMachinePrivate::terminateActiveAnimations(QAbstractState *state,
// If there is no property assignment that sets this property,
// set the property to its target value.
bool found = false;
- QHash<QAbstractState*, QList<QPropertyAssignment> >::const_iterator it;
+ QHash<QAbstractState*, QVector<QPropertyAssignment> >::const_iterator it;
for (it = assignmentsForEnteredStates.constBegin(); it != assignmentsForEnteredStates.constEnd(); ++it) {
- const QList<QPropertyAssignment> &assignments = it.value();
+ const QVector<QPropertyAssignment> &assignments = it.value();
for (int j = 0; j < assignments.size(); ++j) {
if (assignments.at(j).hasTarget(assn.object, assn.propertyName)) {
found = true;
@@ -1697,15 +1637,15 @@ void QStateMachinePrivate::terminateActiveAnimations(QAbstractState *state,
void QStateMachinePrivate::initializeAnimations(QAbstractState *state, const QList<QAbstractAnimation *> &selectedAnimations,
const QList<QAbstractState*> &exitedStates_sorted,
- QHash<QAbstractState*, QList<QPropertyAssignment> > &assignmentsForEnteredStates)
+ QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
{
Q_Q(QStateMachine);
if (!assignmentsForEnteredStates.contains(state))
return;
- QList<QPropertyAssignment> &assignments = assignmentsForEnteredStates[state];
+ QVector<QPropertyAssignment> &assignments = assignmentsForEnteredStates[state];
for (int i = 0; i < selectedAnimations.size(); ++i) {
QAbstractAnimation *anim = selectedAnimations.at(i);
- QList<QPropertyAssignment>::iterator it;
+ QVector<QPropertyAssignment>::iterator it;
for (it = assignments.begin(); it != assignments.end(); ) {
QPair<QList<QAbstractAnimation*>, QList<QAbstractAnimation*> > ret;
const QPropertyAssignment &assn = *it;
@@ -1864,7 +1804,7 @@ void QStateMachinePrivate::_q_start()
QSet<QAbstractState*> statesForDefaultEntry;
QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache);
QHash<RestorableId, QVariant> pendingRestorables;
- QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForEnteredStates =
+ QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForEnteredStates =
computePropertyAssignments(enteredStates, pendingRestorables);
#ifndef QT_NO_ANIMATION
QList<QAbstractAnimation*> selectedAnimations = selectAnimations(transitions);
@@ -2097,23 +2037,6 @@ void QStateMachinePrivate::cancelAllDelayedEvents()
delayedEvents.clear();
}
-void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState)
-{
- Q_UNUSED(guiltyState);
- Q_ASSERT(guiltyState);
-
-#ifdef QSTATEMACHINE_DEBUG
- Q_Q(QStateMachine);
- qDebug() << q << ": emitting finished signal for" << forState;
-#endif
-
- QStatePrivate::get(forState)->emitFinished();
-}
-
-void QStateMachinePrivate::startupHook()
-{
-}
-
/*
This function is called when the state machine is performing no
microstep because no transition is enabled (i.e. an event is ignored).
@@ -2154,6 +2077,24 @@ void QStateMachinePrivate::endMacrostep(bool didChange)
Q_UNUSED(didChange);
}
+
+void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState)
+{
+ Q_UNUSED(guiltyState);
+ Q_ASSERT(guiltyState);
+
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+ qDebug() << q << ": emitting finished signal for" << forState;
+#endif
+
+ QStatePrivate::get(forState)->emitFinished();
+}
+
+void QStateMachinePrivate::startupHook()
+{
+}
+
namespace _QStateMachine_Internal{
class GoToStateTransition : public QAbstractTransition
@@ -2453,6 +2394,7 @@ void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalInd
QMetaMethod method = meta->method(signalIndex);
int argc = method.parameterCount();
QList<QVariant> vargs;
+ vargs.reserve(argc);
for (int i = 0; i < argc; ++i) {
int type = method.parameterType(i);
vargs.append(QVariant(type, argv[i+1]));
@@ -2636,11 +2578,6 @@ void QStateMachine::removeState(QAbstractState *state)
state->setParent(0);
}
-/*!
- Returns whether this state machine is running.
-
- \sa start(), stop()
-*/
bool QStateMachine::isRunning() const
{
Q_D(const QStateMachine);
@@ -2703,11 +2640,6 @@ void QStateMachine::stop()
}
}
-/*!
- Convenience functions to start/stop this state machine.
-
- \sa start(), stop(), started(), finished(), stopped()
-*/
void QStateMachine::setRunning(bool running)
{
if (running)
@@ -3272,7 +3204,7 @@ QStateMachine::WrappedEvent::~WrappedEvent()
\fn QStateMachine::runningChanged(bool running)
\since 5.4
- This signal is emitted when the running property is changed.
+ This signal is emitted when the running property is changed with \a running as argument.
\sa QStateMachine::running
*/