summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-06-10 22:47:14 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-06-10 22:47:14 (GMT)
commit6f56474450b7c54f2c95b5dea6a7a42623141649 (patch)
tree420c52085d8cf778360c09baf9722b21d01259da /apps
parenta154682fc1b25581742d38dd5fe9aa06ede167b7 (diff)
downloaduscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.zip
uscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.tar.gz
uscxml-6f56474450b7c54f2c95b5dea6a7a42623141649.tar.bz2
W3C MMI Architecture framework
Diffstat (limited to 'apps')
-rw-r--r--apps/samples/map/map.html30
-rw-r--r--apps/samples/map/map.js158
-rw-r--r--apps/samples/vrml.zipbin0 -> 117742 bytes
-rw-r--r--apps/samples/vrml/img/Tutorial.pngbin0 -> 34969 bytes
-rw-r--r--apps/samples/vrml/img/Tutorial.pxmbin0 -> 123387 bytes
-rw-r--r--apps/samples/vrml/img/drag.pngbin0 -> 3543 bytes
-rw-r--r--apps/samples/vrml/img/drag2.pngbin0 -> 509 bytes
-rw-r--r--apps/samples/vrml/img/drag3.pngbin0 -> 186 bytes
-rw-r--r--apps/samples/vrml/img/pitchRoll.pngbin0 -> 913 bytes
-rw-r--r--apps/samples/vrml/img/pitchRoll3.pngbin0 -> 3596 bytes
-rw-r--r--apps/samples/vrml/img/xy.pngbin0 -> 746 bytes
-rw-r--r--apps/samples/vrml/img/xy2.pngbin0 -> 820 bytes
-rw-r--r--apps/samples/vrml/img/yawZoom.pngbin0 -> 2252 bytes
-rw-r--r--apps/samples/vrml/viewer.html33
-rw-r--r--apps/samples/vrml/viewer.js572
-rw-r--r--apps/uscxml-browser.cpp (renamed from apps/mmi-browser.cpp)18
-rw-r--r--apps/uscxml-browser.vbs (renamed from apps/mmi-browser.vbs)0
-rw-r--r--apps/w3c-mmi/MMIEventServlet.cpp210
-rw-r--r--apps/w3c-mmi/MMIEventServlet.h59
-rw-r--r--apps/w3c-mmi/im/MMISessionManager.cpp257
-rw-r--r--apps/w3c-mmi/im/MMISessionManager.h81
-rw-r--r--apps/w3c-mmi/im/uscxml-interaction-manager.cpp182
-rw-r--r--apps/w3c-mmi/mc/uscxml-modality-component.cpp191
23 files changed, 1513 insertions, 278 deletions
diff --git a/apps/samples/map/map.html b/apps/samples/map/map.html
new file mode 100644
index 0000000..01dc92b
--- /dev/null
+++ b/apps/samples/map/map.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/tundra/tundra.css">
+ <!-- link rel="stylesheet" href="map.css" -->
+ <script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>
+ <style type="text/css">
+ </style>
+
+ <script type="text/javascript">
+ </script>
+
+ <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
+ <script type="text/javascript" src="map.js"></script>
+
+ <script type="text/javascript">
+ require(["dojo/domReady!", "dojo"], function(dom, dojo) {
+ var map = new Map("map");
+ });
+ </script>
+ </head>
+ <body class="tundra">
+ <table>
+ <tr><td>
+ <div id="map" />
+ </td></tr>
+ </table>
+ </body>
+</html>
diff --git a/apps/samples/map/map.js b/apps/samples/map/map.js
new file mode 100644
index 0000000..6794875
--- /dev/null
+++ b/apps/samples/map/map.js
@@ -0,0 +1,158 @@
+function Map(element) {
+
+ // private attributes
+ var self = this;
+
+ // private instanceId
+ if (!Map.instances)
+ Map.instances = 0;
+ var instanceId = Map.instances++;
+
+ // public attributes
+ this.coords = {};
+
+
+ require([
+ "dojo/ready",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dojo/dom",
+ "dojox/geo/openlayers/Map",
+ "dojox/geo/openlayers/GfxLayer",
+ "dojox/geo/openlayers/Layer",
+ "dojox/geo/openlayers/GeometryFeature",
+ "dojox/geo/openlayers/Point",
+ "dojox/geo/openlayers/LineString",
+ "dojox/geo/openlayers/WidgetFeature",
+ "dojox/charting/widget/Chart",
+ "dojox/charting/widget/Chart2D",
+ "dojox/charting/plot2d/Pie",
+ "dojox/charting/themes/PlotKit/blue"
+ ], function(
+ ready,
+ domConstruct,
+ win,
+ dom,
+ Map,
+ GfxLayer,
+ Layer,
+ GeometryFeature,
+ Point,
+ LineString,
+ WidgetFeature,
+ Chart,
+ Chart2D,
+ Pie,
+ blue
+ ) {
+ ready(function(){
+
+ if (typeof(element) === 'string') {
+ element = dom.byId(element);
+ }
+
+ element.style.width = "450px";
+ element.style.height = "350px";
+
+ var options = {
+ baseLayerName: "WorldMap",
+ baseLayerType : dojox.geo.openlayers.BaseLayerType.OSM,
+ //baseLayerUrl: "http://localhost/mapserver/mapserv.cgi?map=./world.map",
+ baseLayerOptions: {
+ layers: ['contry','state','city','town','highway']
+ },
+ touchHandler: false,
+ accessible: true
+ };
+
+ // Available base layers: http://dojotoolkit.org/reference-guide/1.7/dojox/geo/openlayers.html#id5
+ self.map = new Map(element, options);
+
+ // This is New York location
+ var ny = {
+ latitude : 49.877648,
+ longitude : 8.654762
+ };
+
+ var people = [ {
+ name : 'Dirk',
+ y : 49.877848,
+ x : 8.653762
+ }, {
+ name : 'Stefan',
+ y : 49.877348,
+ x : 8.655462
+ } ];
+
+ var div = domConstruct.create("div", {}, win.body());
+ //var div = domConstruct.create("div", {});
+ var chart = new Chart({
+ margins : {
+ l : 0,
+ r : 0,
+ t : 0,
+ b : 0
+ }
+ }, div);
+
+ var c = chart.chart;
+ c.addPlot("default", {
+ type : "Pie",
+ radius : 50,
+ labelOffset : 100,
+ fontColor : "black",
+ fontSize : 20
+ });
+
+ var ser = [ 2, 8, 12, 3 ];
+ c.addSeries("Series", ser);
+ c.setTheme(blue);
+ c.render();
+ c.theme.plotarea.fill = undefined;
+
+ var descr = {
+ longitude : ny.longitude,
+ latitude : ny.latitude,
+ widget : chart,
+ width : 120,
+ height : 120
+ };
+ feat3 = new WidgetFeature(descr);
+
+ // create a GfxLayer
+ var layer = new GfxLayer();
+
+ var point = new Point({
+ x:ny.longitude,
+ y:ny.latitude
+ });
+ // create a GeometryFeature
+ var feat = new GeometryFeature(point);
+ // set the shape properties, fill and stroke
+ feat.setFill([ 0, 128, 128 ]);
+ feat.setStroke([ 0, 0, 0 ]);
+ feat.setShapeProperties({
+ r : 8
+ });
+
+ var pts = new LineString(people);
+ // create a GeometryFeature
+ var feat2 = new GeometryFeature(pts);
+ // set the shape stroke property
+ feat2.setStroke([ 0, 0, 0 ]);
+
+ // add the feature to the layer
+ layer.addFeature(feat);
+ layer.addFeature(feat2);
+ layer.addFeature(feat3);
+ // add layer to the map
+ self.map.addLayer(layer);
+
+ // fit to New York with 0.1 degrees extent
+ self.map.fitTo({
+ position : [ ny.longitude, ny.latitude ],
+ extent : 0.001
+ });
+ });
+ });
+}
diff --git a/apps/samples/vrml.zip b/apps/samples/vrml.zip
new file mode 100644
index 0000000..730236b
--- /dev/null
+++ b/apps/samples/vrml.zip
Binary files differ
diff --git a/apps/samples/vrml/img/Tutorial.png b/apps/samples/vrml/img/Tutorial.png
new file mode 100644
index 0000000..7f5a041
--- /dev/null
+++ b/apps/samples/vrml/img/Tutorial.png
Binary files differ
diff --git a/apps/samples/vrml/img/Tutorial.pxm b/apps/samples/vrml/img/Tutorial.pxm
new file mode 100644
index 0000000..682a00c
--- /dev/null
+++ b/apps/samples/vrml/img/Tutorial.pxm
Binary files differ
diff --git a/apps/samples/vrml/img/drag.png b/apps/samples/vrml/img/drag.png
new file mode 100644
index 0000000..b398a3f
--- /dev/null
+++ b/apps/samples/vrml/img/drag.png
Binary files differ
diff --git a/apps/samples/vrml/img/drag2.png b/apps/samples/vrml/img/drag2.png
new file mode 100644
index 0000000..4dfb651
--- /dev/null
+++ b/apps/samples/vrml/img/drag2.png
Binary files differ
diff --git a/apps/samples/vrml/img/drag3.png b/apps/samples/vrml/img/drag3.png
new file mode 100644
index 0000000..467ba6e
--- /dev/null
+++ b/apps/samples/vrml/img/drag3.png
Binary files differ
diff --git a/apps/samples/vrml/img/pitchRoll.png b/apps/samples/vrml/img/pitchRoll.png
new file mode 100644
index 0000000..4f73745
--- /dev/null
+++ b/apps/samples/vrml/img/pitchRoll.png
Binary files differ
diff --git a/apps/samples/vrml/img/pitchRoll3.png b/apps/samples/vrml/img/pitchRoll3.png
new file mode 100644
index 0000000..ede9247
--- /dev/null
+++ b/apps/samples/vrml/img/pitchRoll3.png
Binary files differ
diff --git a/apps/samples/vrml/img/xy.png b/apps/samples/vrml/img/xy.png
new file mode 100644
index 0000000..fe081ee
--- /dev/null
+++ b/apps/samples/vrml/img/xy.png
Binary files differ
diff --git a/apps/samples/vrml/img/xy2.png b/apps/samples/vrml/img/xy2.png
new file mode 100644
index 0000000..2cc3f15
--- /dev/null
+++ b/apps/samples/vrml/img/xy2.png
Binary files differ
diff --git a/apps/samples/vrml/img/yawZoom.png b/apps/samples/vrml/img/yawZoom.png
new file mode 100644
index 0000000..a256b3b
--- /dev/null
+++ b/apps/samples/vrml/img/yawZoom.png
Binary files differ
diff --git a/apps/samples/vrml/viewer.html b/apps/samples/vrml/viewer.html
index 1e1043b..9838c33 100644
--- a/apps/samples/vrml/viewer.html
+++ b/apps/samples/vrml/viewer.html
@@ -38,16 +38,37 @@
<script type="text/javascript">
require(["dojo/domReady!", "dojo"], function(dom, dojo) {
- var viewer = new VRMLViewer("scene1");
- var annotations = new Annotations("annotations1", { 'viewer': viewer });
+ var viewer = new VRMLViewer("scene1", {
+ "pose": {
+ "pitch" : 0,
+ "roll" : 0,
+ "yaw" : 0,
+ "zoom" : 1,
+ "x" : 0,
+ "y" : 0,
+ "z" : 0,
+ "width" : 400,
+ "height" : 400,
+ "autorotate" : false
+ },
+ "serverURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml",
+ "imageURL": "http://smartvortex.tbm.tudelft.nl:8090/vrml/hook/HARD_MP_VAL_005.png"
+ });
+ var viewer2 = new VRMLViewer("scene2");
+// var annotations = new Annotations("annotations1", { 'viewer': viewer });
});
</script>
</head>
<body class="tundra">
- <table>
- <tr><td>
- <div id="scene1" />
- </td></tr>
+ <table align="center">
+ <tr>
+ <td><br /><br /><br /><br /><br /><br />
+ <div id="scene1" />
+ </td>
+ <td><br /><br /><br /><br /><br /><br />
+ <div id="scene2" />
+ </td>
+ </tr>
<tr><td>
<div id="annotations1"></div>
</td></tr>
diff --git a/apps/samples/vrml/viewer.js b/apps/samples/vrml/viewer.js
index f6f2e42..660a66a 100644
--- a/apps/samples/vrml/viewer.js
+++ b/apps/samples/vrml/viewer.js
@@ -6,10 +6,13 @@ function VRMLViewer(element, params) {
// private instanceId
if (!VRMLViewer.instances)
VRMLViewer.instances = 0;
- var instanceId = VRMLViewer.instances++;
+ this.instanceId = VRMLViewer.instances++;
var batchChanges = false;
// public attributes
+ this.width = 450;
+ this.height = 350;
+
this.pose = {};
this.pose.pitch = 0;
this.pose.roll = 0;
@@ -18,49 +21,142 @@ function VRMLViewer(element, params) {
this.pose.x = 0;
this.pose.y = 0;
this.pose.z = 0;
- this.pose.width = 450;
- this.pose.height = 350;
this.pose.autorotate = false;
-
- this.serverURL = "http://88.69.49.213:8080/vrml";
+ this.serverURL;
this.imageURL;
+
+ this.pose.width = this.width;
+ this.pose.height = this.height;
+
+ this.params = params;
+
+ // privileged public methods
+ this.updateScene = function() {
+ if (self.imageURL && !self.batchChanges) {
+ self.imgElem.src = self.imageURL + urlSuffixForPose(self.pose);
+ }
+ }
+
+ var urlSuffixForPose = function(pose) {
+ var url =
+ '?width=' + pose.width +
+ '&height=' + pose.height +
+ '&pitch=' + pose.pitch +
+ '&roll=' + pose.roll +
+ '&yaw=' + pose.yaw +
+ '&x=' + pose.x +
+ '&y=' + pose.y +
+ '&z=' + pose.z +
+ '&zoom=' + pose.zoom +
+ '&autorotate=' + (pose.autorotate ? '1' : '0');
+ return url;
+ }
+
+ var moverRelativeTo = function(mover, container) {
+ var containerPos = absolutePosition(container);
+ return {
+ x: mover.x - containerPos.x,
+ y: mover.y - containerPos.y
+ };
+ }
+
+ // see http://stackoverflow.com/questions/288699/get-the-position-of-a-div-span-tag
+ var absolutePosition = function(el) {
+ for (var lx=0, ly=0; el != null; lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
+ return {x: lx,y: ly};
+ }
+
+ this.refreshServer = function(server) {
+ self.serverURL = server;
+ self.localStorage.put("vrmlServer", self.serverURL, null);
+ self.progressElem.appendChild(self.progress.domNode);
+ self.progress.start();
+ self.xhr.get({
+ // The URL to request
+ url: server,
+ handleAs:"json",
+ headers:{"X-Requested-With":null},
+ load: function(result) {
+ self.progress.stop();
+ for (id in self.fileStore.query) {
+ self.fileStore.remove(id);
+ }
+ (function fillstore(tree, parentId) {
+ for (key in tree) {
+ if ('url' in tree[key]) {
+ self.fileStore.add({id:parentId+key, name:key, url:self.serverURL + tree[key].path, parent:parentId});
+ } else {
+ self.fileStore.add({id:parentId+key, name:key, parent:parentId});
+ fillstore(tree[key], parentId+key);
+ }
+ }
+ } (result.models, "root", ""));
+ }
+ });
+ }
+
+ this.setPose = function(imageURL, pose, serverURL) {
+ if (serverURL && serverURL != self.serverURL) {
+ self.refreshServer(serverURL);
+ }
+ self.imageURL = imageURL;
+ self.pose = pose;
+
+ var pitch = (pose.pitch % (2 * 3.14159) + 0.5) * 100;
+ var roll = (pose.roll % (2 * 3.14159) + 0.5) * 100;
+ var yaw = (pose.yaw % (2 * 3.14159) + 0.5) * 100;
+
+ var x = ((pose.x / 100) + 0.5) * 100;
+ var y = ((pose.y / 100) + 0.5) * 100;
+
+ var zoom = (((pose.zoom - 1) / 3) + 0.5) * 100;
+
+ self.pitchRollHandlerElem.parentNode.style.right = pitch + "%";
+ self.pitchRollHandlerElem.parentNode.style.top = roll + "%";
+
+ self.yawZoomHandlerElem.parentNode.style.right = yaw + "%";
+ self.yawZoomHandlerElem.parentNode.style.top = zoom + "%";
+
+ self.xyHandlerElem.parentNode.style.right = x + "%";
+ self.xyHandlerElem.parentNode.style.top = y + "%";
+
+ self.updateScene();
+ }
require(["dojo/dom-construct",
"dojo/_base/xhr",
"dojo/dom",
+ "dojo/on",
"dojox/storage",
- "dojox/layout/FloatingPane",
"dojo/store/Memory",
"dojo/store/Observable",
"dijit/tree/ObjectStoreModel",
"dijit/Tree",
"dijit/form/TextBox",
"dijit/form/Button",
- "dijit/form/NumberSpinner",
- "dijit/form/VerticalSlider",
- "dijit/form/VerticalRuleLabels",
- "dijit/form/VerticalRule",
- "dijit/form/HorizontalSlider",
"dojox/mobile/ProgressIndicator",
- "dojo/ready"],
+ "dijit/form/DropDownButton",
+ "dijit/TooltipDialog",
+ "dojo/dnd/Moveable",
+ "dojo/ready",
+ "dojo/dnd/Source"],
function(domConst,
xhr,
dom,
+ on,
storage,
- FloatingPane,
Memory,
Observable,
ObjectStoreModel,
Tree,
TextBox,
Button,
- NumberSpinner,
- VerticalSlider,
- VerticalRuleLabels,
- VerticalRule,
- HorizontalSlider,
ProgressIndicator,
- ready) {
+ DropDownButton,
+ TooltipDialog,
+ Moveable,
+ ready,
+ Source) {
ready(function() {
@@ -78,41 +174,54 @@ function VRMLViewer(element, params) {
// establish our dom
element.appendChild(domConst.toDom('\
- <div class="floatPane">\
- <div style="text-align: right"><div class="server" /></div><button type="button" class="browseButton"></button></div>\
- <div style="height: 100%; overflow: auto" class="fileList"></div>\
- </div>\
<table>\
<tr>\
<td valign="top">\
<div style="position: relative; padding: 0px">\
- <img class="model" style="z-index: -1; min-width: ' + self.pose.width + 'px; min-height: ' + self.pose.height + 'px"></img>\
+ <img class="model" src="img/Tutorial.png" style="z-index: -1; width: ' + self.pose.width + 'px; height: ' + self.pose.height + 'px"></img>\
<div style="z-index: 1; position: absolute; right: 45%; top: 45%">\
<div class="progress"></div>\
</div>\
- <div style="position: absolute; left: 10px; top: 7%; height: 100%">\
- <div class="pitchSlide"></div>\
+ <div style="position: absolute; left: 10px; top: 10px">\
+ <table></tr>\
+ <td class="browseDropDown" style="vertical-align: middle"></td>\
+ <td align="right"><button type="button" class="resetButton"></button></td>\
+ <td class="dragHandler" style="vertical-align: middle; padding-top: 4px;"></td>\
+ </tr></table>\
</div>\
<div style="position: absolute; right: 10px; top: 15%; height: 50%">\
<div class="zoomSlide"></div>\
</div>\
- <div style="position: absolute; left: 7%; top: 10px; width: 100%">\
- <div class="rollSlide"></div>\
+ <div style="position: absolute; right: 55%; top: 48%">\
+ <div class="pitchRollHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\
+ <table>\
+ <tr>\
+ <td><img class="pitchRollHandlerImg" src="img/pitchRoll.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="pitchLabel"></div><div class="rollLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
</div>\
- <div style="position: absolute; left: 7%; bottom: 15px;">\
- <div class="yawSlide"></div>\
+ <div style="position: absolute; right: 45%; top: 48%">\
+ <div class="yawZoomHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\
+ <table>\
+ <tr>\
+ <td><img class="yawZoomHandlerImg" src="img/yawZoom.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="yawLabel"></div><div class="zoomLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
+ </div>\
+ <div style="position: absolute; right: 50%; top: 58%">\
+ <div class="xyHandler" style="font-size: 0.5em; background-color: rgba(255,255,255,0.5); border-radius: 5px; moz-border-radius: 5px;">\
+ <table>\
+ <tr>\
+ <td><img class="xyHandlerImg" src="img/xy.png" width="20px" style="padding: 2px 0px 0px 4px;" /></td>\
+ <td><div class="xLabel"></div><div class="yLabel"></div></td>\
+ </tr>\
+ </table>\
+ </div>\
</div>\
- <table cellspacing="0" style="position: absolute; right: 5px; bottom: 25px">\
- <tr>\
- <td align="right">x: <input type="text" class="xSpinner"></input></td>\
- </tr>\
- <tr>\
- <td align="right">y: <input type="text" class="ySpinner"></input></td>\
- </tr>\
- <tr>\
- <td align="right"><button type="button" class="resetButton"></button></td>\
- </tr>\
- </table>\
</div>\
</td>\
<td valign="top" height="100%">\
@@ -127,28 +236,127 @@ function VRMLViewer(element, params) {
// fetch special dom nodes for content
self.messageBox = dojo.query("div.messages", element)[0];
self.imgElem = dojo.query("img.model", element)[0];
- self.serverBoxElem = dojo.query("div.server", element)[0];
- self.browseButtonElem = dojo.query("button.browseButton", element)[0];
- self.fileListElem = dojo.query("div.fileList", element)[0];
+ self.browseDropDownElem = dojo.query("td.browseDropDown", element)[0];
self.resetButtonElem = dojo.query("button.resetButton", element)[0];
- self.xSpinnerElem = dojo.query("input.xSpinner", element)[0];
- self.ySpinnerElem = dojo.query("input.ySpinner", element)[0];
- self.pitchSlideElem = dojo.query("div.pitchSlide", element)[0];
- self.rollSlideElem = dojo.query("div.rollSlide", element)[0];
- self.yawSlideElem = dojo.query("div.yawSlide", element)[0];
- self.zoomSlideElem = dojo.query("div.zoomSlide", element)[0];
self.progressElem = dojo.query("div.progress", element)[0];
- self.floatPaneElem = dojo.query("div.floatPane", element)[0];
+ self.pitchRollHandlerElem = dojo.query(".pitchRollHandler", element)[0];
+ self.yawZoomHandlerElem = dojo.query(".yawZoomHandler", element)[0];
+ self.xyHandlerElem = dojo.query(".xyHandler", element)[0];
- self.floatPane = new FloatingPane({
- title: "VRML Viewer",
- resizable: true, dockable: false, closable: false,
- style: "position:absolute;top:10;left:10;width:250px;height:300px;z-index: 2",
- id: "floatPane",
- }, self.floatPaneElem);
- self.floatPane.startup();
+ self.pitchRollHandler = new Moveable(self.pitchRollHandlerElem);
+ self.pitchRollHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.pitchRollHandlerImg", mover.node)[0];
+ var pitchLabel = dojo.query("div.pitchLabel", mover.node)[0];
+ var rollLabel = dojo.query("div.rollLabel", mover.node)[0];
+
+ pitchLabel.innerHTML = '';
+ rollLabel.innerHTML = '';
+
+ self.updateScene();
+ }
+ self.pitchRollHandler.onMoving = function(mover) {
+ // mover.node.style.backgroundColor = "rgba(255,255,255,0.5)";
+ // mover.node.style.borderRadius = "5px";
+ // mover.node.style.mozBorderRadius = "5px";
+ // mover.node.style.webkitBorderRadius = "5px";
+ var handlerImg = dojo.query(".pitchRollHandlerImg", mover.node)[0];
+ var pitchLabel = dojo.query(".pitchLabel", mover.node)[0];
+ var rollLabel = dojo.query(".rollLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ // self.pose.pitch = self.pose.pitch % (2 * 3.14159);
+ // self.pose.roll = self.pose.roll % (2 * 3.14159);
+ self.pose.roll = offset.x / self.pose.width - 0.5;
+ self.pose.pitch = offset.y / self.pose.height - 0.5;
+ self.pose.roll *= 2 * 3.14159;
+ self.pose.pitch *= 2 * 3.14159;
+ self.pose.roll = Math.ceil((self.pose.roll) * 10) / 10;
+ self.pose.pitch = Math.ceil((self.pose.pitch) * 10) / 10;
+ pitchLabel.innerHTML = 'Pitch:' + self.pose.pitch;
+ rollLabel.innerHTML = 'Roll:' + self.pose.roll;
+ }
+
+ self.yawZoomHandler = new Moveable(self.yawZoomHandlerElem);
+ self.yawZoomHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0];
+ var yawLabel = dojo.query("div.yawLabel", mover.node)[0];
+ var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0];
+
+ yawLabel.innerHTML = '';
+ zoomLabel.innerHTML = '';
+
+ self.updateScene();
+ }
+ self.yawZoomHandler.onMoving = function(mover) {
+ var handlerImg = dojo.query("img.yawZoomHandlerImg", mover.node)[0];
+ var yawLabel = dojo.query("div.yawLabel", mover.node)[0];
+ var zoomLabel = dojo.query("div.zoomLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ // self.pose.pitch = self.pose.pitch % (2 * 3.14159);
+ // self.pose.roll = self.pose.roll % (2 * 3.14159);
+ self.pose.yaw = (self.pose.width - offset.x) / self.pose.width - 0.5;
+ self.pose.zoom = offset.y / self.pose.height - 0.5;
+ self.pose.yaw *= 2 * 3.14159;
+ self.pose.zoom = self.pose.zoom * 3 + 1;
+ self.pose.zoom = Math.ceil((self.pose.zoom) * 10) / 10;
+ self.pose.yaw = Math.ceil((self.pose.yaw) * 10) / 10;
+ yawLabel.innerHTML = 'Yaw:' + self.pose.yaw;
+ zoomLabel.innerHTML = 'Zoom:' + self.pose.zoom;
+ }
+ self.xyHandler = new Moveable(self.xyHandlerElem);
+ self.xyHandler.onMoveStop = function(mover) {
+ var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0];
+ var xLabel = dojo.query("div.xLabel", mover.node)[0];
+ var yLabel = dojo.query("div.yLabel", mover.node)[0];
+
+ xLabel.innerHTML = '';
+ yLabel.innerHTML = '';
+
+ self.updateScene();
+ }
+ self.xyHandler.onMoving = function(mover) {
+ var handlerImg = dojo.query("img.xyHandlerImg", mover.node)[0];
+ var xLabel = dojo.query("div.xLabel", mover.node)[0];
+ var yLabel = dojo.query("div.yLabel", mover.node)[0];
+ var offset = moverRelativeTo(handlerImg, self.element);
+
+ self.pose.x = offset.x / self.pose.width - 0.5;
+ self.pose.y = offset.y / self.pose.height - 0.5;
+ self.pose.x *= 100;
+ self.pose.y *= 100;
+ self.pose.y = Math.ceil((self.pose.y) * 10) / 10;
+ self.pose.x = Math.ceil((self.pose.x) * 10) / 10;
+ xLabel.innerHTML = 'X:' + self.pose.x;
+ yLabel.innerHTML = 'Y:' + self.pose.y;
+ }
+
+ self.createAvatar = function(item, mode) {
+ if (mode == 'avatar') {
+ // create your avatar if you want
+ var avatar = dojo.create( 'div', { innerHTML: item.data });
+ var avatarPose = dojo.clone(self.pose);
+ avatarPose.width=60;
+ avatarPose.height=60;
+ var avatarImgUrl = urlSuffixForPose(avatarPose);
+ avatar.innerHTML = '<img src=' + self.imageURL + avatarImgUrl + ' /> ';
+ item.srcEcc = "VRMLViewer";
+ item.iconPoseUrl = self.imageURL + avatarImgUrl;
+ item.imageURL = self.imageURL;
+ item.serverURL = self.serverURL;
+ item.pose = avatarPose;
+ return {node: avatar, data: item, type: item.type};
+ }
+ console.log(item, mode);
+ var handler = dojo.create( 'div', { innerHTML: '<img src="img/drag.png" width="20px" />' });
+ return {node: handler, data: item, type: item.type};
+ };
+
+ self.dragHandler = new Source(dojo.query("td.dragHandler", element)[0], {copyOnly: true, creator: self.createAvatar});
+ self.dragHandler.insertNodes(false, [ { } ]);
+
// setup fileStore for tree list
self.fileStore = new Observable(new Memory({
data: [ { id: 'root', name:'3D Models'} ],
@@ -163,12 +371,12 @@ function VRMLViewer(element, params) {
// setup actual tree dijit
self.fileList = new dijit.Tree({
- id: "fileList",
+ id: "fileList" + self.instanceId,
model: self.fileTreeModel,
persist: false,
showRoot: false,
+ style: "height: 200px;",
onClick: function(item){
- // self.messageBox.innerHTML = '<pre>' + item.url + '?width=200&height=150</pre>' + '<img src="' + item.url + '?width=200&height=150" />';
if ('url' in item) {
self.imageURL = item.url;
self.updateScene();
@@ -184,14 +392,8 @@ function VRMLViewer(element, params) {
}
//return {backgroundImage: "url('" + item.url + "?width=16&height=16')"};
- }).placeAt(self.fileListElem);
- //tree.dndController.singular = true;
-
- var savedServerURL = self.localStorage.get("vrmlServer");
- if (savedServerURL) {
- self.serverURL = savedServerURL;
- }
-
+ });
+
self.serverBox = new TextBox({
name: "Server",
value: self.serverURL,
@@ -205,221 +407,57 @@ function VRMLViewer(element, params) {
return false;
}
},
- }, self.serverBoxElem);
-
-
- self.resetButton = new Button({
- label: "Reset",
- onClick: function(){
- self.xSpinner.set('value',0);
- self.ySpinner.set('value',0);
- self.zSpinner.set('value',0);
- self.pitchSlide.attr('value',0);
- self.rollSlide.attr('value',0);
- self.yawSlide.attr('value',0);
- self.zoomSlide.attr('value',1);
-
- self.floatPane.domNode.style.top = "10px";
- self.floatPane.domNode.style.left = "10px";
-// self.floatPane.startup();
- self.floatPane.show();
- }
- }, self.resetButtonElem);
-
- self.xSpinner = new NumberSpinner({
- value: 0,
- smallDelta: 1,
- constraints: { places:0 },
- style: "width:60px",
- onChange: function(value){
- self.pose.x = value;
- self.updateScene();
- }
- }, self.xSpinnerElem );
-
- self.ySpinner = new NumberSpinner({
- value: 0,
- smallDelta: 1,
- constraints: { places:0 },
- style: "width:60px",
- onChange: function(value){
- self.pose.y = value;
- self.updateScene();
- }
- }, self.ySpinnerElem );
-
- self.zSpinner = new NumberSpinner({
- value: 0,
- smallDelta: 1,
- constraints: { places:0 },
- style: "width:60px",
- onChange: function(value){
- self.pose.z = value;
- self.updateScene();
- }
- }, self.zSpinnerElem );
+ });
self.browseButton = new Button({
label: "Browse",
onClick: function(){
self.refreshServer(self.serverBox.get("value"));
}
- }, self.browseButtonElem);
-
- // add zoom slider
- self.zoomSlide = new VerticalSlider({
- minimum: 0.001,
- showButtons: false,
- maximum: 1,
- value: 1,
- intermediateChanges: false,
- style: "height: 90%",
- onChange: function(value){
- self.pose.zoom = Math.ceil(value * 1000) / 1000;
- self.updateScene();
- }
- }, self.zoomSlideElem);
-
- // add pitch slider
- // Create the rules
- // var rulesNode = dojo.create("div", {}, self.pitchSlideElem, "first");
- // var sliderRules = new VerticalRule({
- // container: "leftDecoration",
- // count: 11,
- // style: "width: 5px;"}, rulesNode);
+ });
- // Create the labels
- // var labelsNode = dojo.create(
- // "div", {}, self.pitchSlideElem, "first");
- // var sliderLabels = new VerticalRuleLabels({
- // labels: ["Pitch", ""],
- // container: "rightDecoration",
- // labelStyle: "-webkit-transform: rotate(-90deg); -moz-transform: rotate(-90deg); padding-left: -3px; font-size: 0.75em"
- // }, labelsNode);
+ self.browseDropDownContent = domConst.toDom('<div />');
+ self.browseDropDownContent.appendChild(self.serverBox.domNode);
+ self.browseDropDownContent.appendChild(self.browseButton.domNode);
+ self.browseDropDownContent.appendChild(self.fileList.domNode);
- self.pitchSlide = new VerticalSlider({
- minimum: 0,
- showButtons: false,
- maximum: 2 * 3.14159,
- value: 0,
- intermediateChanges: false,
- style: "height: 90%",
- onChange: function(value){
- self.pose.pitch = Math.ceil(value * 100) / 100;
- self.updateScene();
- }
- }, self.pitchSlideElem);
+ self.browseToolTip = new TooltipDialog({ content:self.browseDropDownContent, style:"max-height:200px"});
+ self.browseDropDown = new DropDownButton({ label: "Files", dropDown: self.browseToolTip });
+ self.browseDropDownElem.appendChild(self.browseDropDown.domNode);
- // add roll slider
- self.rollSlide = new HorizontalSlider({
- minimum: 0,
- showButtons: false,
- maximum: 2 * 3.14159,
- intermediateChanges: false,
- style: "width: 90%",
- onChange: function(value){
- self.pose.roll = Math.ceil(value * 100) / 100;
- self.updateScene();
- }
- }, self.rollSlideElem);
+ self.resetButton = new Button({
+ label: "Reset",
+ onClick: function(){
+ self.pose.x = 0;
+ self.pose.y = 0;
+ self.pose.pitch = 0;
+ self.pose.roll = 0;
+ self.pose.yaw = 0;
+ self.pose.zoom = 1;
+
+ self.xyHandler.node.style.left = 0;
+ self.xyHandler.node.style.top = 0;
+ self.pitchRollHandler.node.style.left = 0;
+ self.pitchRollHandler.node.style.top = 0;
+ self.yawZoomHandler.node.style.left = 0;
+ self.yawZoomHandler.node.style.top = 0;
- // add yaw slider
- self.yawSlide = new HorizontalSlider({
- minimum: 0,
- showButtons: false,
- maximum: 2 * 3.14159,
- intermediateChanges: false,
- style: "width: 90%",
- onChange: function(value){
- self.pose.yaw = Math.ceil(value * 100) / 100;
self.updateScene();
}
- }, self.yawSlideElem);
-
- })
- });
+ }, self.resetButtonElem);
- // privileged public methods
- this.updateScene = function() {
- if (self.imageURL && !self.batchChanges) {
- self.imgElem.src = self.imageURL +
- '?width=' + self.pose.width +
- '&height=' + self.pose.height +
- '&pitch=' + self.pose.pitch +
- '&roll=' + self.pose.roll +
- '&yaw=' + self.pose.yaw +
- '&x=' + self.pose.x +
- '&y=' + self.pose.y +
- '&z=' + self.pose.z +
- '&zoom=' + self.pose.zoom +
- '&autorotate=' + (self.pose.autorotate ? '1' : '0');
- }
- }
+ // do we have parameters for the initial pose?
+ if(self.params)
+ self.setPose(self.params.imageURL, self.params.pose, self.params.serverURL);
- this.refreshServer = function(server) {
- self.serverURL = server;
- self.localStorage.put("vrmlServer", self.serverURL, null);
- self.progressElem.appendChild(self.progress.domNode);
- self.progress.start();
- self.xhr.get({
- // The URL to request
- url: server,
- handleAs:"json",
- headers:{"X-Requested-With":null},
- load: function(result) {
- self.progress.stop();
- for (id in self.fileStore.query) {
- self.fileStore.remove(id);
+ var savedServerURL = self.localStorage.get("vrmlServer");
+ if (savedServerURL && !self.serverURL) {
+ self.serverURL = savedServerURL;
+ self.refreshServer(savedServerURL);
}
- (function fillstore(tree, parentId) {
- for (key in tree) {
- if ('url' in tree[key]) {
- self.fileStore.add({id:parentId+key, name:key, url:self.serverURL + tree[key].path, parent:parentId});
-// self.messageBox.innerHTML += '<pre>' + self.serverURL + tree[key].path + '</pre>';
-// self.messageBox.innerHTML += '<pre>' + tree[key].url + '?width=200&height=150</pre>' + '<img src="' + tree[key].url + '?width=200&height=150" />';
- } else {
- self.fileStore.add({id:parentId+key, name:key, parent:parentId});
- fillstore(tree[key], parentId+key);
- }
- }
- } (result.models, "root", ""));
- }
- });
- }
- this.setPose = function(imageURL, pose, serverURL) {
- if (serverURL && serverURL != self.serverURL) {
- refreshServer(serverURL);
- }
- self.imageURL = imageURL;
- self.pose = pose;
-
- self.batchChanges = true;
-// self.fileList.set('item', imageURL);
- self.xSpinner.set('value',pose.x);
- self.ySpinner.set('value',pose.y);
- self.zSpinner.set('value',pose.z);
- self.pitchSlide.attr('value',pose.pitch);
- self.rollSlide.attr('value',pose.roll);
- self.yawSlide.attr('value',pose.yaw);
- self.zoomSlide.attr('value',pose.zoom);
- self.batchChanges = false;
- updateScene();
- }
+ })
+ });
-/*
- view = "normal";
- // if (params.view == "maximized") {
- // view = "maximized";
- // }
-
- // if (this.view == "maximized") {
- // this.width = Math.min(element.clientWidth - 150, 800);
- // this.height = (this.width * 3) / 4;
- // } else {
- // this.width = Math.min(element.clientWidth - 50, 800);
- // this.height = (this.width * 3) / 4;
- // }
-*/
}
diff --git a/apps/mmi-browser.cpp b/apps/uscxml-browser.cpp
index a6db6ec..afe4e7f 100644
--- a/apps/mmi-browser.cpp
+++ b/apps/uscxml-browser.cpp
@@ -105,16 +105,17 @@ void customTerminate() {
}
void printUsageAndExit() {
- printf("mmi-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
+ printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
printf("Usage\n");
- printf("\tmmi-browser");
+ printf("\tuscxml-browser");
#ifdef BUILD_AS_PLUGINS
- printf(" [-p pluginPath]");
+ printf(" [-d pluginPath]");
#endif
printf(" URL\n");
printf("\n");
printf("Options\n");
printf("\t-v : be verbose\n");
+ printf("\t-pN : port for HTTP server\n");
printf("\n");
exit(1);
}
@@ -133,6 +134,7 @@ int main(int argc, char** argv) {
}
bool verbose = false;
+ size_t port = 8080;
google::InitGoogleLogging(argv[0]);
google::LogToStderr();
@@ -140,14 +142,17 @@ int main(int argc, char** argv) {
opterr = 0;
#endif
int option;
- while ((option = getopt(argc, argv, "vl:p:")) != -1) {
+ while ((option = getopt(argc, argv, "vl:d:p:")) != -1) {
switch(option) {
case 'l':
google::InitGoogleLogging(optarg);
break;
- case 'p':
+ case 'd':
uscxml::Factory::pluginPath = optarg;
break;
+ case 'p':
+ port = strTo<size_t>(optarg);
+ break;
case 'v':
verbose = true;
break;
@@ -163,6 +168,9 @@ int main(int argc, char** argv) {
// std::cout << argv[i] << std::endl;
// std::cout << optind << std::endl;
+ // intialize http server on given port
+ HTTPServer::getInstance(port);
+
LOG(INFO) << "Processing " << argv[optind];
Interpreter interpreter = Interpreter::fromURI(argv[optind]);
if (interpreter) {
diff --git a/apps/mmi-browser.vbs b/apps/uscxml-browser.vbs
index fc8ea9a..fc8ea9a 100644
--- a/apps/mmi-browser.vbs
+++ b/apps/uscxml-browser.vbs
diff --git a/apps/w3c-mmi/MMIEventServlet.cpp b/apps/w3c-mmi/MMIEventServlet.cpp
new file mode 100644
index 0000000..5ee1807
--- /dev/null
+++ b/apps/w3c-mmi/MMIEventServlet.cpp
@@ -0,0 +1,210 @@
+#include "MMIEventServlet.h"
+#include <uscxml/NameSpacingParser.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include "uscxml/Message.h"
+#include <iostream>
+#include <event2/dns.h>
+#include <event2/buffer.h>
+#include <event2/keyvalq_struct.h>
+
+#include <string.h>
+
+#include <io/uri.hpp>
+#include <glog/logging.h>
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#define MMI_HTTP_EVENT_CASE(type) \
+else if (boost::iequals(mmiEvent.getLocalName(), #type)) { \
+ monIter = _monitors.begin(); \
+ while(monIter != _monitors.end()) { \
+ (*monIter)->received(type::fromXML(mmiDoc)); \
+ monIter++; \
+ } \
+}
+
+namespace uscxml {
+
+ using namespace Arabica::DOM;
+
+ MMIEventServlet::MMIEventServlet(const std::string& path) : _path(path) {
+ // register at http server
+ bool success = HTTPServer::registerServlet(_path, this);
+ assert(success);
+ }
+
+ MMIEventServlet::~MMIEventServlet() {
+ HTTPServer* httpServer = HTTPServer::getInstance();
+ httpServer->unregisterServlet(this);
+ }
+
+ void MMIEventServlet::send(const MMIEvent& mmiEvent) {
+ URL url(mmiEvent.target);
+ url.addMonitor(this);
+
+ std::stringstream content;
+ content << mmiEvent.toXML();
+ url.setOutContent(content.str());
+ url.download();
+
+ }
+
+ void MMIEventServlet::httpRecvRequest(const HTTPServer::Request& req) {
+
+ // is this a request from a HTML browser?
+
+
+ NameSpacingParser* parser = NameSpacingParser::fromXML(req.data.compound.at("content").atom);
+ if (!parser) {
+ evhttp_send_error(req.curlReq, 402, NULL);
+ return;
+ }
+
+ Document<std::string> mmiDoc = parser->getDocument();
+ std::cout << mmiDoc.getNamespaceURI() << std::endl;
+ Node<std::string> mmiEvent = mmiDoc.getFirstChild();
+ // get the first element
+ while (mmiEvent && mmiEvent.getNodeType() != Node_base::ELEMENT_NODE) {
+ mmiEvent = mmiEvent.getNextSibling();
+ }
+ // get the contained message
+ if (boost::iequals(mmiEvent.getLocalName(), "mmi")) {
+ mmiEvent = mmiEvent.getFirstChild();
+ while (mmiEvent && mmiEvent.getNodeType() != Node_base::ELEMENT_NODE) {
+ mmiEvent = mmiEvent.getNextSibling();
+ }
+ }
+ std::cout << mmiEvent << std::endl;
+
+ if (!mmiEvent) {
+ evhttp_send_error(req.curlReq, 402, NULL);
+ return;
+ }
+
+ std::set<MMIEventReceiver*>::iterator monIter;
+ if (false) {}
+ MMI_HTTP_EVENT_CASE(NewContextRequest)
+ MMI_HTTP_EVENT_CASE(NewContextResponse)
+ MMI_HTTP_EVENT_CASE(PrepareRequest)
+ MMI_HTTP_EVENT_CASE(PrepareResponse)
+ MMI_HTTP_EVENT_CASE(StartRequest)
+ MMI_HTTP_EVENT_CASE(StartResponse)
+ MMI_HTTP_EVENT_CASE(DoneNotification)
+ MMI_HTTP_EVENT_CASE(CancelRequest)
+ MMI_HTTP_EVENT_CASE(CancelResponse)
+ MMI_HTTP_EVENT_CASE(PauseRequest)
+ MMI_HTTP_EVENT_CASE(PauseResponse)
+ MMI_HTTP_EVENT_CASE(ResumeRequest)
+ MMI_HTTP_EVENT_CASE(ResumeResponse)
+ MMI_HTTP_EVENT_CASE(ExtensionNotification)
+ MMI_HTTP_EVENT_CASE(ClearContextRequest)
+ MMI_HTTP_EVENT_CASE(ClearContextResponse)
+ MMI_HTTP_EVENT_CASE(StatusRequest)
+ MMI_HTTP_EVENT_CASE(StatusResponse)
+ else {
+ LOG(ERROR) << "Unknown MMI Event";
+ evhttp_send_error(req.curlReq, 402, NULL);
+ return;
+ }
+
+ evhttp_send_reply(req.curlReq, 204, NULL, NULL);
+
+#if 0
+ Event reqEvent = req;
+ reqEvent.type = Event::EXTERNAL;
+ bool scxmlStructFound = false;
+
+ if (reqEvent.data.compound["header"].compound.find("Content-Type") != reqEvent.data.compound["header"].compound.end() &&
+ boost::iequals(reqEvent.data.compound["header"].compound["Content-Type"].atom, "application/x-www-form-urlencoded")) {
+ std::stringstream ss(reqEvent.data.compound["content"].atom);
+ std::string term;
+ while(std::getline(ss, term, '&')) {
+ size_t split = term.find_first_of("=");
+ if (split != std::string::npos) {
+ std::string key = evhttp_decode_uri(term.substr(0, split).c_str());
+ std::string value = evhttp_decode_uri(term.substr(split + 1).c_str());
+ if (boost::iequals(key, "_scxmleventname")) {
+ reqEvent.name = value;
+ } else if (boost::iequals(key, "content")) {
+ reqEvent.initContent(value);
+ } else {
+ reqEvent.data.compound[key] = value;
+ reqEvent.params.insert(std::make_pair(key, value));
+ }
+ } else {
+ // this is most likely wrong
+ reqEvent.content = evhttp_decode_uri(term.c_str());
+ }
+ }
+ } else {
+ if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) {
+ // TODO: this looses all other information
+ reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str()));
+ scxmlStructFound = true;
+ }
+ if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) {
+ reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str());
+ }
+ }
+ std::map<std::string, Data>::iterator headerIter = reqEvent.data.compound["header"].compound.begin();
+ while(headerIter != reqEvent.data.compound["header"].compound.end()) {
+ reqEvent.data.compound[headerIter->first] = Data(evhttp_decode_uri(headerIter->second.atom.c_str()), Data::VERBATIM);
+ headerIter++;
+ }
+
+
+ /// test532
+ if (reqEvent.name.length() == 0)
+ reqEvent.name = "http." + req.data.compound.at("type").atom;
+
+ if (!scxmlStructFound) {
+ // get content into event
+ reqEvent.data.compound["content"] = Data(req.content, Data::VERBATIM);
+ }
+
+ evhttp_send_reply(req.curlReq, 200, "OK", NULL);
+#endif
+ }
+
+ void MMIEventServlet::downloadStarted(const URL& url) {}
+
+ void MMIEventServlet::downloadCompleted(const URL& url) {
+ std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin();
+ while(reqIter != _sendRequests.end()) {
+ if (reqIter->second.first == url) {
+ _sendRequests.erase(reqIter);
+ return;
+ }
+ reqIter++;
+ }
+ assert(false);
+ }
+
+ void MMIEventServlet::downloadFailed(const URL& url, int errorCode) {
+
+ std::map<std::string, std::pair<URL, SendRequest> >::iterator reqIter = _sendRequests.begin();
+ while(reqIter != _sendRequests.end()) {
+ if (reqIter->second.first == url) {
+ Event failEvent;
+ failEvent.name = "error.communication";
+// returnEvent(failEvent);
+
+ _sendRequests.erase(reqIter);
+ return;
+ }
+ reqIter++;
+ }
+ assert(false);
+
+ }
+
+
+} \ No newline at end of file
diff --git a/apps/w3c-mmi/MMIEventServlet.h b/apps/w3c-mmi/MMIEventServlet.h
new file mode 100644
index 0000000..10adbc3
--- /dev/null
+++ b/apps/w3c-mmi/MMIEventServlet.h
@@ -0,0 +1,59 @@
+#ifndef MMIEVENTSERVLET_H_92WSR1SU
+#define MMIEVENTSERVLET_H_92WSR1SU
+
+
+#include "uscxml/concurrency/eventqueue/DelayedEventQueue.h"
+#include "uscxml/server/HTTPServer.h"
+#include "uscxml/Interpreter.h"
+#include "uscxml/Factory.h"
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include <event2/http.h>
+#include <event2/http_struct.h>
+
+#include <uscxml/plugins/ioprocessor/modality/MMIMessages.h>
+
+namespace uscxml {
+
+ class MMIEventServlet : public HTTPServlet, public URLMonitor, public MMIEventSender {
+ public:
+ MMIEventServlet(const std::string& path);
+ virtual ~MMIEventServlet();
+
+ void addMonitor(MMIEventReceiver* mmiMonitor) {
+ _monitors.insert(mmiMonitor);
+ }
+ void removeMonitor(MMIEventReceiver* mmiMonitor) {
+ _monitors.erase(mmiMonitor);
+ }
+
+ /// HTTPServlet
+ void httpRecvRequest(const HTTPServer::Request& req);
+ void setURL(const std::string& url) {
+ _url = url;
+ }
+ std::string getURL() { return _url; }
+
+ bool canAdaptPath() {
+ return false;
+ }
+
+ // URLMonitor
+ void downloadStarted(const URL& url);
+ void downloadCompleted(const URL& url);
+ void downloadFailed(const URL& url, int errorCode);
+
+ // MMIEventSender
+ virtual void send(const MMIEvent& mmiEvent);
+
+ protected:
+ std::string _url;
+ std::string _path;
+ std::map<std::string, std::pair<URL, SendRequest> > _sendRequests;
+ std::set<MMIEventReceiver*> _monitors;
+ };
+}
+
+#endif /* end of include guard: MMIEVENTSERVLET_H_92WSR1SU */
diff --git a/apps/w3c-mmi/im/MMISessionManager.cpp b/apps/w3c-mmi/im/MMISessionManager.cpp
new file mode 100644
index 0000000..768a8a1
--- /dev/null
+++ b/apps/w3c-mmi/im/MMISessionManager.cpp
@@ -0,0 +1,257 @@
+#include "MMISessionManager.h"
+#include <uscxml/NameSpacingParser.h>
+#include <uscxml/concurrency/tinythread.h>
+
+#include <io/uri.hpp>
+#include <glog/logging.h>
+
+namespace uscxml {
+
+ using namespace Arabica::DOM;
+
+ MMISessionManager::MMISessionManager(Interpreter interpreter) : _protoInterpreter(interpreter) {
+ bool success = HTTPServer::registerServlet(interpreter.getName(), this);
+ assert(success);
+ _factory = new Factory(Factory::getInstance());
+ _factory->registerIOProcessor(new MMIIOProcessor(this));
+ }
+
+ MMISessionManager::~MMISessionManager() {
+ HTTPServer* httpServer = HTTPServer::getInstance();
+ httpServer->unregisterServlet(this);
+ }
+
+ void MMISessionManager::setupHTMLClient(const HTTPServer::Request& req) {
+ // open template file
+ HTTPServer::Reply reply(req);
+ URL templateURL(_protoInterpreter.getBaseURI().asString() + "/templates/mc-html.html");
+ templateURL.download(true);
+ std::string templateContent = templateURL.getInContent();
+ boost::replace_all(templateContent, "${im.url}", _url);
+ reply.content = templateContent;
+ HTTPServer::reply(reply);
+ }
+
+ void MMISessionManager::httpRecvRequest(const HTTPServer::Request& req) {
+ // is this an initial request from an HTML MC?
+ if (!req.data["query"]["token"] && // no token in query
+ boost::iequals(req.data["type"].atom, "get") && // request type is GET
+ boost::icontains(req.data["header"]["Accept"].atom, "text/html") && // accepts html
+ req.content.length() == 0) { // no content
+ setupHTMLClient(req);
+ return;
+ }
+
+ // is this a comet longpolling request?
+ if (req.data["query"]["token"] &&
+ boost::iequals(req.data["type"].atom, "get")) {
+ std::string token = req.data["query"]["token"].atom;
+ if (_tokens.find(token) != _tokens.end()) {
+ MMISessionManager::CometMMISession* comet = static_cast<MMISessionManager::CometMMISession*>(_tokens[token]);
+ comet->longPoll(req);
+ return;
+ }
+ }
+
+ // assume that there is an mmi event inside
+ NameSpacingParser* parser = NameSpacingParser::fromXML(req.data.compound.at("content").atom);
+ if (!parser) {
+ evhttp_send_error(req.curlReq, 204, NULL);
+ return;
+ }
+
+ Node<std::string> mmiEvent = MMIEvent::getEventNode(parser->getDocument());
+ if (!mmiEvent) {
+ evhttp_send_error(req.curlReq, 204, NULL);
+ return;
+ }
+
+ switch(MMIEvent::getType(mmiEvent)) {
+ case MMIEvent::NEWCONTEXTREQUEST: {
+ received(NewContextRequest::fromXML(mmiEvent), req.data["query"]["token"].atom);
+ evhttp_send_error(req.curlReq, 204, NULL);
+ break;
+ }
+ case MMIEvent::EXTENSIONNOTIFICATION: {
+ received(ExtensionNotification::fromXML(mmiEvent));
+ evhttp_send_error(req.curlReq, 204, NULL);
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Unknown MMI Event";
+ evhttp_send_error(req.curlReq, 204, NULL);
+ break;
+ }
+ }
+ }
+
+ void MMISessionManager::received(const ExtensionNotification& mmiEvent) {
+ assert(_sessions.find(mmiEvent.context) != _sessions.end());
+ _sessions[mmiEvent.context]->_interpreter.receive(mmiEvent);
+ }
+
+ void MMISessionManager::received(const NewContextRequest& mmiEvent, const std::string& token) {
+
+ // copy DOM from prototype instance
+ Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation();
+ Arabica::DOM::Document<std::string> newDOM = domFactory.createDocument("", "", 0);
+ newDOM.appendChild(newDOM.importNode(_protoInterpreter.getDocument().getDocumentElement(), true));
+
+ // instantiate new interpreter and name it after the context
+ std::string contextId = Interpreter::getUUID();
+ Interpreter interpreter = Interpreter::fromDOM(newDOM);
+ interpreter.setFactory(_factory);
+ interpreter.setName(contextId);
+ interpreter.setNameSpaceInfo(_protoInterpreter.getNameSpaceInfo());
+ interpreter.setBaseURI(_protoInterpreter.getBaseURI().asString());
+
+ MMISession* session;
+
+ if (token.length() > 0) {
+ session = new MMISessionManager::CometMMISession();
+ static_cast<MMISessionManager::CometMMISession*>(session)->_token = token;
+ _tokens[token] = session;
+ } else {
+ // todo handle other cases
+ session = new MMISessionManager::CometMMISession();
+ }
+ session->_interpreter = interpreter;
+
+ // save interpreter
+ _sessions[contextId] = session;
+
+ interpreter.start();
+ interpreter.receive(mmiEvent);
+
+ }
+
+ void MMISessionManager::received(const NewContextResponse& mmiEvent) {
+ }
+
+ void MMISessionManager::send(const std::string& name, const SendRequest& req) {
+ assert(_sessions.find(name) != _sessions.end());
+ _sessions[name]->send(req);
+ }
+
+ void MMISessionManager::CometMMISession::send(const SendRequest& req) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ if (!_longPollingReq) {
+ _outQueue.push_back(req);
+ return;
+ }
+
+ if (req.dom) {
+ std::stringstream ss;
+ Node<std::string> mmiEvent = MMIEvent::getEventNode(req.dom);
+ HTTPServer::Reply reply(_longPollingReq);
+
+ switch (MMIEvent::getType(mmiEvent)) {
+ case MMIEvent::NEWCONTEXTRESPONSE: {
+ NewContextResponse response = NewContextResponse::fromXML(mmiEvent);
+ ss << response.toXML();
+ reply.content = ss.str();
+ break;
+ }
+ case MMIEvent::STARTREQUEST: {
+ StartRequest request = StartRequest::fromXML(mmiEvent);
+ std::cout << mmiEvent << std::endl;
+ ss << request.toXML();
+ reply.content = ss.str();
+ break;
+ }
+ default:
+ break;
+ }
+ reply.headers["Content-Type"] = "application/xml";
+ HTTPServer::reply(reply);
+ _longPollingReq = HTTPServer::Request();
+ }
+ }
+
+ void MMISessionManager::CometMMISession::receive(const Arabica::DOM::Node<std::string>& msg) {
+
+ }
+
+ void MMISessionManager::CometMMISession::longPoll(const HTTPServer::Request& req) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(_mutex);
+ if (_longPollingReq)
+ evhttp_send_error(_longPollingReq.curlReq, 204, NULL);
+ _longPollingReq = req;
+ if (!_outQueue.empty()) {
+ send(_outQueue.front());
+ _outQueue.pop_front();
+ }
+ }
+
+ boost::shared_ptr<IOProcessorImpl> MMISessionManager::MMIIOProcessor::create(InterpreterImpl* interpreter) {
+ boost::shared_ptr<IOProcessorImpl> ioProc = boost::shared_ptr<IOProcessorImpl>(new MMISessionManager::MMIIOProcessor(_sessionManager));
+ return ioProc;
+ }
+
+ Data MMISessionManager::MMIIOProcessor::getDataModelVariables() {
+ Data data;
+ return data;
+ }
+
+ void MMISessionManager::MMIIOProcessor::send(const SendRequest& req) {
+ SendRequest reqCopy(req);
+
+ if (req.dom) {
+ Arabica::DOM::Node<std::string> mmiEvent = MMIEvent::getEventNode(req.dom);
+ if (!mmiEvent || !mmiEvent.getNodeType() == Node_base::ELEMENT_NODE)
+ return;
+
+ Arabica::DOM::Element<std::string> mmiElem = Arabica::DOM::Element<std::string>(mmiEvent);
+ switch (MMIEvent::getType(mmiEvent)) {
+ case MMIEvent::STARTRESPONSE:
+ case MMIEvent::PREPARERESPONSE:
+ case MMIEvent::PAUSERESPONSE:
+ case MMIEvent::RESUMERESPONSE:
+ case MMIEvent::CANCELRESPONSE:
+ case MMIEvent::DONENOTIFICATION:
+ case MMIEvent::NEWCONTEXTRESPONSE:
+ case MMIEvent::CLEARCONTEXTRESPONSE:
+ case MMIEvent::STATUSRESPONSE: {
+ // all of the above have a status
+ if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Status")) {
+ mmiElem.setAttributeNS(MMIEvent::nameSpace, "Status", "Success");
+ }
+ }
+ case MMIEvent::PAUSEREQUEST:
+ case MMIEvent::RESUMEREQUEST:
+ case MMIEvent::CANCELREQUEST:
+ case MMIEvent::CLEARCONTEXTREQUEST:
+ case MMIEvent::STATUSREQUEST: {
+ // all of the above have a context
+ if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Context")) {
+ mmiElem.setAttributeNS(MMIEvent::nameSpace, "Context", _interpreter->getName());
+ }
+ }
+ default: {
+ if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Source")) {
+ mmiElem.setAttributeNS(MMIEvent::nameSpace, "Source", _sessionManager->getURL());
+ }
+ if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "Target")) {
+ if (boost::starts_with(_interpreter->getCurrentEvent().name, "mmi.")) {
+ mmiElem.setAttributeNS(MMIEvent::nameSpace, "Target", _interpreter->getCurrentEvent().origin);
+ }
+ }
+ if (!mmiElem.hasAttributeNS(MMIEvent::nameSpace, "RequestID")) {
+ if (boost::starts_with(_interpreter->getCurrentEvent().name, "mmi.")) {
+ mmiElem.setAttributeNS(MMIEvent::nameSpace, "RequestID", _interpreter->getCurrentEvent().sendid);
+ }
+ }
+ }
+ }
+
+ if (MMIEvent::getType(mmiEvent) == MMIEvent::EXTENSIONNOTIFICATION && !mmiElem.hasAttribute("Name") && req.name.length() > 0) {
+ mmiElem.setAttribute("Name", req.name);
+ }
+ // use session mgr to dispatch to session
+
+ _sessionManager->send(_interpreter->getName(), reqCopy);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/apps/w3c-mmi/im/MMISessionManager.h b/apps/w3c-mmi/im/MMISessionManager.h
new file mode 100644
index 0000000..2ca3d0c
--- /dev/null
+++ b/apps/w3c-mmi/im/MMISessionManager.h
@@ -0,0 +1,81 @@
+#ifndef MMISESSIONMANAGER_H_IHDWUAKD
+#define MMISESSIONMANAGER_H_IHDWUAKD
+
+#include <uscxml/Interpreter.h>
+#include <deque>
+#include "../MMIEventServlet.h"
+
+namespace uscxml {
+ class MMISessionManager : public HTTPServlet {
+ public:
+ MMISessionManager(Interpreter interpreter);
+ ~MMISessionManager();
+
+ class MMISession {
+ public:
+ Interpreter _interpreter;
+ tthread::recursive_mutex _mutex;
+ virtual void send(const SendRequest& req) = 0;
+ virtual void receive(const Arabica::DOM::Node<std::string>& msg) = 0;
+ };
+
+ class CometMMISession : public MMISession {
+ public:
+ HTTPServer::Request _request;
+ std::deque<SendRequest> _outQueue;
+ HTTPServer::Request _longPollingReq;
+ std::string _token;
+
+ void send(const SendRequest& req);
+ void receive(const Arabica::DOM::Node<std::string>& msg);
+ void longPoll(const HTTPServer::Request& req);
+ };
+
+ class MMIIOProcessor : public IOProcessorImpl {
+ public:
+ MMIIOProcessor(MMISessionManager* sessionManager) : _sessionManager(sessionManager) {}
+
+ // IOProcessorImpl
+ virtual boost::shared_ptr<IOProcessorImpl> create(InterpreterImpl* interpreter);
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("mmi.event");
+ return names;
+ }
+ virtual Data getDataModelVariables();
+ virtual void send(const SendRequest& req);
+ protected:
+ MMISessionManager* _sessionManager;
+ };
+
+ void send(const std::string& name, const SendRequest& req);
+
+ /// HTTPServlet
+ void httpRecvRequest(const HTTPServer::Request& req);
+ void setURL(const std::string& url) {
+ _url = url;
+ }
+ std::string getURL() { return _url; }
+
+ bool canAdaptPath() {
+ return false;
+ }
+
+ protected:
+ void received(const NewContextRequest& mmiEvent, const std::string& token = "");
+ void received(const NewContextResponse& mmiEvent);
+ void received(const ExtensionNotification& mmiEvent);
+
+ void setupHTMLClient(const HTTPServer::Request& req);
+
+ Interpreter _protoInterpreter;
+ Factory* _factory;
+ DelayedEventQueue _eventQueue;
+ std::map<std::string, MMISession*> _sessions;
+ std::map<std::string, MMISession*> _tokens;
+ std::string _url;
+ };
+}
+
+
+#endif /* end of include guard: MMISESSIONMANAGER_H_IHDWUAKD */
diff --git a/apps/w3c-mmi/im/uscxml-interaction-manager.cpp b/apps/w3c-mmi/im/uscxml-interaction-manager.cpp
new file mode 100644
index 0000000..a7162cc
--- /dev/null
+++ b/apps/w3c-mmi/im/uscxml-interaction-manager.cpp
@@ -0,0 +1,182 @@
+#include "uscxml/config.h"
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+#include "uscxml/concurrency/tinythread.h"
+
+#include "MMISessionManager.h"
+
+#ifdef HAS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAS_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifdef HAS_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef _WIN32
+#include "XGetopt.h"
+#endif
+
+class VerboseMonitor : public uscxml::InterpreterMonitor {
+ void onStableConfiguration(uscxml::Interpreter interpreter) {
+ printConfig(interpreter.getConfiguration());
+ }
+
+ void beforeCompletion(uscxml::Interpreter interpreter) {
+ printConfig(interpreter.getConfiguration());
+ }
+
+ void printConfig(const Arabica::XPath::NodeSet<std::string>& config) {
+ std::string seperator;
+ std::cout << "Config: {";
+ for (int i = 0; i < config.size(); i++) {
+ std::cout << seperator << ATTR(config[i], "id");
+ seperator = ", ";
+ }
+ std::cout << "}" << std::endl;
+ }
+};
+
+
+#ifdef HAS_EXECINFO_H
+void printBacktrace(void** array, int size) {
+ char** messages = backtrace_symbols(array, size);
+ for (int i = 0; i < size && messages != NULL; ++i) {
+ std::cerr << "\t" << messages[i] << std::endl;
+ }
+ std::cerr << std::endl;
+ free(messages);
+}
+
+#ifdef HAS_DLFCN_H
+// see https://gist.github.com/nkuln/2020860
+typedef void (*cxa_throw_type)(void *, void *, void (*) (void *));
+cxa_throw_type orig_cxa_throw = 0;
+
+void load_orig_throw_code() {
+ orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
+}
+
+extern "C"
+void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
+ std::cerr << __FUNCTION__ << " will throw exception from " << std::endl;
+ if (orig_cxa_throw == 0)
+ load_orig_throw_code();
+
+ void *array[50];
+ size_t size = backtrace(array, 50);
+ printBacktrace(array, size);
+ orig_cxa_throw(thrown_exception, pvtinfo, dest);
+}
+#endif
+#endif
+
+
+// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c
+void customTerminate() {
+ static bool tried_throw = false;
+ try {
+ // try once to re-throw currently active exception
+ if (!tried_throw) {
+ throw;
+ tried_throw = true;
+ } else {
+ tried_throw = false;
+ };
+ } catch (const std::exception &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. what(): "
+ << e.what() << std::endl;
+ } catch (const uscxml::Event &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. Event: "
+ << e << std::endl;
+ } catch (...) {
+ std::cerr << __FUNCTION__ << " caught unknown/unhandled exception."
+ << std::endl;
+ }
+
+#ifdef HAS_EXECINFO_H
+ void * array[50];
+ int size = backtrace(array, 50);
+
+ printBacktrace(array, size);
+#endif
+ abort();
+}
+
+void printUsageAndExit() {
+ printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
+ printf("Usage\n");
+ printf("\tuscxml-browser");
+#ifdef BUILD_AS_PLUGINS
+ printf(" [-d pluginPath]");
+#endif
+ printf(" URL\n");
+ printf("\n");
+ printf("Options\n");
+ printf("\t-v : be verbose\n");
+ printf("\t-pN : port for HTTP server\n");
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char** argv) {
+ using namespace uscxml;
+
+ std::set_terminate(customTerminate);
+
+#if defined(HAS_SIGNAL_H) && !defined(WIN32)
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ if (argc < 2) {
+ printUsageAndExit();
+ }
+
+ bool verbose = false;
+ size_t port = 8080;
+ google::InitGoogleLogging(argv[0]);
+ google::LogToStderr();
+
+#ifndef _WIN32
+ opterr = 0;
+#endif
+ int option;
+ while ((option = getopt(argc, argv, "vl:d:p:")) != -1) {
+ switch(option) {
+ case 'l':
+ google::InitGoogleLogging(optarg);
+ break;
+ case 'd':
+ uscxml::Factory::pluginPath = optarg;
+ break;
+ case 'p':
+ port = strTo<size_t>(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case '?':
+ break;
+ default:
+ printUsageAndExit();
+ break;
+ }
+ }
+
+ // intialize http server on given port
+ HTTPServer::getInstance(port);
+
+ LOG(INFO) << "Processing " << argv[optind];
+ Interpreter protoInterpreter = Interpreter::fromURI(argv[optind]);
+ if (protoInterpreter) {
+ MMISessionManager mmiSessionManager(protoInterpreter);
+ while(true)
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(1000));
+ }
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/apps/w3c-mmi/mc/uscxml-modality-component.cpp b/apps/w3c-mmi/mc/uscxml-modality-component.cpp
new file mode 100644
index 0000000..afe4e7f
--- /dev/null
+++ b/apps/w3c-mmi/mc/uscxml-modality-component.cpp
@@ -0,0 +1,191 @@
+#include "uscxml/config.h"
+#include "uscxml/Interpreter.h"
+#include <glog/logging.h>
+
+#ifdef HAS_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAS_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#ifdef HAS_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#ifdef _WIN32
+#include "XGetopt.h"
+#endif
+
+class VerboseMonitor : public uscxml::InterpreterMonitor {
+ void onStableConfiguration(uscxml::Interpreter interpreter) {
+ printConfig(interpreter.getConfiguration());
+ }
+
+ void beforeCompletion(uscxml::Interpreter interpreter) {
+ printConfig(interpreter.getConfiguration());
+ }
+
+ void printConfig(const Arabica::XPath::NodeSet<std::string>& config) {
+ std::string seperator;
+ std::cout << "Config: {";
+ for (int i = 0; i < config.size(); i++) {
+ std::cout << seperator << ATTR(config[i], "id");
+ seperator = ", ";
+ }
+ std::cout << "}" << std::endl;
+ }
+};
+
+
+#ifdef HAS_EXECINFO_H
+void printBacktrace(void** array, int size) {
+ char** messages = backtrace_symbols(array, size);
+ for (int i = 0; i < size && messages != NULL; ++i) {
+ std::cerr << "\t" << messages[i] << std::endl;
+ }
+ std::cerr << std::endl;
+ free(messages);
+}
+
+#ifdef HAS_DLFCN_H
+// see https://gist.github.com/nkuln/2020860
+typedef void (*cxa_throw_type)(void *, void *, void (*) (void *));
+cxa_throw_type orig_cxa_throw = 0;
+
+void load_orig_throw_code() {
+ orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
+}
+
+extern "C"
+void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
+ std::cerr << __FUNCTION__ << " will throw exception from " << std::endl;
+ if (orig_cxa_throw == 0)
+ load_orig_throw_code();
+
+ void *array[50];
+ size_t size = backtrace(array, 50);
+ printBacktrace(array, size);
+ orig_cxa_throw(thrown_exception, pvtinfo, dest);
+}
+#endif
+#endif
+
+
+// see http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c
+void customTerminate() {
+ static bool tried_throw = false;
+ try {
+ // try once to re-throw currently active exception
+ if (!tried_throw) {
+ throw;
+ tried_throw = true;
+ } else {
+ tried_throw = false;
+ };
+ } catch (const std::exception &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. what(): "
+ << e.what() << std::endl;
+ } catch (const uscxml::Event &e) {
+ std::cerr << __FUNCTION__ << " caught unhandled exception. Event: "
+ << e << std::endl;
+ } catch (...) {
+ std::cerr << __FUNCTION__ << " caught unknown/unhandled exception."
+ << std::endl;
+ }
+
+#ifdef HAS_EXECINFO_H
+ void * array[50];
+ int size = backtrace(array, 50);
+
+ printBacktrace(array, size);
+#endif
+ abort();
+}
+
+void printUsageAndExit() {
+ printf("uscxml-browser version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n");
+ printf("Usage\n");
+ printf("\tuscxml-browser");
+#ifdef BUILD_AS_PLUGINS
+ printf(" [-d pluginPath]");
+#endif
+ printf(" URL\n");
+ printf("\n");
+ printf("Options\n");
+ printf("\t-v : be verbose\n");
+ printf("\t-pN : port for HTTP server\n");
+ printf("\n");
+ exit(1);
+}
+
+int main(int argc, char** argv) {
+ using namespace uscxml;
+
+ std::set_terminate(customTerminate);
+
+#if defined(HAS_SIGNAL_H) && !defined(WIN32)
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ if (argc < 2) {
+ printUsageAndExit();
+ }
+
+ bool verbose = false;
+ size_t port = 8080;
+ google::InitGoogleLogging(argv[0]);
+ google::LogToStderr();
+
+#ifndef _WIN32
+ opterr = 0;
+#endif
+ int option;
+ while ((option = getopt(argc, argv, "vl:d:p:")) != -1) {
+ switch(option) {
+ case 'l':
+ google::InitGoogleLogging(optarg);
+ break;
+ case 'd':
+ uscxml::Factory::pluginPath = optarg;
+ break;
+ case 'p':
+ port = strTo<size_t>(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case '?':
+ break;
+ default:
+ printUsageAndExit();
+ break;
+ }
+ }
+
+// for (int i = 0; i < argc; i++)
+// std::cout << argv[i] << std::endl;
+// std::cout << optind << std::endl;
+
+ // intialize http server on given port
+ HTTPServer::getInstance(port);
+
+ LOG(INFO) << "Processing " << argv[optind];
+ Interpreter interpreter = Interpreter::fromURI(argv[optind]);
+ if (interpreter) {
+ interpreter.setCmdLineOptions(argc, argv);
+// interpreter->setCapabilities(Interpreter::CAN_NOTHING);
+// interpreter->setCapabilities(Interpreter::CAN_BASIC_HTTP | Interpreter::CAN_GENERIC_HTTP);
+
+ if (verbose) {
+ VerboseMonitor* vm = new VerboseMonitor();
+ interpreter.addMonitor(vm);
+ }
+
+ interpreter.start();
+ while(interpreter.runOnMainThread(25));
+ }
+
+ return EXIT_SUCCESS;
+} \ No newline at end of file