77#include < QUdpSocket>
88#include < QNetworkDatagram>
99
10+ #ifdef USE_SCXML_TRIGGERED_TRANSITIONS
11+ /* This is the only way to monitor triggered transitions */
12+ /* QT += scxml-private */
13+ #include < algorithm>
14+ #include < map>
15+ #include < set>
16+ #include < QtScxml/private/qscxmlstatemachineinfo_p.h>
17+ #include < QtScxml/private/qscxmlstatemachine_p.h>
18+ #endif
19+
1020namespace Scxmlmonitor {
1121
12- static const std::size_t SCXML_MONITOR_VERSION = 0x09 ;
22+ static const std::size_t SCXML_MONITOR_VERSION = 10 ;
1323
1424/* External SCXML monitor for ScxmlEditor */
1525/* See 'https://github.com/alexzhornyak/ScxmlEditor-Tutorial' */
@@ -171,7 +181,7 @@ class IScxmlExternMonitor: public QObject {
171181 }
172182
173183 inline virtual void processEventMessage (QScxmlStateMachine *machine, const QString &id, const QScxmlEvent &event) {
174- processMonitorMessage (machine->name (), id, event.name (), smttBeforeTakingTransition );
184+ processMonitorMessage (machine->name (), id, event.name (), smttBeforeProcessingEvent );
175185 }
176186
177187private slots:
@@ -238,6 +248,13 @@ private slots:
238248 }
239249 }
240250
251+ inline QString monitorID (QScxmlStateMachine *machine) const {
252+ auto itInvoked = _invokedMachines.constFind (machine);
253+ const QString id = itInvoked == _invokedMachines.cend () ?
254+ this ->_machineID : std::get<InvType::Id>(itInvoked.value ());
255+ return id;
256+ }
257+
241258 inline void connectMonitorToMachine (QScxmlStateMachine *machine) {
242259 if (!machine || _connectedMachines.contains (machine))
243260 return ;
@@ -248,27 +265,61 @@ private slots:
248265 const auto allStates = machine->stateNames (false );
249266 for (const auto &itState : allStates) {
250267 auto stateconnection = machine->connectToState (itState, [=](bool active) {
251- auto itInvoked = _invokedMachines.constFind (machine);
252- const QString id = itInvoked == _invokedMachines.cend () ?
253- this ->_machineID : std::get<InvType::Id>(itInvoked.value ());
254- processMonitorMessage (machine->name (), id, itState, active ? smttBeforeEnter : smttBeforeExit);
268+ processMonitorMessage (machine->name (), monitorID (machine), itState, active ? smttBeforeEnter : smttBeforeExit);
255269 });
256270 _scxmlConnections.append (stateconnection);
257271 }
258272
259273 /* all events + transitions */
260274 auto eventconnection = machine->connectToEvent (" *" , [=](const QScxmlEvent &event) {
261- auto itInvoked = _invokedMachines.constFind (machine);
262- const QString id = itInvoked == _invokedMachines.cend () ?
263- this ->_machineID : std::get<InvType::Id>(itInvoked.value ());
264- processEventMessage (machine, id, event);
275+ processEventMessage (machine, monitorID (machine), event);
265276 });
266277 _scxmlConnections.append (eventconnection);
267278
268279 const auto invokeconnection = connect (machine, &QScxmlStateMachine::invokedServicesChanged,
269280 this , &IScxmlExternMonitor::onInvokedServicesChanged);
270281 _scxmlConnections.append (invokeconnection);
271282
283+ #ifdef USE_SCXML_TRIGGERED_TRANSITIONS
284+ QScxmlStateMachineInfo *scxmlInfo = new QScxmlStateMachineInfo (machine);
285+
286+ std::map<QScxmlStateMachineInfo::StateId, std::set<QScxmlStateMachineInfo::TransitionId>> transitionsMap;
287+ const auto allTrans = scxmlInfo->allTransitions ();
288+ for (auto transitionId : allTrans) {
289+ const auto stateFromId = scxmlInfo->transitionSource (transitionId);
290+ auto itStateTransitions = transitionsMap.find (stateFromId);
291+ if (itStateTransitions == transitionsMap.cend ()) {
292+ transitionsMap.insert (std::make_pair (stateFromId, std::set<QScxmlStateMachineInfo::TransitionId>{ transitionId }));
293+ } else {
294+ itStateTransitions->second .insert (transitionId);
295+ }
296+ }
297+
298+ const auto connectionInfo = QObject::connect (scxmlInfo, &QScxmlStateMachineInfo::transitionsTriggered, scxmlInfo,
299+ [=](const QVector<QScxmlStateMachineInfo::TransitionId> &transitions) {
300+ if (scxmlInfo->stateMachine ()) {
301+ for (auto transitionId : transitions) {
302+ auto fromID = scxmlInfo->transitionSource (transitionId);
303+ const QString sFrom = scxmlInfo->stateName (fromID);
304+
305+ const auto itStateTransitions = transitionsMap.find (fromID);
306+ if (itStateTransitions != transitionsMap.cend ()) {
307+ const auto itTransition = itStateTransitions->second .find (transitionId);
308+ if (itTransition != itStateTransitions->second .end ()) {
309+ const auto pos = std::distance (itStateTransitions->second .begin (), itTransition);
310+ this ->processMonitorMessage (machine->name (), this ->monitorID (machine),
311+ QString (" %1|%2" ).arg (
312+ sFrom ).arg (pos),
313+ TScxmlMsgType::smttBeforeTakingTransition);
314+ }
315+ }
316+ }
317+ }
318+ });
319+ _scxmlInfoConnections.append (connectionInfo);
320+
321+ #endif
322+
272323 const auto allInvoked = machine->invokedServices ();
273324 for (const auto it: allInvoked) {
274325 QScxmlStateMachine *submachine = qvariant_cast<QScxmlStateMachine *>(it->property (" stateMachine" ));
@@ -280,10 +331,19 @@ private slots:
280331
281332 inline void cleanup (void ) {
282333 _invokedMachines.clear ();
334+
335+ #ifdef USE_SCXML_TRIGGERED_TRANSITIONS
336+ for (auto &it : _scxmlInfoConnections) {
337+ QObject::disconnect (it);
338+ }
339+ _scxmlInfoConnections.clear ();
340+ #endif
341+
283342 for (auto &it : _scxmlConnections) {
284343 QObject::disconnect (it);
285344 }
286- _scxmlConnections.clear ();
345+ _scxmlConnections.clear ();
346+
287347 _connectedMachines.clear ();
288348 _machine = nullptr ;
289349 }
@@ -301,6 +361,10 @@ private slots:
301361 QSet<QScxmlStateMachine*> _connectedMachines;
302362 QList<QMetaObject::Connection> _scxmlConnections;
303363 QString _machineID = " " ;
364+
365+ #ifdef USE_SCXML_TRIGGERED_TRANSITIONS
366+ QList<QMetaObject::Connection> _scxmlInfoConnections;
367+ #endif
304368};
305369
306370class UDPScxmlExternMonitor : public IScxmlExternMonitor {
@@ -352,6 +416,19 @@ class UDPScxmlExternMonitor: public IScxmlExternMonitor {
352416 processClearMonitor (" " , " " );
353417 }
354418
419+ inline virtual void processEventMessage (QScxmlStateMachine *machine, const QString &id, const QScxmlEvent &event) override {
420+ QString sEventData = event.data ().toString ();
421+ if (!sEventData .isEmpty ()) {
422+ if (sEventData .length () > 40 ) {
423+ sEventData = sEventData .left (40 ) + " ..." ;
424+ }
425+ }
426+ processMonitorMessage (machine->name (),
427+ id,
428+ sEventData .isEmpty () ? event.name () : (event.name () + " : [" + sEventData + " ]" ),
429+ Scxmlmonitor::smttBeforeProcessingEvent);
430+ }
431+
355432private:
356433
357434 // network
0 commit comments