summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/blackjack/blackjack.scxml19
-rw-r--r--examples/calc/calc.scxml226
-rw-r--r--scc/scc.xslt2
-rw-r--r--src/qscxml.cpp183
-rw-r--r--src/qscxml.h21
-rw-r--r--src/qscxml.pri8
6 files changed, 259 insertions, 200 deletions
diff --git a/examples/blackjack/blackjack.scxml b/examples/blackjack/blackjack.scxml
index 4c73cd4..5362546 100644
--- a/examples/blackjack/blackjack.scxml
+++ b/examples/blackjack/blackjack.scxml
@@ -197,7 +197,7 @@
<transition event="q-messagebox.finished" target="waitForBet" />
<transition event="bth-mb-timeout" target="waitForBet" />
<onentry>
- <send event="'bth-mb-timeout'" delay="'1500ms'" />
+ <send event="bth-mb-timeout" delay="1500ms" />
</onentry>
</state>
<state id="testCards">
@@ -235,20 +235,18 @@
<state id="checkWinner">
<onentry>
- <script>
- _global.diff = myDeck.evalBest() - dealerCards.evalBest();
- </script>
+ <assign dataid="diff" expr="myDeck.evalBest() - dealerCards.evalBest()" />
</onentry>
- <transition cond="diff&gt;0" target="win" />
- <transition cond="diff&lt;0" target="loss" />
- <transition cond="diff==0" target="draw" />
+ <transition cond="_data.diff&gt;0" target="win" />
+ <transition cond="_data.diff&lt;0" target="loss" />
+ <transition cond="_data.diff==0" target="draw" />
</state>
<state id="endGame">
<invoke type="q-bindings"><content>[[welcomeLabel,"text","Game Over"]]</content></invoke>
<transition event="timeout" target="newgame" />
<onentry>
- <send event="'timeout'" delay="'3s'" />
+ <send event="timeout" delay="3s" />
</onentry>
</state>
<state id="endRound">
@@ -256,9 +254,8 @@
<transition event="q-signal:newRoundButton.clicked()" target="newround" />
<transition event="timeout" target="newround" />
<onentry>
- <send event="'timeout'" delay="'3s'" />
+ <send event="timeout" delay="3s" />
</onentry>
-
<state id="win">
<onentry>
<script>
@@ -271,7 +268,7 @@
<state id="loss">
<invoke type="q-bindings"><content>[[welcomeLabel,"text","You Lost..."]]</content></invoke>
<transition cond="points == 0" target="endGame" />
- </state>
+ </state>
<state id="draw">
<invoke type="q-bindings"><content>[[welcomeLabel,"text","You It's a draw."]]</content></invoke>
<onentry>
diff --git a/examples/calc/calc.scxml b/examples/calc/calc.scxml
index ec732c7..516c20e 100644
--- a/examples/calc/calc.scxml
+++ b/examples/calc/calc.scxml
@@ -1,203 +1,173 @@
<scxml
initial="on" profile="ecma" name="calc">
<script>
- function insertDigit ()
- {
- insert (_event.name.charAt(_event.name.lastIndexOf('.')+1));
- }
- function insert(c)
- {
- short_expr += c;
- updateDisplay();
- }
- function negate ()
- {
- short_expr = "-";
- updateDisplay ();
- }
+ function insertDigit ()
+ {
+ insert (_event.name.charAt(_event.name.lastIndexOf('.')+1));
+ }
+ function insert(c)
+ {
+ short_expr += c;
+ updateDisplay();
+ }
+ function negate ()
+ {
+ short_expr = "-";
+ updateDisplay ();
+ }
- function updateDisplay ()
- {
- if (short_expr == "")
- dispLbl.text = _data.res;
- else
- dispLbl.text = short_expr;
- }
- function subcalc ()
- {
- if (short_expr != "")
- _data.long_expr += "(" + short_expr + ")";
- _data.res = eval(_data.long_expr);
- short_expr = "";
- updateDisplay ();
- return true;
- }
+ function updateDisplay ()
+ {
+ if (short_expr == "")
+ dispLbl.text = _data.res;
+ else
+ dispLbl.text = short_expr;
+ }
+ function subcalc ()
+ {
+ if (short_expr != "")
+ _data.long_expr += "(" + short_expr + ")";
+ _data.res = eval(_data.long_expr);
+ short_expr = "";
+ updateDisplay ();
+ return true;
+ }
- function insertOp ()
- {
- var sc = subcalc ();
- var op = '';
- if (_event.name == "OPER.PLUS")
- op = '+';
- else if (_event.name == "OPER.MINUS")
- op = '-';
- else if (_event.name == "OPER.STAR")
- op = '*';
- else if (_event.name == "OPER.DIV")
- op = '/';
- _data.long_expr += op;
- return sc;
- }
- function reset ()
- {
- short_expr = "";
- }
- function calc ()
- {
- if (subcalc ()) {
- short_expr = "" + _data.res;
- _data.long_expr = "";
- _data.res = 0;
- return true;
- } else
- return false;
- }
+ function insertOp ()
+ {
+ var sc = subcalc ();
+ var op = '';
+ if (_event.name == "OPER.PLUS")
+ op = '+';
+ else if (_event.name == "OPER.MINUS")
+ op = '-';
+ else if (_event.name == "OPER.STAR")
+ op = '*';
+ else if (_event.name == "OPER.DIV")
+ op = '/';
+ _data.long_expr += op;
+ return sc;
+ }
+ function reset ()
+ {
+ short_expr = "";
+ }
+ function calc ()
+ {
+ if (subcalc ()) {
+ short_expr = "" + _data.res;
+ _data.long_expr = "";
+ _data.res = 0;
+ return true;
+ } else
+ return false;
+ }
</script>
<state id="on" initial="ready">
<datamodel>
- <data id="long_expr" />
- <data id="res" >0</data>
- </datamodel>
+ <data id="long_expr" />
+ <data id="res" >0</data>
+ </datamodel>
<onentry>
<script>
- var short_expr = 0;
- _data.res = 0;
- _data.long_expr = "";
- updateDisplay();
+ var short_expr = 0;
+ _data.res = 0;
+ _data.long_expr = "";
+ updateDisplay();
</script>
</onentry>
<state id="ready" initial="begin">
<state id="begin">
<transition event="OPER.MINUS" target="negated1" />
<onentry>
- <script>
- updateDisplay ();
- </script>
+ <script>updateDisplay ();</script>
</onentry>
</state>
<state id="result">
</state>
- <transition event="OPER" target="opEntered" />
- <transition event="DIGIT.0" target="zero1">
- <script>
- reset ();
- </script>
- </transition>
- <transition event="DIGIT" target="int1">
- <script>
- reset ();
- </script>
- </transition>
- <transition event="POINT" target="frac1">
- <script>
- reset ();
- </script>
- </transition>
- </state>
+ <transition event="OPER" target="opEntered" />
+ <transition event="DIGIT.0" target="zero1">
+ <script>reset ();</script>
+ </transition>
+ <transition event="DIGIT" target="int1">
+ <script>reset ();</script>
+ </transition>
+ <transition event="POINT" target="frac1">
+ <script>reset ();</script>
+ </transition>
+ </state>
<state id="negated1">
<onentry>
- <script>
- negate ();
- </script>
+ <script>negate ();</script>
</onentry>
<transition event="DIGIT.0" target="zero1" />
- <transition event="DIGIT" target="int1" />
+ <transition event="DIGIT" target="int1" />
<transition event="POINT" target="frac1" />
</state>
<state id="operand1">
<state id="zero1">
- <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int1" />
+ <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int1" />
<transition event="POINT" target="frac1" />
</state>
<state id="int1">
<transition event="POINT" target="frac1" />
- <transition event="DIGIT">
- <script>
- insertDigit ();
- </script>
+ <transition event="DIGIT">
+ <script>insertDigit ();</script>
</transition>
<onentry>
- <script>
- insertDigit ();
- </script>
+ <script>insertDigit ();</script>
</onentry>
</state>
<state id="frac1">
<onentry>
- <script>
- insert ('.');
- </script>
+ <script>insert ('.');</script>
</onentry>
- <transition event="DIGIT">
- <script>
- insertDigit ();
- </script>
+ <transition event="DIGIT">
+ <script>insertDigit ();</script>
</transition>
</state>
<transition event="CE" target="ready" />
- <transition event="OPER" target="opEntered" />
+ <transition event="OPER" target="opEntered" />
</state>
<state id="error" />
<state id="opEntered">
<transition event="OPER.MINUS" target="negated2" />
<transition event="POINT" target="frac2" />
<transition event="DIGIT.0" target="zero2" />
- <transition event="DIGIT" target="int2" />
+ <transition event="DIGIT" target="int2" />
<onentry>
- <script>
- insertOp ();
- </script>
+ <script>insertOp ();</script>
</onentry>
</state>
<state id="negated2">
<onentry>
- <script>
- negate ();
- </script>
+ <script>negate ();</script>
</onentry>
<transition event="CE" target="opEntered" />
<transition event="DIGIT.0" target="zero2" />
- <transition event="DIGIT" target="int2" />
+ <transition event="DIGIT" target="int2" />
<transition event="POINT" target="frac2" />
</state>
<state id="operand2">
<state id="zero2">
- <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int2" />
+ <transition event="DIGIT" cond="_event.name != 'DIGIT.0'" target="int2" />
<transition event="POINT" target="frac2" />
</state>
<state id="int2">
- <transition event="DIGIT">
- <script>
- insertDigit ();
- </script>
+ <transition event="DIGIT">
+ <script>insertDigit ();</script>
</transition>
<onentry>
- <script>
- insertDigit ();
- </script>
+ <script>insertDigit ();</script>
</onentry>
<transition event="POINT" target="frac2" />
</state>
<state id="frac2">
<onentry>
- <script>
- insert ('.');
- </script>
+ <script>insert ('.');</script>
</onentry>
<transition event="DIGIT">
- <script>
- insertDigit ();
- </script>
+ <script>insertDigit ();</script>
</transition>
</state>
<transition event="OPER" cond="!insertOp()" target="error" />
diff --git a/scc/scc.xslt b/scc/scc.xslt
index 1f5fc20..1c35319 100644
--- a/scc/scc.xslt
+++ b/scc/scc.xslt
@@ -274,7 +274,7 @@ class SMClass_<xsl:call-template name="smname" /> : public QStateMachine
{
if (event && !event->type() == QEvent::None) {
switch (event->type()) {
- case QEvent::Signal: {
+ case QEvent::StateMachineSignal: {
QStateMachine::SignalEvent* e = (QStateMachine::SignalEvent*)event;
_event.data = e->arguments();
_event.name = e->sender()->metaObject()->method(e->signalIndex()).signature();
diff --git a/src/qscxml.cpp b/src/qscxml.cpp
index fd524ee..ec7eb5c 100644
--- a/src/qscxml.cpp
+++ b/src/qscxml.cpp
@@ -37,9 +37,7 @@
#include <QFinalState>
#include <QState>
#include <QMetaMethod>
-#ifdef QT_GUI_LIB
-#include "qscxmlgui.h"
-#endif
+#include <QScriptProgram>
@@ -168,6 +166,8 @@ class QScxmlPrivate
void initScriptEngine(QScxml* thiz);
+ QScriptValue dataObj;
+
QScriptEngine* scriptEng;
QList<QScxmlInvokerFactory*> invokerFactories;
@@ -175,6 +175,8 @@ class QScxmlPrivate
QString sessionID;
QString startScript;
+ QSet<QString> knownEvents;
+
QStack<AnchorSnapshot> snapshotStack;
QMultiHash<QString,QAbstractTransition*> anchorTransitions;
@@ -189,22 +191,25 @@ class QScxmlTimer : public QObject
{
Q_OBJECT
public:
- QScxmlTimer(QScriptEngine* engine, const QScriptValue & scr, int delay) : QObject(engine),script(scr)
+ QScxmlTimer(QScriptEngine* engine, const QScriptValue & scr, int delay) : QObject(engine)
{
QTimer::singleShot(delay,this,SLOT(exec()));
+ if (scr.isString()) {
+ script = engine->evaluate(QString("function(){%1}").arg(scr.toString()));
+ } else
+ script = scr;
}
protected Q_SLOTS:
void exec()
{
+
if (script.isFunction())
script.call();
- else if (script.isString())
- script.engine()->evaluate(script.toString());
deleteLater();
}
private:
- QScriptValue script;
+ QScriptValue script;
};
@@ -418,6 +423,23 @@ static QScriptValue invoke(QScriptContext *context, QScriptEngine *engine)
return QScriptValue();
}
+static QScriptValue dataAccess(QScriptContext *context, QScriptEngine *)
+{
+ if (context->argumentCount() == 0) {
+ // getter
+ return context->callee().property("value");
+ } else if (context->argumentCount() == 1) {
+ // setter
+ QScriptValue val = context->argument(0);
+ context->callee().setProperty("value",val);
+ QScxml* scxml = qobject_cast<QScxml*>(context->callee().property("scxml").toQObject());
+ if (scxml) {
+ scxml->dataChanged(context->callee().property("key").toString(),val.toVariant());
+ }
+ return val;
+ } else
+ return QScriptValue();
+}
static QScriptValue isInState(QScriptContext *context, QScriptEngine *engine)
{
@@ -438,6 +460,8 @@ static QScriptValue isInState(QScriptContext *context, QScriptEngine *engine)
}
+
+
};
void QScxmlPrivate::initScriptEngine(QScxml* thiz)
@@ -445,7 +469,6 @@ void QScxmlPrivate::initScriptEngine(QScxml* thiz)
QScriptValue glob = scriptEng->globalObject();
QScriptValue scxmlObj = scriptEng->newQObject(thiz);
glob.setProperty("In",scriptEng->newFunction(QScxmlFunctions::isInState));
-// glob.setProperty("_rcvSig",scriptEng->newFunction(QScxmlFunctions::receiveSignal));
scxmlObj.setProperty("print",scriptEng->newFunction(QScxmlFunctions::script_print));
scxmlObj.setProperty("postEvent",scriptEng->newFunction(QScxmlFunctions::postEvent));
scxmlObj.setProperty("invoke",scriptEng->newFunction(QScxmlFunctions::invoke));
@@ -455,7 +478,9 @@ void QScxmlPrivate::initScriptEngine(QScxml* thiz)
scxmlObj.setProperty("clearTimeout",scriptEng->newFunction(QScxmlFunctions::clearTimeout));
scxmlObj.setProperty("connectSignalToEvent",scriptEng->newFunction(QScxmlFunctions::connectSignalToEvent));
QScriptValue dmObj = scriptEng->newObject();
- glob.setProperty("_data",scriptEng->newObject());
+ dataObj = scriptEng->newObject();
+ dataObj.setProperty("_values",scriptEng->newObject());
+ glob.setProperty("_data",dataObj);
glob.setProperty("_global",scriptEng->globalObject());
glob.setProperty("scxml",scxmlObj);
}
@@ -552,6 +577,16 @@ QScxmlTransition::QScxmlTransition (QState* state,QScxml* machine)
: QAbstractTransition(state),scxml(machine)
{
}
+
+void QScxmlTransition::setConditionExpression(const QString & c)
+{
+ prog = QScriptProgram(c,scxml->baseUrl().toLocalFile());
+}
+
+QString QScxmlTransition::conditionExpression() const
+{
+ return prog.sourceCode();
+}
/*!
\reimp
*/
@@ -564,21 +599,26 @@ void QScxmlTransition::onTransition(QEvent*)
bool QScxmlTransition::eventTest(QEvent *e)
{
QScriptEngine* engine = scxml->scriptEngine();
- QString ev;
+ QString event;
if (e) {
if (e->type() == QScxmlEvent::eventType()) {
- ev = ((QScxmlEvent*)e)->eventName();
+ event = ((QScxmlEvent*)e)->eventName();
+ }
+ bool found = false;
+ for (int i=0; i < ev.size() && !found; ++i) {
+ QString prefix = ev[i];
+ found = prefix=="*" || prefix==event || event.startsWith(prefix)
+ || (prefix.endsWith(".*") && event.startsWith(prefix.left(prefix.indexOf(".*"))))
+ ;
}
- if (!(eventPrefix() == "*" || eventPrefix() == ev || ev.startsWith(eventPrefix()+".")))
+ if (!found )
return false;
}
if (!conditionExpression().isEmpty()) {
-
-
- QScriptValue v = engine->evaluate(conditionExpression(),scxml->baseUrl().toLocalFile());
+ QScriptValue v = engine->evaluate(prog);
if (engine->hasUncaughtException()) {
QScxmlEvent* e = new QScxmlEvent("error.illegalcond",
@@ -588,7 +628,7 @@ bool QScxmlTransition::eventTest(QEvent *e)
<< QVariant(conditionExpression())
<< QVariant(engine->uncaughtExceptionLineNumber())
<< QVariant(engine->uncaughtExceptionBacktrace()));
- qDebug() << engine->uncaughtException().toString();
+ qDebug() << engine->uncaughtException().toString() << prog.sourceCode();
e->metaData.kind = QScxmlEvent::MetaData::Platform;
scxml->postEvent(e);
engine->clearExceptions();
@@ -732,12 +772,6 @@ void QScxml::init()
connect(this,SIGNAL(started()),this,SLOT(registerSession()));
connect(this,SIGNAL(stopped()),this,SLOT(unregisterSession()));
pvt->initScriptEngine(this);
-#ifdef QT_GUI_LIB
- static QScxmlAutoInvokerFactory<QScxmlMenuInvoker> _s_menuInvokerFactory;
- static QScxmlAutoInvokerFactory<QScxmlMessageBoxInvoker> _s_msgboxInvokerFactory;
- registerInvokerFactory(&_s_msgboxInvokerFactory);
- registerInvokerFactory(&_s_menuInvokerFactory);
-#endif
}
/*!
Creates a new QScxml object, with parent \a parent.
@@ -862,6 +896,8 @@ void QScxml::endMicrostep(QEvent*)
pvt->snapshotStack.remove(0,pvt->snapshotStack.size()-100);
}
pvt->curSnapshot.clear();
+ qDebug() << configuration();
+ emit configurationChanged();
/*
if (e->type() == QScxmlEvent::eventType()) {
qDebug() << "\n" + _q_configToString(rootState(),-1,configuration());
@@ -907,30 +943,43 @@ void QScxml::postNamedEvent(const QString & event)
e->metaData.kind = QScxmlEvent::MetaData::External;
postEvent(e);
}
+
+void QScxml::setData(const QString & id, const QVariant & val)
+{
+ QScriptValue accessor = pvt->dataObj.property(id);
+ if (accessor.isFunction()) {
+ accessor.setProperty("value",scriptEngine()->newVariant(val));
+ }
+}
+
/*!
Executes script \a s in the attached script engine.
If the script fails, a "error.illegalvalue" event is posted to the state machine.
*/
-void QScxml::executeScript (const QString & s)
+void QScxml::executeScript (const QScriptProgram & s)
{
-// qDebug() << "Executing\n--------------------------\n"<<s;
- pvt->scriptEng->evaluate (s,baseUrl().toLocalFile());
+ qDebug() << "Executing\n--------------------------\n"<<s.sourceCode();
+ pvt->scriptEng->evaluate (s);
if (pvt->scriptEng->hasUncaughtException()) {
QScxmlEvent* e = new QScxmlEvent("error.illegalvalue",
QStringList()<< "error" << "expr" << "line" << "backtrace",
QVariantList()
<< QVariant(pvt->scriptEng->uncaughtException().toString())
- << QVariant(s)
+ << QVariant(s.sourceCode())
<< QVariant(pvt->scriptEng->uncaughtExceptionLineNumber())
<< QVariant(pvt->scriptEng->uncaughtExceptionBacktrace()));
e->metaData.kind = QScxmlEvent::MetaData::Platform;
- qDebug() << pvt->scriptEng->uncaughtException().toString();
+ qDebug() << pvt->scriptEng->uncaughtException().toString() << s.sourceCode();
postEvent(e);
pvt->scriptEng->clearExceptions();
}
// qDebug() <<"\n--------------------\n";
}
+void QScxml::executeScript (const QString & s)
+{
+ executeScript(QScriptProgram(s,baseUrl().toLocalFile()));
+}
/*!
Enabled invoker factory \a f to be called from <invoke /> tags.
@@ -1034,6 +1083,11 @@ void QScxml::setBaseUrl(const QUrl & u)
pvt->burl = u;
}
+QStringList QScxml::knownEventNames() const
+{
+ return pvt->knownEvents.toList();
+}
+
void QScxml::registerSession()
{
pvt->sessionID = QUuid::createUuid().toString();
@@ -1073,16 +1127,17 @@ struct ScTransitionInfo
class QScxmlScriptExec : public QObject
{
Q_OBJECT
- QString script;
+ QScriptProgram prog;
QScxml* scxml;
public:
- QScxmlScriptExec(const QString & scr, QScxml* scx) : script(scr),scxml(scx)
+ QScxmlScriptExec(const QString & scr, QScxml* scx) :
+ prog(QScriptProgram(scr,scx->baseUrl().toLocalFile())),scxml(scx)
{
}
public Q_SLOTS:
void exec()
{
- scxml->executeScript(script);
+ scxml->executeScript(prog);
}
};
@@ -1330,7 +1385,7 @@ void QScxmlLoader::loadState (
} else if (r.name().toString().compare("script",Qt::CaseInsensitive) == 0) {
QString txt = r.readElementText().trimmed();
if (curExecContext.type == ScExecContext::None && curState == topLevelState) {
- stateMachine->executeScript(txt);
+ stateMachine->executeScript(QScriptProgram(txt,stateMachine->baseUrl().toLocalFile()));
} else
curExecContext.script += txt;
} else if (r.name().toString().compare("log",Qt::CaseInsensitive) == 0) {
@@ -1365,7 +1420,9 @@ void QScxmlLoader::loadState (
curExecContext.type = ScExecContext::StateExit;
curExecContext.script = "";
} else if (r.name().toString().compare("raise",Qt::CaseInsensitive) == 0 || r.name().toString().compare("event",Qt::CaseInsensitive) == 0 ) {
- eventName = QString("\"%1\"").arg(r.attributes().value("event").toString());
+ eventName = r.attributes().value("event").toString();
+ stateMachine->pvt->knownEvents.insert(eventName);
+ eventName = QString("\"%1\"").arg(eventName);
target = "'_internal'";
targetType = "scxml";
content = "{}";
@@ -1377,10 +1434,20 @@ void QScxmlLoader::loadState (
content = "{}";
target = r.attributes().value("target").toString();
- if (target == "")
- target = "\"\"";
+ if (target == "") {
+ target = r.attributes().value("targetexpr").toString();
+ if (target == "")
+ target = "\"\"";
+ } else
+ target = "\""+target+"\"";
targetType = r.attributes().value("type").toString();
eventName = r.attributes().value("event").toString();
+ if (eventName == "") {
+ eventName = r.attributes().value("eventexpr").toString();
+ } else {
+ stateMachine->pvt->knownEvents.insert(eventName);
+ eventName = "'"+eventName+"'";
+ }
QStringList nameList = r.attributes().value("namelist").toString().split(" ");
foreach (QString name,nameList) {
if (name != "") {
@@ -1393,10 +1460,14 @@ void QScxmlLoader::loadState (
idLocation = r.attributes().value("sendid").toString();
delay = r.attributes().value("delay").toString();
- if (delay == "")
- delay = "0";
- else
- delay = QString("scxml.cssTime(%1)").arg(delay);
+ if (delay == "") {
+ delay = r.attributes().value("delayexpr").toString();
+ if (delay == "")
+ delay = "0";
+ } else
+ delay = "'"+delay+"'";
+
+ delay = QString("scxml.cssTime(%1)").arg(delay);
} else if (r.name().toString().compare("invoke",Qt::CaseInsensitive) == 0) {
idLocation = r.attributes().value("idlocation").toString();
@@ -1429,7 +1500,11 @@ void QScxmlLoader::loadState (
curExecContext.script = "";
curTransition = new QScxmlTransition(curState,stateMachine);
curTransition->setConditionExpression(r.attributes().value("cond").toString());
- curTransition->setEventPrefix(r.attributes().value("event").toString());
+ curTransition->setEventPrefixes(r.attributes().value("event").toString().split(' '));
+ foreach(QString pfx, curTransition->eventPrefixes()) {
+ if (pfx != "*")
+ stateMachine->pvt->knownEvents.insert(pfx);
+ }
curExecContext.trans = curTransition;
QString anc = r.attributes().value("anchor").toString();
if (!anc.isEmpty()) {
@@ -1438,10 +1513,12 @@ void QScxmlLoader::loadState (
}
inf.transition = curTransition;
transitions.append(inf);
- if (curTransition->eventPrefix().startsWith("q-signal:")) {
- signalEvents.insert(curTransition->eventPrefix());
+ foreach (QString prefix, curTransition->eventPrefixes()) {
+ if (prefix.startsWith("q-signal:")) {
+ signalEvents.insert(prefix);
+ }
}
- curTransition->setObjectName(QString ("%1 to %2 on %3 if %4 (anchor=%5)").arg(curState->objectName()).arg(inf.targets.join(" ")).arg(curTransition->eventPrefix()).arg(curTransition->conditionExpression()).arg(anc));
+ curTransition->setObjectName(QString ("%1 to %2 on %3 if %4 (anchor=%5)").arg(curState->objectName()).arg(inf.targets.join(" ")).arg(curTransition->eventPrefixes().join(" ")).arg(curTransition->conditionExpression()).arg(anc));
}
} else if (r.name().toString().compare("anchor",Qt::CaseInsensitive) == 0) {
QObject::connect(curState,SIGNAL(exited()),new QScxmlAnchorSave(stateMachine,stateMachine->pvt,r.attributes().value("type").toString(),r.attributes().value("snapshot").toString(),curState),SLOT(save()));
@@ -1459,8 +1536,11 @@ void QScxmlLoader::loadState (
val = stateMachine->scriptEngine()->evaluate(t);
}
}
- stateMachine->scriptEngine()->evaluate("_data")
- .setProperty(id,val);
+ QScriptValue func = stateMachine->scriptEngine()->newFunction(QScxmlFunctions::dataAccess);
+ func.setProperty("key",id);
+ qDebug() << id << val.toVariant();
+ stateMachine->pvt->dataObj.setProperty(id,func,QScriptValue::PropertyGetter|QScriptValue::PropertySetter);
+ stateMachine->pvt->dataObj.setProperty(id,val);
} else if (r.name().toString().compare("param",Qt::CaseInsensitive) == 0) {
paramNames << r.attributes().value("name").toString();
paramVals << r.attributes().value("expr").toString();
@@ -1509,6 +1589,7 @@ void QScxmlLoader::loadState (
curExecContext.type = r.name().toString().compare("onexit",Qt::CaseInsensitive)==0 ? ScExecContext::StateExit : ScExecContext::StateEntry;
curExecContext.applyScript();
curExecContext.type = ScExecContext::None;
+ curExecContext.script = "";
} else if (r.name().toString().compare("transition",Qt::CaseInsensitive) == 0) {
if (!curHistoryState) {
curExecContext.trans = curTransition;
@@ -1544,6 +1625,16 @@ void QScxmlLoader::loadState (
}
}
+QMap<QString,QVariant> QScxml::data() const
+{
+ QMap<QString,QVariant> d;
+ QScriptValueIterator it (scriptEngine()->evaluate("_data"));
+ while (it.hasNext()) {
+ it.next();
+ d[it.name()] = it.value().toVariant();
+ }
+ return d;
+}
QScxml* QScxmlLoader::load(QIODevice* device, QObject* obj, const QString & filename)
{
@@ -1562,14 +1653,10 @@ QScxml* QScxmlLoader::load(QIODevice* device, QObject* obj, const QString & file
foreach (QString s, signalEvents) {
QString sig = s;
sig = sig.mid(sig.indexOf(':')+1);
-// sig = sig.left(sig.indexOf('('));
int liop = sig.lastIndexOf('.');
QString obj = sig.left(liop);
sig = sig.mid(liop+1);
stateMachine->pvt->startScript += QString("scxml.connectSignalToEvent(%1,'%2',\"%3\");").arg(obj).arg(sig).arg(s);
-
-// QString scr = QString("%1.connect({e:\"%2\"},_rcvSig);\n").arg(sig).arg(s);
-/// stateMachine->pvt->startScript += scr;
}
foreach (QState* s, statesWithFinal) {
diff --git a/src/qscxml.h b/src/qscxml.h
index fc6b590..4cf4365 100644
--- a/src/qscxml.h
+++ b/src/qscxml.h
@@ -19,7 +19,7 @@
#include <QStringList>
#include <QScriptValue>
#include <QUrl>
-
+#include <QScriptProgram>
class QScriptEngine;
class QScxml;
@@ -60,22 +60,23 @@ class QScxmlTransition : public QAbstractTransition
{
Q_OBJECT
Q_PROPERTY(QString conditionExpression READ conditionExpression WRITE setConditionExpression)
- Q_PROPERTY(QString eventPrefix READ eventPrefix WRITE setEventPrefix)
+ Q_PROPERTY(QStringList eventPrefixes READ eventPrefixes WRITE setEventPrefixes)
public:
QScxmlTransition (QState* state, QScxml* machine);
- QString conditionExpression () const { return cond; }
- void setConditionExpression (const QString & c) { cond = c; }
- QString eventPrefix () const { return ev; }
- void setEventPrefix (const QString & e) { ev = e; }
+ QString conditionExpression () const;
+ void setConditionExpression (const QString & c);
+ QStringList eventPrefixes () const { return ev; }
+ void setEventPrefixes (const QStringList & e) { ev = e; }
protected:
bool eventTest(QEvent*);
void onTransition (QEvent*);
private:
QScxml* scxml;
- QString ev,cond;
+ QStringList ev;
+ QScriptProgram prog;
};
class QScxmlInvoker : public QObject
@@ -147,10 +148,14 @@ class QScxml : public QStateMachine
void setBaseUrl (const QUrl &);
QUrl baseUrl () const;
static QScxml* load (const QString & filename, QObject* o = NULL);
+ QMap<QString,QVariant> data() const;
+ QStringList knownEventNames() const;
public Q_SLOTS:
void postNamedEvent(const QString &);
void executeScript (const QString &);
+ void executeScript (const QScriptProgram &);
+ void setData(const QString & id, const QVariant & value);
private Q_SLOTS:
void registerSession();
@@ -159,6 +164,8 @@ class QScxml : public QStateMachine
Q_SIGNALS:
void eventTriggered(const QString &);
+ void dataChanged (const QString &, const QVariant &);
+ void configurationChanged();
private:
class QScxmlPrivate* pvt;
diff --git a/src/qscxml.pri b/src/qscxml.pri
index 873c038..97caa28 100644
--- a/src/qscxml.pri
+++ b/src/qscxml.pri
@@ -1,7 +1,5 @@
QT += script
-SOURCES += $$PWD/qscxml.cpp \
- $$PWD/qscxmlgui.cpp
+SOURCES += $$PWD/qscxml.cpp
-HEADERS += $$PWD/qscxml.h \
- $$PWD/qscxmlgui.h
-INCLUDEPATH += $$PWD \ No newline at end of file
+HEADERS += $$PWD/qscxml.h
+INCLUDEPATH += $$PWD