diff options
-rw-r--r-- | examples/qml/blackjack/blackjack.qml | 213 | ||||
-rw-r--r-- | examples/qml/blackjack/blackjack.scxml | 372 | ||||
-rw-r--r-- | examples/qml/blackjack/main.cpp | 1 | ||||
-rw-r--r-- | qmlscxml/qmlscxml.cpp | 45 | ||||
-rw-r--r-- | src/qscxml.cpp | 180 |
5 files changed, 474 insertions, 337 deletions
diff --git a/examples/qml/blackjack/blackjack.qml b/examples/qml/blackjack/blackjack.qml index 976661a..6e68022 100644 --- a/examples/qml/blackjack/blackjack.qml +++ b/examples/qml/blackjack/blackjack.qml @@ -9,85 +9,196 @@ Rectangle { id: controller source: "blackjack.scxml" } + states: [ + State { + name: "placeBets" + when: controller.current.waitForBet + PropertyChanges { + target: betContainer + opacity: 1 + } + PropertyChanges { + target: welcomeText + text: "Please place your bet" + } + }, + State { + name: "waitForAction" + when: controller.current.waitForAction + PropertyChanges { + target: welcomeText + text: "Hit or stand?" + } + PropertyChanges { + target: actionContainer + opacity: 1 + } + }, + State { + name: "win" + when: controller.current.win + PropertyChanges { + target: welcomeText + text: "You win!" + } + }, + State { + name: "lose" + when: controller.current.loss + PropertyChanges { + target: welcomeText + text: "You lose..." + } + }, + State { + name: "draw" + when: controller.current.draw + PropertyChanges { + target: welcomeText + text: "It's a draw." + } + }, + State { + name: "game" + when: controller.current.game + PropertyChanges { + target: welcomeText + text: "Welcome" + } + }, + State { + name: "default" + when: !controller.current.waitForBet + PropertyChanges { + target: betContainer + opacity: 0 + } + } + ] Text { id: welcomeText text: "Blackjack" font.pixelSize: 24 - states: [ - State { - name: "placeBets" - when: controller.current.waitForBet - PropertyChanges { - target: welcomeText - text: "Please place your bet" - } - }, - State { - name: "game" - when: controller.current.game - PropertyChanges { - target: welcomeText - text: "Welcome" - } - } - ] + height: 40 } Rectangle { color: "white" - x: 100 - y: 100 + height: 40 + id: pointsContainer + anchors.top: welcomeText.bottom Text { color: "blue" text: "You have " + controller.data.points + " points" + font.pixelSize: 24 } } + Text { + id: handContainer + height: 30 + font.pixelSize: 24 + anchors.top: pointsContainer.bottom + color: "red" + text: "You: "+controller.data.myHand + } + Text { + id: dealerContainer + height: 30 + font.pixelSize: 24 + anchors.left: handContainer.right + anchors.top: handContainer.top + anchors.leftMargin: 10 + text: "Dealer: "+controller.data.dealerHand + } Rectangle { color: "white" - id: betEditBg - x: 80 - y: 400 + id: betContainer + anchors.top: handContainer.bottom + radius: 5 width: 100 - height: 20 + height: 40 + color: "#ffcc33" + opacity: Behavior { NumberAnimation { duration: 300; easing: "InOutQuad" } } TextInput { id: betEdit color: "black" - anchors.fill: parent text: controller.data.pointsToBet + font.pixelSize: 24 + anchors.fill: parent + horizontalAlignment: "AlignHCenter" } - states: [ - State { - name: "placeBets" - when: controller.current.waitForBet - PropertyChanges { - target: betEditBg - color: "#ffcc33" - opacity: 1 - } - }, - State { - name: "default" - when: !controller.current.waitForBet - PropertyChanges { - target: betEditBg - opacity: 0 + Rectangle { + width: 100 + height: betEdit.height + radius: 5 + color: "blue" + anchors.left: betEdit.right + MouseRegion { + anchors.fill: parent + onClicked: { + controller.data.pointsToBet = betEdit.text; + controller.events.bet.raise(); } } - ] + Text { + color: "#ffffcc" + text: "Bet" + font.weight: "Bold" + font.pixelSize: 18 + anchors.fill: parent + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + } + } } Rectangle { - anchors.left: betEditBg.right - anchors.top: betEditBg.top - anchors.bottom: betEditBg.bottom + color: "white" + id: actionContainer + anchors.top: handContainer.bottom + radius: 5 width: 100 - color: "blue" - MouseRegion { + height: 40 + color: "#ffcc33" + opacity: 0 + Rectangle { + id: hitButton + color: "green" anchors.fill: parent - onClicked: { controller.events.bet.raise(); } + opacity: Behavior { NumberAnimation { duration: 300; easing: "InOutQuad" } } + MouseRegion { + anchors.fill: parent + onClicked: { + controller.events.hit.raise(); + } + } + Text { + color: "#ffffcc" + text: "Hit" + anchors.fill: parent + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + } } - Text { - color: "yellow" - text: "Bet" + Rectangle { + id: standButton + width: 100 + height: hitButton.height + radius: 5 + color: "#9966cc" + anchors.left: hitButton.right + MouseRegion { + anchors.fill: parent + onClicked: { + controller.events.stand.raise(); + } + } + Text { + color: "#ffffcc" + text: "Stand" + anchors.fill: parent + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + } } } diff --git a/examples/qml/blackjack/blackjack.scxml b/examples/qml/blackjack/blackjack.scxml index ab1b9cd..0c32a3e 100644 --- a/examples/qml/blackjack/blackjack.scxml +++ b/examples/qml/blackjack/blackjack.scxml @@ -1,224 +1,196 @@ -<scxml - xmlns="http://www.w3.org/2005/07/scxml" - initial="root" profile="ecmascript"> - <datamodel> +<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="root" profile="ecmascript"> + <datamodel> <data id="points" expr="1000" /> <data id="pot" expr="0" /> <data id="pointsToBet" expr="0" /> - </datamodel> + <data id="myHand" expr="new Deck()" /> + <data id="dealerHand" expr="new Deck()" /> + <data id="availDeck" expr="new Deck()" /> + </datamodel> <script><![CDATA[ - var Suits = "CDHS"; - var Ranks = "-A23456789TJQK"; - - function Card (r,s) - { - this.rank = r; - this.suit = s; - this.minValue = Math.min(r,10); - this.toString = function() { - return "" + Ranks[this.rank] + Suits[this.suit]; - }; -; + var Suits = "CDHS"; + var Ranks = "-A23456789TJQK"; + + function Card (r,s) + { + this.rank = r; + this.suit = s; + this.minValue = Math.min(r,10); + } + + Card.prototype.toString = function() { + return "" + Ranks[this.rank] + Suits[this.suit]; + }; + + function Deck() {} + Deck.prototype = + { + draw: function() { return this.cards.pop(); scxml.notifyChange(this);}, + cards: [], + reshuffle: function() { + this.clear (); + function randomSort(a,b) { + return Math.random() - 0.5; } - function Deck() - { - this.draw = function() - { - return this.cards.pop(); - }; - this.cards = new Array(); - this.reset = function() - { - this.clear (); - for (var i=1; i <= 13; ++i) - for (var j = 0; j < 4; ++j) - this.cards.push(new Card(i,j)); - this.cards.sort(function (a,b) - { - return Math.random() * 3 - 1; - }); - }; - - this.clear = function() - { - this.cards = new Array; - }; - this.evalMin = function () - { - var minVal = 0; - var cardCount = this.cards.length; - for (c in this.cards) { - minVal += this.cards[c].minValue; - } - if (cardCount > 4 && minVal < 22) - minVal = 21; - return minVal; - }; - - this.evalBest = function() - { - var bestVal = this.evalMin(); - if (bestVal > 21) - return 0; - else if (bestVal == 21) - return bestVal; - - for (i in this.cards) { - if (this.cards[i].rank == 1) - { - var v = bestVal + 10; - if (v <= 21) - bestVal = v; - } - } - return bestVal; - - }; - this.toString = function() - { - var s = ""; - for (i in this.cards) - s += this.cards[i].toString() + ":"; - - return s; - }; - - this.drawFrom = function(d) - { - var c = d.draw (); - this.cards.push(c); -// updateDisplay (); - }; + for (var i=1; i <= 13; ++i) + for (var j = 0; j < 4; ++j) + this.cards.push(new Card(i,j)); + this.cards.sort(randomSort); + }, + + clear: function() { + this.cards = []; + scxml.notifyChange(this); + }, + evalMin: function () { + var minVal = 0; + var cardCount = this.cards.length; + for (c in this.cards) { + minVal += this.cards[c].minValue; } - - - function hitMe () - { - myDeck.drawFrom (availDeck); + if (cardCount > 4 && minVal < 22) + minVal = 21; + return minVal; + }, + evalBest: function() { + var bestVal = this.evalMin(); + if (bestVal > 21) + return 0; + else if (bestVal == 21) + return bestVal; + + for (i in this.cards) { + if (this.cards[i].rank == 1) + { + var v = bestVal + 10; + if (v <= 21) + bestVal = v; + } } + return bestVal; + + }, + toString: function() { + return this.cards.join(' '); + }, + drawFrom: function(d) { + this.cards.push(d.draw ()); + scxml.notifyChange(this); + } + }; + + function hitMe () + { + _data.myHand.drawFrom (_data.availDeck); + } ]]></script> - <final id="exit" /> <state id="root" initial="newgame"> - <onentry> - <script> - var myDeck = new Deck; - var dealerCards = new Deck; - var availDeck = new Deck; - </script> - - </onentry> - <transition event="NEWGAME" target="newgame" /> - <state id="newgame"> - <transition target="newround" /> - </state> - <state id="quitdlg"> - <transition event="YES" target="exit" /> - <transition event="NO" target="gamestate" /> - </state> - <state id="game"> - <history type="deep" id="gamestate" /> - <transition event="EXIT" target="quitdlg" /> - <state id="newround"> <onentry> - <assign dataid="pot" expr="0" /> - <script> - availDeck.reset (); - myDeck.clear (); - dealerCards.clear(); - dealerCards.drawFrom(availDeck); - hitMe (); - hitMe (); - </script> + <assign dataid="myHand" expr="new Deck()" /> + <assign dataid="dealerHand" expr="new Deck()" /> + <assign dataid="availDeck" expr="new Deck()" /> </onentry> - <transition target="waitForBet" /> - </state> - <state id="waitForBet"> - <transition event="BET" target="testCards" cond="parseInt(_data.pointsToBet) <= _data.points"> - <assign dataid="pot" expr="_data.pointsToBet" /> - <assign dataid="points" expr="_data.points-_data.pot" /> - </transition> - <transition event="BET" target="betTooHigh" cond="parseInt(_data.pointsToBet) > _data.points"> - </transition> - <transition event="SURRENDER" target="newround" /> - </state> - <state id="betTooHigh"> - <transition event="OK" target="waitForBet" /> - <transition event="TIMEOUT" target="waitForBet" /> - <onentry> - <send event="TIMEOUT" delay="1500ms" /> - </onentry> - </state> - <state id="testCards"> - <transition target="loss" cond="myDeck.evalBest() == 0" /> - <transition target="getDealerCards" cond="myDeck.evalBest() == 21" /> - <transition target="waitForAction" cond="myDeck.evalBest() %21 != 0" /> - </state> - - <state id="waitForAction"> - <transition event="HIT" target="testCards"> - <script>hitMe (); </script> - </transition> - <transition event="STAND" target="getDealerCards" /> - </state> - - <state id="getDealerCards"> - <onentry> - <script><![CDATA[ - while (dealerCards.evalBest() > 0 && dealerCards.evalBest() < 17) - dealerCards.drawFrom(availDeck); - ]]></script> - <raise event="DONE" /> - </onentry> - <transition target="checkWinner" /> - </state> - - <state id="checkWinner"> + <transition event="NEWGAME" target="newgame" /> + <state id="newgame"> + <transition target="newRound" /> + </state> + <state id="quitdlg"> + <transition event="YES" target="exit" /> + <transition event="NO" target="gamestate" /> + </state> + <state id="game"> + <history type="deep" id="gamestate" /> + <transition event="EXIT" target="quitdlg" /> + <state id="newRound"> + <onentry> + <assign dataid="pot" expr="0" /> + <script> + _data.availDeck.reshuffle (); + _data.myHand.clear (); + _data.dealerHand.clear(); + _data.dealerHand.drawFrom(_data.availDeck); + hitMe (); + hitMe (); + </script> + </onentry> + <transition target="waitForBet" /> + </state> + <state id="waitForBet"> + <transition event="BET" target="testCards" cond="parseInt(_data.pointsToBet) <= _data.points"> + <assign dataid="pot" expr="_data.pointsToBet" /> + <assign dataid="points" expr="_data.points-_data.pot" /> + </transition> + <transition event="BET" target="betTooHigh" cond="parseInt(_data.pointsToBet) > _data.points" /> + <transition event="SURRENDER" target="newRound" /> + </state> + <state id="betTooHigh"> + <transition event="OK" target="waitForBet" /> + <transition event="TIMEOUT" target="waitForBet" /> + <onentry> + <send event="TIMEOUT" delay="1500ms" /> + </onentry> + </state> + <state id="testCards"> + <transition target="loss" cond="_data.myHand.evalBest() == 0" /> + <transition target="getdealerHand" cond="_data.myHand.evalBest() == 21" /> + <transition target="waitForAction" cond="_data.myHand.evalBest() %21 != 0" /> + </state> - <onentry> - <assign location="_data.diff" expr="myDeck.evalBest() - dealerCards.evalBest()" /> - </onentry> + <state id="waitForAction"> + <transition event="HIT" target="testCards"> + <script>hitMe (); </script> + </transition> + <transition event="STAND" target="getdealerHand" /> + </state> - <transition cond="diff>0" target="win" /> - <transition cond="diff<0" target="loss" /> - <transition cond="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" /> - </onentry> - </state> - <state id="endRound"> - <invoke type="q-bindings"><content>[[newRoundButton,"enabled",true]]</content></invoke> - <transition event="NEWROUND" target="newround" /> - <transition event="TIMEOUT" target="newround" /> - <onentry> - <send event="TIMEOUT" delay="3s" /> - </onentry> + <state id="getdealerHand"> + <onentry> + <script><![CDATA[ + while (_data.dealerHand.evalBest() > 0 && _data.dealerHand.evalBest() < 17) + _data.dealerHand.drawFrom(_data.availDeck); + ]]></script> + <raise event="DONE" /> + </onentry> + <transition target="checkWinner" /> + </state> - <state id="win"> + <state id="checkWinner"> + <onentry> + <assign location="_data.diff" expr="_data.myHand.evalBest() - _data.dealerHand.evalBest()" /> + </onentry> + <transition cond="_data.diff > 0" target="win" /> + <transition cond="_data.diff < 0" target="loss" /> + <transition cond="_data.diff==0" target="draw" /> + </state> + <state id="endGame"> + <transition event="TIMEOUT" target="newgame" /> <onentry> - <assign dataid="points" expr="Math.floor(_data.points) + Math.floor(_data.pot) * 2" /> + <send event="TIMEOUT" delay="3s" /> </onentry> - </state> - <state id="loss"> - <invoke type="q-bindings"><content>[[welcomeLabel,"text","You Lost..."]]</content></invoke> - <transition cond="points == 0" target="endGame" /> + </state> + <state id="endRound"> + <transition event="newRound" target="newRound" /> + <transition event="TIMEOUT" target="newRound" /> + <onentry> + <send event="TIMEOUT" delay="3s" /> + </onentry> + + <state id="win"> + <onentry> + <assign dataid="points" expr="Math.floor(_data.points) + Math.floor(_data.pot) * 2" /> + </onentry> + </state> + <state id="loss"> + <transition cond="_data.points == 0" target="endGame" /> </state> <state id="draw"> - <invoke type="q-bindings"><content>[[welcomeLabel,"text","You It's a draw."]]</content></invoke> - <onentry> - <assign dataid="points" expr="Math.floor(_data.points) + Math.floor(pot)" /> - </onentry> + <onentry> + <assign dataid="points" expr="Math.floor(_data.points) + Math.floor(_data.pot)" /> + </onentry> </state> </state> </state> - </state> - + <final id="exit" /> </scxml> - - - diff --git a/examples/qml/blackjack/main.cpp b/examples/qml/blackjack/main.cpp index dd7777a..87639d6 100644 --- a/examples/qml/blackjack/main.cpp +++ b/examples/qml/blackjack/main.cpp @@ -48,6 +48,7 @@ int main(int argc, char ** argv) { QApplication app(argc, argv); + qsrand(QDateTime::currentDateTime().toTime_t()); QmlView view(NULL); QmlComponent component(view.engine(), "blackjack.qml"); diff --git a/qmlscxml/qmlscxml.cpp b/qmlscxml/qmlscxml.cpp index 04a4c89..367fff1 100644 --- a/qmlscxml/qmlscxml.cpp +++ b/qmlscxml/qmlscxml.cpp @@ -41,6 +41,7 @@ #include "qmlscxml.h" #include "qscxml.h" #include <QDebug> +#include <QTimer> #include "qmlpropertymap.h" class QmlScxmlEventProxy : public QObject @@ -61,7 +62,9 @@ class QmlScxmlEventProxy : public QObject public Q_SLOTS: void raise() { - scxml->postNamedEvent(eventName); + if (scxml) { + scxml->postDelayedEvent(new QScxmlEvent(eventName),0); + } } void onEvent(const QString & e) @@ -122,7 +125,6 @@ namespace { }; void QmlScxml::setSource(const QUrl & u) { - qDebug() << u; if (u != m_source) { m_source = u; if (scxml) { @@ -135,6 +137,7 @@ void QmlScxml::setSource(const QUrl & u) connect(scxml,SIGNAL(stopped()),this,SIGNAL(runningChanged())); connect(scxml,SIGNAL(finished()),this,SIGNAL(finished())); connect(scxml,SIGNAL(eventTriggered(QString)),this,SIGNAL(trigger(QString))); + connect(scxml,SIGNAL(dataChanged(QString,QVariant)),this,SLOT(onDataChanged(QString,QVariant))); connect(scxml,SIGNAL(configurationChanged()),this,SLOT(checkConfig())); if (m_states) delete m_states; @@ -185,18 +188,42 @@ void QmlScxml::setSource(const QUrl & u) } } +class QmlScxmlDataTestTimer : public QTimer +{ + QString key; + QScxml* scxml; + QmlPropertyMap* propMap; + public: + QmlScxmlDataTestTimer(const QString & k, QScxml* qs, QmlPropertyMap* pm) + : QTimer(qs),key(k),scxml(qs),propMap(pm) + { + setInterval(0); + setSingleShot(true); + start(); + } + + void timerEvent(QTimerEvent* te) + { + if (te->timerId() == timerId()) { + + scxml->setData(key,propMap->value(key)); + deleteLater(); + } + } + +}; + void QmlScxml::onDataChanged(const QString & key) { - qDebug() << "onDataChanged" << key; - m_data->blockSignals(true); - scxml->setData(key,(*m_data)[key]); - m_data->blockSignals(false); + new QmlScxmlDataTestTimer(key,scxml,m_data); } void QmlScxml::onDataChanged(const QString & key, const QVariant & value) { - qDebug() << "onDataChanged" << key << value; if (m_data) { - (*m_data)[key] = value; + if ((*m_data)[key] != value) { + (*m_data)[key] = value; + emit dataChanged(m_data); + } } } @@ -243,7 +270,7 @@ void QmlScxml::setRunning(bool r) void QmlScxml::raise(const QString & e) { if (scxml) { - scxml->postNamedEvent(e); + scxml->postDelayedEvent(new QScxmlEvent(e),0); } } void QmlScxml::stop() diff --git a/src/qscxml.cpp b/src/qscxml.cpp index 3896bda..68412ed 100644 --- a/src/qscxml.cpp +++ b/src/qscxml.cpp @@ -70,6 +70,7 @@ #include <QState> #include <QMetaMethod> #include <QScriptProgram> +#include <QScriptClass> @@ -199,6 +200,8 @@ class QScxmlPrivate QSet<QString> knownEvents; + QScriptClass* scriptClass; + static QHash<QString,QScxml*> sessions; }; QHash<QString,QScxml*> QScxmlPrivate::sessions; @@ -439,19 +442,41 @@ static QScriptValue invoke(QScriptContext *context, QScriptEngine *engine) return QScriptValue(); } +static QScriptValue notifyChange(QScriptContext *context, QScriptEngine * engine) +{ + if (context->argumentCount() > 0) { + QScriptValue val = context->argument(0); + if (val.data().isObject()) { + QString key = val.data().property("key").toString(); + if (key != "") { + notifyDataChange(engine,key,val.data().property("value")); + } + } + } + return QScriptValue(); +} +static void notifyDataChange (QScriptEngine* engine, const QString & id, const QScriptValue & v) +{ + QScxml* scxml = qobject_cast<QScxml*>(engine->globalObject().property("scxml").toQObject()); + if (scxml) { + scxml->dataChanged(id,v.toVariant()); + } +} + + static QScriptValue dataAccess(QScriptContext *context, QScriptEngine * engine) { if (context->argumentCount() == 0) { // getter - return context->callee().property("value"); + return context->callee().data().property("value"); } else if (context->argumentCount() == 1) { // setter QScriptValue val = context->argument(0); - context->callee().setProperty("value",val); - qDebug() << "data set" << val.toVariant() << context->callee().property("key").toString(); + context->callee().data().setProperty("value",val); + val.setData(context->callee().data()); QScxml* scxml = qobject_cast<QScxml*>(engine->globalObject().property("scxml").toQObject()); if (scxml) { - scxml->dataChanged(context->callee().property("key").toString(),val.toVariant()); + scxml->dataChanged(context->callee().data().property("key").toString(),val.toVariant()); } return val; } else @@ -494,9 +519,9 @@ void QScxmlPrivate::initScriptEngine(QScxml* thiz) scxmlObj.setProperty("setTimeout",scriptEng->newFunction(QScxmlFunctions::setTimeout)); scxmlObj.setProperty("clearTimeout",scriptEng->newFunction(QScxmlFunctions::clearTimeout)); scxmlObj.setProperty("connectSignalToEvent",scriptEng->newFunction(QScxmlFunctions::connectSignalToEvent)); + scxmlObj.setProperty("notifyChange",scriptEng->newFunction(QScxmlFunctions::notifyChange)); QScriptValue dmObj = scriptEng->newObject(); dataObj = scriptEng->newObject(); - dataObj.setProperty("_values",scriptEng->newObject()); glob.setProperty("_data",dataObj); glob.setProperty("_global",scriptEng->globalObject()); glob.setProperty("scxml",scxmlObj); @@ -595,9 +620,9 @@ QScxmlTransition::QScxmlTransition (QState* state,QScxml* machine) { } -void QScxmlTransition::setConditionExpression(const QString & c) +void QScxmlTransition::setConditionExpression(const QString & cond) { - prog = QScriptProgram(c,scxml->baseUrl().toLocalFile()); + prog = QScriptProgram(cond,scxml->baseUrl().toLocalFile()); } QString QScxmlTransition::conditionExpression() const @@ -936,10 +961,7 @@ void QScxml::postNamedEvent(const QString & event) void QScxml::setData(const QString & id, const QVariant & val) { - QScriptValue accessor = pvt->dataObj.property(id); - if (accessor.isFunction()) { - accessor.setProperty("value",scriptEngine()->newVariant(val)); - } + pvt->dataObj.setProperty(id,scriptEngine()->newVariant(val)); } /*! @@ -1100,78 +1122,80 @@ QEvent::Type QScxmlEvent::eventType() static QEvent::Type _t = (QEvent::Type)QEvent::registerEventType(QEvent::User+200); return _t; } -const char SCXML_NAMESPACE [] = "http://www.w3.org/2005/07/scxml"; +namespace { + const char SCXML_NAMESPACE [] = "http://www.w3.org/2005/07/scxml"; -struct ScTransitionInfo -{ - - QScxmlTransition* transition; - QStringList targets; - QString script; - ScTransitionInfo() : transition(NULL) {} -}; + struct ScTransitionInfo + { -class QScxmlScriptExec : public QObject -{ - Q_OBJECT - QScriptProgram prog; - QScxml* scxml; - public: - QScxmlScriptExec(const QString & scr, QScxml* scx) : - prog(QScriptProgram(scr,scx->baseUrl().toLocalFile())),scxml(scx) - { - } - public Q_SLOTS: - void exec() - { - scxml->executeScript(prog); - } -}; + QScxmlTransition* transition; + QStringList targets; + QString script; + ScTransitionInfo() : transition(NULL) {} + }; -struct ScStateInfo -{ - QString initial; -}; + class QScxmlScriptExec : public QObject + { + Q_OBJECT + QScriptProgram prog; + QScxml* scxml; + public: + QScxmlScriptExec(const QString & scr, QScxml* scx) : + prog(QScriptProgram(scr,scx->baseUrl().toLocalFile())),scxml(scx) + { + } + public Q_SLOTS: + void exec() + { + scxml->executeScript(prog); + } + }; -struct ScHistoryInfo -{ - QHistoryState* hstate; - QString defaultStateID; -}; + struct ScStateInfo + { + QString initial; + }; -struct ScExecContext -{ - QScxml* sm; - QString script; - enum {None, StateEntry,StateExit,Transition } type; - QScxmlTransition* trans; - QAbstractState* state; - ScExecContext() : sm(NULL),type(None),trans(NULL),state(NULL) + struct ScHistoryInfo { - } + QHistoryState* hstate; + QString defaultStateID; + }; - void applyScript() + struct ScExecContext { - if (!script.isEmpty()) { - QScxmlScriptExec* exec = new QScxmlScriptExec(script,sm); - switch(type) { - case StateEntry: - QObject::connect(state,SIGNAL(entered()),exec,SLOT(exec())); - break; - case StateExit: - QObject::connect(state,SIGNAL(exited()),exec,SLOT(exec())); - break; - case Transition: - QObject::connect(trans,SIGNAL(triggered()),exec,SLOT(exec())); - break; - default: - delete exec; - break; + QScxml* sm; + QString script; + enum {None, StateEntry,StateExit,Transition } type; + QScxmlTransition* trans; + QAbstractState* state; + ScExecContext() : sm(NULL),type(None),trans(NULL),state(NULL) + { + } + + void applyScript() + { + if (!script.isEmpty()) { + QScxmlScriptExec* exec = new QScxmlScriptExec(script,sm); + switch(type) { + case StateEntry: + QObject::connect(state,SIGNAL(entered()),exec,SLOT(exec())); + break; + case StateExit: + QObject::connect(state,SIGNAL(exited()),exec,SLOT(exec())); + break; + case Transition: + QObject::connect(trans,SIGNAL(triggered()),exec,SLOT(exec())); + break; + default: + delete exec; + break; + } } } - } + }; }; class QScxmlLoader @@ -1436,21 +1460,24 @@ void QScxmlLoader::loadState ( curTransition->setObjectName(QString ("%1 to %2 on %3 if %4").arg(curState->objectName()).arg(inf.targets.join(" ")).arg(curTransition->eventPrefixes().join(" ")).arg(curTransition->conditionExpression())); } } else if (r.name().toString().compare("data",Qt::CaseInsensitive) == 0) { - QScriptValue val = qScriptValueFromValue<QString>(stateMachine->scriptEngine(),"") ; + QScriptEngine* engine = stateMachine->scriptEngine(); + QScriptValue val = qScriptValueFromValue<QString>(engine,"") ; QString id = r.attributes().value("id").toString(); if (r.attributes().value("src").length()) val = evaluateFile(QFileInfo(filename).dir().absoluteFilePath(r.attributes().value("src").toString())); else { if (r.attributes().value("expr").length()) { - val = stateMachine->scriptEngine()->evaluate(r.attributes().value("expr").toString()); + val = engine->evaluate(r.attributes().value("expr").toString()); } else { QString t = r.readElementText(); if (!t.isEmpty()) - val = stateMachine->scriptEngine()->evaluate(t); + val = engine->evaluate(t); } } - QScriptValue func = stateMachine->scriptEngine()->newFunction(QScxmlFunctions::dataAccess); - func.setProperty("key",id); + QScriptValue func = engine->newFunction(QScxmlFunctions::dataAccess); + QScriptValue accessor = engine->newObject(); + accessor.setProperty("key",id); + func.setData(accessor); 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) { @@ -1532,7 +1559,6 @@ void QScxmlLoader::loadState ( } } } - QMap<QString,QVariant> QScxml::data() const { QMap<QString,QVariant> d; |