| 1 |
/*! |
| 2 |
\page scxml.html |
| 3 |
\title Using SCXML files in Qt |
| 4 |
\ingroup sctools |
| 5 |
\brief An overview of the sctools module, which allows loading scripted state charts with SCXML |
| 6 |
|
| 7 |
\tableofcontents |
| 8 |
|
| 9 |
The sctools module allows loading SCXML files into a QtScriptedStateMachine object. |
| 10 |
|
| 11 |
The files that the tool can load conform to the \l{State Chart XML: State Machine Notation for Control Abstraction}{State Chart XML (SCXML)} standard. |
| 12 |
|
| 13 |
\section1 Getting Started with Qt & SCXML |
| 14 |
\list |
| 15 |
\i First of all, make yourself familiar with the \l{State Chart XML: State Machine Notation for Control Abstraction}{SCXML specification}. |
| 16 |
\i Read this document to understand how to enable SCXML files in your project, and how to load SCXML files in runtime/build-time. |
| 17 |
\i Go over the blackjack, calc and mediaplayer examples for usage demonstration. |
| 18 |
\endlist |
| 19 |
|
| 20 |
\section1 Enabling the QtScriptedStateMachine class |
| 21 |
|
| 22 |
The \l QtScriptedStateMachine class is enabled automatically when the script module is enabled. |
| 23 |
|
| 24 |
\section1 Using the QtScriptedStateMachine class |
| 25 |
|
| 26 |
QtScriptedStateMachine is a subclass of QtStateMachine. QtStateMachine actually includes most of the |
| 27 |
"interesting" API, while QtScriptedStateMachine adds the missing parts to support SCXML. |
| 28 |
|
| 29 |
Most of the interaction with QtScriptedStateMachine occurs after the state-machine is loaded, |
| 30 |
and before it's started. |
| 31 |
The interesting functionalities of QtScriptedStateMachine are: |
| 32 |
\section2 Working with the script engine |
| 33 |
|
| 34 |
The main feature of \l QtScriptedStateMachine is that it includes a single \a QScriptEngine object that's |
| 35 |
shared between all state actions and transitions. That's what allows the states to rely on a single |
| 36 |
data context for evaluating conditions and executing the entry/exit/transition actions. |
| 37 |
|
| 38 |
A very useful function is \l QtScriptedStateMachine::registerObject(), which allows you to add an object |
| 39 |
(and optionally all its descendants) to the scripting context. |
| 40 |
\l QtScriptedStateMachine::scriptEngine() allows you to manipulate the scripting context directly. |
| 41 |
Use the mediaplayer example as a reference for using the registerObject function. |
| 42 |
|
| 43 |
|
| 44 |
\section2 Connecting the state-machine to signals/slots |
| 45 |
|
| 46 |
A simpler way to interact with the state machine is through signals and slots. |
| 47 |
The slot \l QtScriptedStateMachine::postNamedEvent() and the signal \l QtScriptedStateMachine::eventTriggered() |
| 48 |
allow for a simple interaction with the state machine, as you can connect signals to postNamedEvent |
| 49 |
and eventTriggered to and signal/slot. |
| 50 |
|
| 51 |
There are no entered/exited signals from states, as that would make the state-machines less deterministic |
| 52 |
and would create results that are difficult to manage and predict (does the signal get emitted before, |
| 53 |
after or during the normal execution list?) |
| 54 |
|
| 55 |
The calc example shows the usage of \l QtScriptedStateMachine::postNamedEvent(). |
| 56 |
|
| 57 |
\section2 Extending the state-machine with custom invokers |
| 58 |
|
| 59 |
A custom invoker allows you to write your own \l{http://www.w3.org/TR/scxml/#Invoke}{invoke} tags, and implement specific invoke types, |
| 60 |
as described in the SCXML standard. |
| 61 |
|
| 62 |
To create a custom invoker, you must subclass from \l QtSsmInvoker, and implement at least: |
| 63 |
\list |
| 64 |
\i A constructor with \l QtScriptedEvent and \l QtStateMachine arguments |
| 65 |
\i The \l QtSsmInvoker::activate() function |
| 66 |
\i A static bool isTypeSupportedString(QString) function, conforms to the \l {http://www.w3.org/TR/scxml/#Invoke}{invoke} element's type attribute |
| 67 |
\i A static void initInvokerFactory(QtScriptedStateMachine*) function, allows some initialization (like adding properties to the script engine) |
| 68 |
\endlist |
| 69 |
|
| 70 |
|
| 71 |
When these terms are met, you can create an invoke-factory, and register it to the state machine. |
| 72 |
Example: |
| 73 |
\code |
| 74 |
#include <QtScriptedStateMachine> |
| 75 |
|
| 76 |
class MyInvoker : public QtSsmInvoker |
| 77 |
{ |
| 78 |
Q_OBJECT |
| 79 |
public: |
| 80 |
MyInvoker(QtScriptedEvent* ievent, QtScriptedStateMachine* p) : QtSsmInvoker(ievent,p),menu(0) |
| 81 |
{ |
| 82 |
} |
| 83 |
static void initInvokerFactory(QtScriptedStateMachine* machine) |
| 84 |
{ |
| 85 |
machine->scriptEngine()->globalObject().setProperty("some-name",someValue); |
| 86 |
} |
| 87 |
static bool isTypeSupported (const QString & s) { return s== "my-type"; } |
| 88 |
public Q_SLOTS: |
| 89 |
void activate () |
| 90 |
{ |
| 91 |
doSomeStuff (); |
| 92 |
} |
| 93 |
}; |
| 94 |
... |
| 95 |
static QSsmAutoInvokerFactory<MyInvoker> _s_factory; |
| 96 |
myScriptedStateMachine->registerInvoker(&_s_factory); |
| 97 |
|
| 98 |
\endcode |
| 99 |
|
| 100 |
The initEvent protected member can be used to access the parameters |
| 101 |
given to the invoker by the calling state machine. \l QtSsmInvoker::postParentEvent() |
| 102 |
allows sending events back to the calling state machine. |
| 103 |
|
| 104 |
|
| 105 |
|
| 106 |
|
| 107 |
|
| 108 |
\section1 Loading SCXML files at runtime |
| 109 |
|
| 110 |
To load SCXML files in runtime, the static function \l QtScriptedStateMachine::load() must be used. |
| 111 |
Note that this function requires the xmlpatterns and xml modules to be enabled. |
| 112 |
\l QtScriptedStateMachine::load() it creates a new \l QtScriptedStateMachine object. |
| 113 |
An example code would be: |
| 114 |
|
| 115 |
\code |
| 116 |
#include "qscriptedstatemachine.h" |
| 117 |
|
| 118 |
// some code |
| 119 |
QtScriptedStateMachine* stateMachine = QtScriptedStateMachine::load ("path-to-some-file.scxml"); |
| 120 |
// ... register some objects, handle some stuff in the script engine... |
| 121 |
stateMachine->start (); |
| 122 |
\endcode |
| 123 |
|
| 124 |
|
| 125 |
\section1 Supported SCXML tags and features |
| 126 |
|
| 127 |
Though most of the SCXML features are supported in this implementation, the support is incomplete, |
| 128 |
partially because the spec itself is still evolving. This documentation tries to capture most of the |
| 129 |
gaps and differences. |
| 130 |
|
| 131 |
\section2 Fully supported elements |
| 132 |
The tags \l {http://www.w3.org/TR/scxml/#state}{state}, \l {http://www.w3.org/TR/scxml/#parallel}{parallel}, \l {http://www.w3.org/TR/scxml/#final}{final}, \l {http://www.w3.org/TR/scxml/#onentry}{onentry}, \l {http://www.w3.org/TR/scxml/#onexit}{onexit}, \l {http://www.w3.org/TR/scxml/#raise}{raise}, \l {http://www.w3.org/TR/scxml/#if}{if}, \l {http://www.w3.org/TR/scxml/#elseif}{elseif}, \l {http://www.w3.org/TR/scxml/#else}{else}, \l {http://www.w3.org/TR/scxml/#log}{log}, \l {http://www.w3.org/TR/scxml/#cancel}{cancel}, \l {http://www.w3.org/TR/scxml/#datamodel}{datamodel},\l {http://www.w3.org/TR/scxml/#data}{data}, \l {http://www.w3.org/TR/scxml/#assign}{assign}, \l {http://www.w3.org/TR/scxml/#param}{param}, ands \l {http://www.w3.org/TR/scxml/#anchor}{anchor} are fully supported according to the scxml spec. |
| 133 |
|
| 134 |
\section2 Partially supported elements |
| 135 |
\list |
| 136 |
\i \l {http://www.w3.org/TR/scxml/#scxml}{scxml}: The attributes version, profile and exmode are ignored. |
| 137 |
\i \l {http://www.w3.org/TR/scxml/#initial}{initial}: Treated as a regular state that's marked as initial for the parent state. |
| 138 |
\i \l {http://www.w3.org/TR/scxml/#history}{history}: Actions in the history's default transition are ignored. |
| 139 |
\i \l {http://www.w3.org/TR/scxml/#content}{content}: Supports only JSON data, not XML. |
| 140 |
\i \l {http://www.w3.org/TR/scxml/#send}{send}: only the scxml target type is supported. The id attribute is ignored. |
| 141 |
\i \l {http://www.w3.org/TR/scxml/#invoke}{invoke}: the autoforward and id tags are ignored. |
| 142 |
\endlist |
| 143 |
|
| 144 |
\section2 Unsupported elements |
| 145 |
The elements \l {http://www.w3.org/TR/scxml/#Donedata}{donedata}, \l {http://www.w3.org/TR/scxml/#Finalize}{finalize} and \l {http://www.w3.org/TR/scxml/#Validate}{validate} are not supported. |
| 146 |
Also, the local/global script scoping functionality is not implemented. |
| 147 |
|
| 148 |
\section2 Extras |
| 149 |
\section3 Signal transitions |
| 150 |
To declare a signal transition, use a transition tag with a q-signal uri scheme. |
| 151 |
Example: |
| 152 |
\code |
| 153 |
<transition target="someState" event="q-signal:someObject.someSignal()" /> |
| 154 |
\endcode |
| 155 |
|
| 156 |
\section3 Property binding |
| 157 |
The q-binding invoker can be used to setup properties on entry, that are restored on exit. |
| 158 |
Note that if the properties are changed externally while the state is active, the properties |
| 159 |
would still be restored. |
| 160 |
|
| 161 |
The binding invoke element accepts a content tag with a JSON array, of which each element is a 3-item |
| 162 |
array: [object, property-name, property-value]. |
| 163 |
|
| 164 |
Example: |
| 165 |
|
| 166 |
\code |
| 167 |
<invoke type="q-bindings"><content> |
| 168 |
[[myObject,"someProperty",someValue1 + someValue2], |
| 169 |
[myObject,"text","hello"]] |
| 170 |
</content></invoke> |
| 171 |
\endcode |
| 172 |
|
| 173 |
\section3 Menus |
| 174 |
A custom invoker added to the solution is the "q-menu" invoker. This invoker allows you to display a |
| 175 |
QMenu and listen to its events. |
| 176 |
The q-menu invoker should a content tag, which includes an expression evaluating to an ecmascript |
| 177 |
object defining the menu. |
| 178 |
Note that support for menus is currently experimental, and the mediaplayer example demonstrates its use. |
| 179 |
|
| 180 |
\section3 Message Boxes |
| 181 |
Similar to q-menus, the "q-messagebox" invoker lets you show a QMessageBox and react to |
| 182 |
the user interactions with it. |
| 183 |
|
| 184 |
The q-messagebox invoker accepts an ecmascript object that contains name/value pairs for the QMessageBox |
| 185 |
properties. |
| 186 |
|
| 187 |
Example: |
| 188 |
\code |
| 189 |
<invoke type="q-messagebox"> |
| 190 |
<content> |
| 191 |
{ |
| 192 |
"parent" : myParentWidget, |
| 193 |
"icon" : QMessageBox.Question, |
| 194 |
"windowTitle" : "Would you like to exit?", |
| 195 |
"text" : "Are you sure?", |
| 196 |
"standardButtons" : QMessageBox.Yes|QMessageBox.No |
| 197 |
} |
| 198 |
</content> |
| 199 |
</invoke> |
| 200 |
\endcode |
| 201 |
|
| 202 |
See the blackjack example for reference. |
| 203 |
|
| 204 |
|
| 205 |
|
| 206 |
|
| 207 |
|
| 208 |
*/ |