summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/qml/blackjack/blackjack.qml213
-rw-r--r--examples/qml/blackjack/blackjack.scxml372
-rw-r--r--examples/qml/blackjack/main.cpp1
-rw-r--r--qmlscxml/qmlscxml.cpp45
-rw-r--r--src/qscxml.cpp180
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) &lt;= _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) &gt; _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) &lt;= _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) &gt; _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&gt;0" target="win" />
- <transition cond="diff&lt;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 &gt; 0" target="win" />
+ <transition cond="_data.diff &lt; 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;