summaryrefslogtreecommitdiffstats
path: root/src/corelib/statemachine
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/statemachine')
-rw-r--r--src/corelib/statemachine/qstate_p.h8
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp63
-rw-r--r--src/corelib/statemachine/qstatemachine.h3
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h26
4 files changed, 70 insertions, 30 deletions
diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h
index 7fb40392e7..ec746caae1 100644
--- a/src/corelib/statemachine/qstate_p.h
+++ b/src/corelib/statemachine/qstate_p.h
@@ -68,14 +68,14 @@ QT_BEGIN_NAMESPACE
struct QPropertyAssignment
{
QPropertyAssignment()
- : object(0), explicitlySet(true) {}
+ : object(nullptr), explicitlySet(true) {}
QPropertyAssignment(QObject *o, const QByteArray &n,
const QVariant &v, bool es = true)
: object(o), propertyName(n), value(v), explicitlySet(es)
{}
bool objectDeleted() const { return !object; }
- void write() const { Q_ASSERT(object != 0); object->setProperty(propertyName, value); }
+ void write() const { Q_ASSERT(object != nullptr); object->setProperty(propertyName, value); }
bool hasTarget(QObject *o, const QByteArray &pn) const
{ return object == o && propertyName == pn; }
@@ -99,8 +99,8 @@ public:
QStatePrivate();
~QStatePrivate();
- static QStatePrivate *get(QState *q) { return q ? q->d_func() : 0; }
- static const QStatePrivate *get(const QState *q) { return q? q->d_func() : 0; }
+ static QStatePrivate *get(QState *q) { return q ? q->d_func() : nullptr; }
+ static const QStatePrivate *get(const QState *q) { return q? q->d_func() : nullptr; }
QList<QAbstractState*> childStates() const;
QList<QHistoryState*> historyStates() const;
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index ee3f7be279..945e36968f 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -140,6 +140,10 @@ QT_BEGIN_NAMESPACE
no error state applies to the erroneous state, the machine will stop
executing and an error message will be printed to the console.
+ \note Important: setting the \l{ChildMode} of a state machine to parallel (\l{ParallelStates})
+ results in an invalid state machine. It can only be set to (or kept as)
+ \l{ExclusiveStates}.
+
\sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework}
*/
@@ -370,10 +374,11 @@ static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tra
QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration;
if (!historyConfiguration.isEmpty()) {
// There is a saved history, so apply that.
- targets.unite(historyConfiguration.toSet());
+ targets.unite(QSet<QAbstractState *>(historyConfiguration.constBegin(), historyConfiguration.constEnd()));
} else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) {
// No saved history, take all default transition targets.
- targets.unite(defaultTransition->targetStates().toSet());
+ const auto &targetStates = defaultTransition->targetStates();
+ targets.unite(QSet<QAbstractState *>(targetStates.constBegin(), targetStates.constEnd()));
} else {
// Woops, we found a history state without a default state. That's not valid!
QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine());
@@ -384,7 +389,7 @@ static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tra
}
}
- targetsList = targets.toList();
+ targetsList = targets.values();
cache->insert(transition, targetsList);
return targetsList;
}
@@ -518,7 +523,7 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState
}
}
-QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool onlyCompound) const
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool onlyCompound)
{
if (states.isEmpty())
return 0;
@@ -537,10 +542,16 @@ QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool
if (ok)
return anc;
}
- return 0;
+
+ // Oops, this should never happen! The state machine itself is a common ancestor of all states,
+ // no matter what. But, for the onlyCompound case: we probably have a state machine whose
+ // childMode is set to parallel, which is illegal. However, we're stuck with it (and with
+ // exposing this invalid/dangerous API to users), so recover in the least horrible way.
+ setError(QStateMachine::StateMachineChildModeSetToParallelError, q_func());
+ return q_func(); // make the statemachine the LCA/LCCA (which it should have been anyway)
}
-QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states) const
+QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states)
{
return findLCA(states, true);
}
@@ -740,7 +751,7 @@ QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstrac
{
Q_ASSERT(cache);
- QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).toList();
+ QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).values();
std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
return statesToExit_sorted;
}
@@ -777,7 +788,7 @@ QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTr
// makes the state machine invalid.
if (error == QStateMachine::NoError)
setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
- QList<QAbstractState *> lst = pendingErrorStates.toList();
+ QList<QAbstractState *> lst = pendingErrorStates.values();
lst.prepend(t->sourceState());
domain = findLCCA(lst);
@@ -879,7 +890,7 @@ QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstra
pendingErrorStatesForDefaultEntry.clear();
}
- QList<QAbstractState*> statesToEnter_sorted = statesToEnter.toList();
+ QList<QAbstractState*> statesToEnter_sorted = statesToEnter.values();
std::sort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan);
return statesToEnter_sorted;
}
@@ -902,7 +913,7 @@ function getTransitionDomain(t)
*/
QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t,
const QList<QAbstractState *> &effectiveTargetStates,
- CalculationCache *cache) const
+ CalculationCache *cache)
{
Q_ASSERT(cache);
@@ -1483,6 +1494,14 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'")
.arg(currentContext->objectName());
break;
+
+ case QStateMachine::StateMachineChildModeSetToParallelError:
+ Q_ASSERT(currentContext != nullptr);
+
+ errorString = QStateMachine::tr("Child mode of state machine '%1' is not 'ExclusiveStates'!")
+ .arg(currentContext->objectName());
+ break;
+
default:
errorString = QStateMachine::tr("Unknown error");
};
@@ -1507,8 +1526,8 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
addAncestorStatesToEnter(currentErrorState, rootState(), pendingErrorStates, pendingErrorStatesForDefaultEntry);
pendingErrorStates -= configuration;
} else {
- qWarning("Unrecoverable error detected in running state machine: %s",
- qPrintable(errorString));
+ qWarning("Unrecoverable error detected in running state machine: %ls",
+ qUtf16Printable(errorString));
q->stop();
}
}
@@ -2444,9 +2463,13 @@ QStateMachine::QStateMachine(QObject *parent)
/*!
\since 5.0
+ \deprecated
Constructs a new state machine with the given \a childMode
and \a parent.
+
+ \warning Do not set the \a childMode to anything else than \l{ExclusiveStates}, otherwise the
+ state machine is invalid, and might work incorrectly!
*/
QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
: QState(*new QStateMachinePrivate, /*parentState=*/0)
@@ -2454,6 +2477,18 @@ QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
Q_D(QStateMachine);
d->childMode = childMode;
setParent(parent); // See comment in constructor above
+
+ if (childMode != ExclusiveStates) {
+ //### FIXME for Qt6: remove this constructor completely, and hide the childMode property.
+ // Yes, the StateMachine itself is conceptually a state, but it should only expose a limited
+ // number of properties. The execution algorithm (in the URL below) treats a state machine
+ // as a state, but from an API point of view, it's questionable if the QStateMachine should
+ // inherit from QState.
+ //
+ // See function findLCCA in https://www.w3.org/TR/2014/WD-scxml-20140529/#AlgorithmforSCXMLInterpretation
+ // to see where setting childMode to parallel will break down.
+ qWarning() << "Invalid childMode for QStateMachine" << this;
+ }
}
/*!
@@ -2503,6 +2538,10 @@ QStateMachine::~QStateMachine()
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.
+ \value StateMachineChildModeSetToParallelError The machine's \l childMode
+ property was set to \l{QState::ParallelStates}. This is illegal.
+ Only states may be declared as parallel, not the state machine
+ itself. This enum value was added in Qt 5.14.
\sa setErrorState()
*/
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
index e520285437..07781d09a4 100644
--- a/src/corelib/statemachine/qstatemachine.h
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -106,7 +106,8 @@ public:
NoError,
NoInitialStateError,
NoDefaultStateInHistoryStateError,
- NoCommonAncestorForTransitionError
+ NoCommonAncestorForTransitionError,
+ StateMachineChildModeSetToParallelError
};
explicit QStateMachine(QObject *parent = nullptr);
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index f3366ca5f7..f140023e31 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -108,10 +108,10 @@ public:
~QStateMachinePrivate();
static QStateMachinePrivate *get(QStateMachine *q)
- { return q ? q->d_func() : 0; }
+ { return q ? q->d_func() : nullptr; }
- QState *findLCA(const QList<QAbstractState*> &states, bool onlyCompound = false) const;
- QState *findLCCA(const QList<QAbstractState*> &states) const;
+ QState *findLCA(const QList<QAbstractState*> &states, bool onlyCompound = false);
+ QState *findLCCA(const QList<QAbstractState*> &states);
static bool transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2);
static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
@@ -160,7 +160,7 @@ public:
QSet<QAbstractState*> &statesForDefaultEntry, CalculationCache *cache);
QAbstractState *getTransitionDomain(QAbstractTransition *t,
const QList<QAbstractState *> &effectiveTargetStates,
- CalculationCache *cache) const;
+ CalculationCache *cache);
void addDescendantStatesToEnter(QAbstractState *state,
QSet<QAbstractState*> &statesToEnter,
QSet<QAbstractState*> &statesForDefaultEntry);
@@ -218,18 +218,18 @@ public:
QByteArray prop;
// two overloads because friends can't have default arguments
friend uint qHash(const RestorableId &key, uint seed)
- Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(std::declval<QByteArray>())))
+ noexcept(noexcept(qHash(std::declval<QByteArray>())))
{ return qHash(qMakePair(key.obj, key.prop), seed); }
- friend uint qHash(const RestorableId &key) Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(key, 0U)))
+ friend uint qHash(const RestorableId &key) noexcept(noexcept(qHash(key, 0U)))
{ return qHash(key, 0U); }
- friend bool operator==(const RestorableId &lhs, const RestorableId &rhs) Q_DECL_NOTHROW
+ friend bool operator==(const RestorableId &lhs, const RestorableId &rhs) noexcept
{ return lhs.obj == rhs.obj && lhs.prop == rhs.prop; }
- friend bool operator!=(const RestorableId &lhs, const RestorableId &rhs) Q_DECL_NOTHROW
+ friend bool operator!=(const RestorableId &lhs, const RestorableId &rhs) noexcept
{ return !operator==(lhs, rhs); }
public:
- explicit RestorableId(QObject *o, QByteArray p) Q_DECL_NOTHROW : guard(o), obj(o), prop(qMove(p)) {}
- QObject *object() const Q_DECL_NOTHROW { return guard; }
- QByteArray propertyName() const Q_DECL_NOTHROW { return prop; }
+ explicit RestorableId(QObject *o, QByteArray p) noexcept : guard(o), obj(o), prop(std::move(p)) {}
+ QObject *object() const noexcept { return guard; }
+ QByteArray propertyName() const noexcept { return prop; }
};
QHash<QAbstractState*, QHash<RestorableId, QVariant> > registeredRestorablesForState;
bool hasRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName) const;
@@ -271,7 +271,7 @@ public:
QList<QAbstractAnimation*> handledAnimations;
QList<QAbstractAnimation*> localResetEndValues;
- void swap(InitializeAnimationResult &other) Q_DECL_NOTHROW
+ void swap(InitializeAnimationResult &other) noexcept
{
qSwap(handledAnimations, other.handledAnimations);
qSwap(localResetEndValues, other.localResetEndValues);
@@ -313,7 +313,7 @@ public:
DelayedEvent(QEvent *e, int tid)
: event(e), timerId(tid) {}
DelayedEvent()
- : event(0), timerId(0) {}
+ : event(nullptr), timerId(0) {}
};
QHash<int, DelayedEvent> delayedEvents;
QHash<int, int> timerIdToDelayedEventId;