From 8af8db3810ec2d8d2d923f39e23512d30ae234d9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 12 Jun 2017 16:19:08 +0200 Subject: Fix emission of state changed signals The state index is not the same as its changed signal index. The changed signal is not being generated for history states. The current fix is that we create a hash cache of state index into the signal index of its appropriate signal just after we set the table data for the state machine. Task-number: QTBUG-61243 Change-Id: I778adaf6c2d626be17c50b558f93ec0035ea3325 Reviewed-by: Qt CI Bot Reviewed-by: Paolo Angelelli Reviewed-by: Ulf Hermann --- src/scxml/qscxmlstatemachine.cpp | 26 +++++++++++++++++++++++++- src/scxml/qscxmlstatemachine_p.h | 4 ++++ tests/auto/statemachine/historystate.scxml | 13 +++++++++++++ tests/auto/statemachine/tst_statemachine.cpp | 19 +++++++++++++++++++ tests/auto/statemachine/tst_statemachine.qrc | 1 + 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/auto/statemachine/historystate.scxml diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp index e57630f..9767a03 100644 --- a/src/scxml/qscxmlstatemachine.cpp +++ b/src/scxml/qscxmlstatemachine.cpp @@ -731,7 +731,9 @@ void QScxmlStateMachinePrivate::emitStateActive(int stateIndex, bool active) { Q_Q(QScxmlStateMachine); void *args[] = { Q_NULLPTR, const_cast(reinterpret_cast(&active)) }; - QMetaObject::activate(q, m_metaObject, stateIndex, args); + const int signalIndex = m_stateIndexToSignalIndex.value(stateIndex, -1); + if (signalIndex >= 0) + QMetaObject::activate(q, m_metaObject, signalIndex, args); } void QScxmlStateMachinePrivate::emitInvokedServicesChanged() @@ -755,6 +757,26 @@ void QScxmlStateMachinePrivate::attach(QScxmlStateMachineInfo *info) info, &QScxmlStateMachineInfo::transitionsTriggered); } +void QScxmlStateMachinePrivate::updateMetaCache() +{ + m_stateIndexToSignalIndex.clear(); + + if (!m_tableData) + return; + + if (!m_stateTable) + return; + + int signalIndex = 0; + for (int i = 0; i < m_stateTable->stateCount; ++i) { + const auto &s = m_stateTable->state(i); + if (!s.isHistoryState() && s.type != StateTable::State::Invalid) { + m_stateIndexToSignalIndex.insert(i, signalIndex); + ++signalIndex; + } + } +} + QStringList QScxmlStateMachinePrivate::stateNames(const std::vector &stateIndexes) const { QStringList names; @@ -1767,6 +1789,8 @@ void QScxmlStateMachine::setTableData(QScxmlTableData *tableData) == QScxmlExecutableContent::StateTable::terminator); } + d->updateMetaCache(); + emit tableDataChanged(tableData); } diff --git a/src/scxml/qscxmlstatemachine_p.h b/src/scxml/qscxmlstatemachine_p.h index bfa7bc1..388dd8d 100644 --- a/src/scxml/qscxmlstatemachine_p.h +++ b/src/scxml/qscxmlstatemachine_p.h @@ -283,6 +283,8 @@ public: void attach(QScxmlStateMachineInfo *info); const OrderedSet &configuration() const { return m_configuration; } + void updateMetaCache(); + private: QStringList stateNames(const std::vector &stateIndexes) const; std::vector historyStates(int stateIdx) const; @@ -379,6 +381,8 @@ private: bool isPaused() const { return m_runningState == Paused; } QScxmlInternal::StateMachineInfoProxy *m_infoSignalProxy; + + QHash m_stateIndexToSignalIndex; }; QT_END_NAMESPACE diff --git a/tests/auto/statemachine/historystate.scxml b/tests/auto/statemachine/historystate.scxml new file mode 100644 index 0000000..4b3a5e4 --- /dev/null +++ b/tests/auto/statemachine/historystate.scxml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/auto/statemachine/tst_statemachine.cpp b/tests/auto/statemachine/tst_statemachine.cpp index ed1f424..69d38b6 100644 --- a/tests/auto/statemachine/tst_statemachine.cpp +++ b/tests/auto/statemachine/tst_statemachine.cpp @@ -48,6 +48,7 @@ private Q_SLOTS: void activeStateNames_data(); void activeStateNames(); void connections(); + void historyState(); void onExit(); void eventOccurred(); @@ -251,6 +252,24 @@ void tst_StateMachine::connections() #endif } +void tst_StateMachine::historyState() +{ + QScopedPointer stateMachine( + QScxmlStateMachine::fromFile(QString(":/tst_statemachine/historystate.scxml"))); + QVERIFY(!stateMachine.isNull()); + + bool state2Reached = false; + QMetaObject::Connection state2Connection = stateMachine->connectToState("State2", + [&state2Reached](bool enabled) { + state2Reached = state2Reached || enabled; + }); + QVERIFY(state2Connection); + + stateMachine->start(); + + QTRY_VERIFY(state2Reached); +} + void tst_StateMachine::onExit() { #if defined(__cpp_return_type_deduction) && __cpp_return_type_deduction == 201304 diff --git a/tests/auto/statemachine/tst_statemachine.qrc b/tests/auto/statemachine/tst_statemachine.qrc index c31fe4c..78c1f00 100644 --- a/tests/auto/statemachine/tst_statemachine.qrc +++ b/tests/auto/statemachine/tst_statemachine.qrc @@ -6,5 +6,6 @@ ids1.scxml stateDotDoneEvent.scxml invoke.scxml + historystate.scxml -- cgit v1.2.3