diff options
-rw-r--r-- | src/scxml/qscxmldatamodel.cpp | 7 | ||||
-rw-r--r-- | src/scxml/qscxmlstatemachine.cpp | 24 | ||||
-rw-r--r-- | tests/auto/statemachine/tst_statemachine.cpp | 51 |
3 files changed, 63 insertions, 19 deletions
diff --git a/src/scxml/qscxmldatamodel.cpp b/src/scxml/qscxmldatamodel.cpp index 298981e..eaa15e8 100644 --- a/src/scxml/qscxmldatamodel.cpp +++ b/src/scxml/qscxmldatamodel.cpp @@ -95,10 +95,11 @@ void QScxmlDataModel::setStateMachine(QScxmlStateMachine *stateMachine) { Q_D(QScxmlDataModel); - if (d->m_stateMachine.value() == nullptr && stateMachine != nullptr) { + if (d->m_stateMachine.valueBypassingBindings() == nullptr && stateMachine != nullptr) { // the binding is removed only on the first valid set - // as the later attempts are ignored (removed when value is set below) - d->m_stateMachine = stateMachine; + // as the later attempts are ignored + d->m_stateMachine.removeBindingUnlessInWrapper(); + d->m_stateMachine.setValueBypassingBindings(stateMachine); stateMachine->setDataModel(this); d->m_stateMachine.notify(); } diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp index d0b62fc..1ccd37d 100644 --- a/src/scxml/qscxmlstatemachine.cpp +++ b/src/scxml/qscxmlstatemachine.cpp @@ -675,7 +675,8 @@ void QScxmlStateMachinePrivate::updateMetaCache() m_stateIndexToSignalIndex.clear(); m_stateNameToSignalIndex.clear(); - if (!m_tableData.value()) + const QScxmlTableData *tableData = m_tableData.valueBypassingBindings(); + if (!tableData) return; if (!m_stateTable) @@ -687,7 +688,7 @@ void QScxmlStateMachinePrivate::updateMetaCache() const auto &s = m_stateTable->state(i); if (!s.isHistoryState() && s.type != StateTable::State::Invalid) { m_stateIndexToSignalIndex.insert(i, signalIndex); - m_stateNameToSignalIndex.insert(m_tableData.value()->string(s.name), + m_stateNameToSignalIndex.insert(tableData->string(s.name), signalIndex + methodOffset); ++signalIndex; @@ -1650,10 +1651,11 @@ void QScxmlStateMachine::setDataModel(QScxmlDataModel *model) { Q_D(QScxmlStateMachine); - if (d->m_dataModel.value() == nullptr && model != nullptr) { + if (d->m_dataModel.valueBypassingBindings() == nullptr && model != nullptr) { // the binding is removed only on the first valid set - // as the later attempts are ignored (removed when value is set below) - d->m_dataModel = model; + // as the later attempts are ignored + d->m_dataModel.removeBindingUnlessInWrapper(); + d->m_dataModel.setValueBypassingBindings(model); model->setStateMachine(this); d->m_dataModel.notify(); emit dataModelChanged(model); @@ -1706,16 +1708,18 @@ void QScxmlStateMachine::setTableData(QScxmlTableData *tableData) { Q_D(QScxmlStateMachine); - if (d->m_tableData.value() == tableData) { - d->m_tableData.removeBindingUnlessInWrapper(); + d->m_tableData.removeBindingUnlessInWrapper(); + if (d->m_tableData.valueBypassingBindings() == tableData) return; - } - d->m_tableData = tableData; + d->m_tableData.setValueBypassingBindings(tableData); if (tableData) { d->m_stateTable = reinterpret_cast<const QScxmlExecutableContent::StateTable *>( tableData->stateMachineTable()); - if (objectName().isEmpty()) { + // cannot use objectName() here, because it creates binding loop + const QString currentObjectName = d->extraData + ? d->extraData->objectName.valueBypassingBindings() : QString(); + if (currentObjectName.isEmpty()) { setObjectName(tableData->name()); } if (d->m_stateTable->maxServiceId != QScxmlExecutableContent::StateTable::InvalidIndex) { diff --git a/tests/auto/statemachine/tst_statemachine.cpp b/tests/auto/statemachine/tst_statemachine.cpp index 5b717e9..6080d42 100644 --- a/tests/auto/statemachine/tst_statemachine.cpp +++ b/tests/auto/statemachine/tst_statemachine.cpp @@ -38,6 +38,8 @@ private Q_SLOTS: void logWithoutExpr(); void bindings(); + + void setTableDataUpdatesObjectNames(); }; void tst_StateMachine::stateNames_data() @@ -449,11 +451,16 @@ void tst_StateMachine::bindings() return; } + using StateMachinePtr = std::unique_ptr<QScxmlStateMachine>; + // -- QScxmlStateMachine::initialValues QVariantMap map1{{"map", 1}}; QVariantMap map2{{"map", 2}}; QTestPrivate::testReadWritePropertyBasics<QScxmlStateMachine, QVariantMap>( - *stateMachine1, map1, map2, "initialValues"); + *stateMachine1, map1, map2, "initialValues", + []() { + return StateMachinePtr{QScxmlStateMachine::fromFile(QString("not_a_real_file"))}; + }); if (QTest::currentTestFailed()) { qWarning() << "QScxmlStateMachine::initialValues bindable test failed."; return; @@ -468,7 +475,10 @@ void tst_StateMachine::bindings() MockLoader loader1; MockLoader loader2; QTestPrivate::testReadWritePropertyBasics<QScxmlStateMachine, QScxmlCompiler::Loader*>( - *stateMachine1, &loader1, &loader2, "loader"); + *stateMachine1, &loader1, &loader2, "loader", + []() { + return StateMachinePtr{QScxmlStateMachine::fromFile(QString("not_a_real_file"))}; + }); if (QTest::currentTestFailed()) { qWarning() << "QScxmlStateMachine::loader bindable test failed."; return; @@ -483,18 +493,25 @@ void tst_StateMachine::bindings() QScxmlNullDataModel model1; // data can only change once QTestPrivate::testWriteOncePropertyBasics<QScxmlStateMachine, QScxmlDataModel*>( - *stateMachine2, nullptr, &model1, "dataModel"); + *stateMachine2, nullptr, &model1, "dataModel", true, + []() { + return StateMachinePtr{QScxmlStateMachine::fromFile(QString("not_a_real_file"))}; + }); if (QTest::currentTestFailed()) { qWarning() << "QScxmlStateMachine::dataModel bindable test failed."; return; } // -- QScxmlStateMachine::tableData - // Use the statemachine to generate the tabledDatas for testing + // Use the statemachine to generate the tableData for testing std::unique_ptr<QScxmlStateMachine> stateMachine4( QScxmlStateMachine::fromFile(QString(":/tst_statemachine/invoke.scxml"))); QTestPrivate::testReadWritePropertyBasics<QScxmlStateMachine, QScxmlTableData*>( - *stateMachine2, stateMachine1.get()->tableData(), stateMachine4.get()->tableData(), "tableData"); + *stateMachine2, stateMachine1.get()->tableData(), stateMachine4.get()->tableData(), + "tableData", + []() { + return StateMachinePtr{QScxmlStateMachine::fromFile(QString("not_a_real_file"))}; + }); if (QTest::currentTestFailed()) { qWarning() << "QScxmlStateMachine::tableData bindable test failed."; return; @@ -528,7 +545,7 @@ void tst_StateMachine::bindings() std::unique_ptr<QScxmlStateMachine> stateMachine5( QScxmlStateMachine::fromFile(QString("not_a_real_file"))); // data can only change once - QTestPrivate::testWriteOncePropertyBasics<QScxmlDataModel, QScxmlStateMachine*>( + QTestPrivate::testWriteOncePropertyBasics<QScxmlNullDataModel, QScxmlStateMachine*>( dataModel1, nullptr, stateMachine5.get(), "stateMachine"); if (QTest::currentTestFailed()) { qWarning() << "QScxmlDataModel::stateMachine bindable test failed."; @@ -536,6 +553,28 @@ void tst_StateMachine::bindings() } } +void tst_StateMachine::setTableDataUpdatesObjectNames() +{ + std::unique_ptr<QScxmlStateMachine> stateMachine1( + QScxmlStateMachine::fromFile(QString(":/tst_statemachine/emptylog.scxml"))); + const QString sm1ObjectName = stateMachine1->objectName(); + std::unique_ptr<QScxmlStateMachine> stateMachine2( + QScxmlStateMachine::fromFile(QString(":/tst_statemachine/eventoccurred.scxml"))); + const QString sm2ObjectName = stateMachine2->objectName(); + QCOMPARE_NE(sm1ObjectName, sm2ObjectName); + + std::unique_ptr<QScxmlStateMachine> sm( + QScxmlStateMachine::fromFile(QString("not_a_real_file"))); + QVERIFY(sm->objectName().isEmpty()); + // no name set, so update object name + sm->setTableData(stateMachine1->tableData()); + QCOMPARE_EQ(sm->objectName(), sm1ObjectName); + + // object name already set, so do not update + sm->setTableData(stateMachine2->tableData()); + QCOMPARE_EQ(sm->objectName(), sm1ObjectName); // did not change +} + QTEST_MAIN(tst_StateMachine) #include "tst_statemachine.moc" |