From 15e3ec42ce60b9c4636fcaea489716d6fd57dcd2 Mon Sep 17 00:00:00 2001
From: alfongj
Date: Thu, 11 Aug 2011 21:33:48 +0100
Subject: [PATCH] Closes #39, closes #40, closes #45, updates #31, #33, #35,
#46 & solved bugs
---
.../math/games/builder/fig/FigFontManager.as | 6 +
.../games/builder/fig/TreeGridFigWriter.as | 1 +
.../builder/io/ExtensiveFormXMLReader.as | 323 ------------
.../lse/math/games/builder/io/FileManager.as | 57 +-
...tensiveFormXMLWriter.as => XMLExporter.as} | 252 ++++-----
.../lse/math/games/builder/io/XMLImporter.as | 488 ++++++++++++++++++
.../math/games/builder/model/ExtensiveForm.as | 73 ++-
.../src/lse/math/games/builder/model/Iset.as | 15 +-
.../src/lse/math/games/builder/model/Node.as | 3 +-
...{ActionHandler.as => TreeActionHandler.as} | 331 ++++++------
.../builder/presenter/TreeGridPresenter.as | 60 ++-
.../games/builder/settings/FileSettings.as | 123 +++++
.../lse/math/games/builder/settings/SCodes.as | 102 +++-
.../math/games/builder/settings/Settings.mxml | 284 ++++++++--
.../games/builder/settings/UserSettings.as | 61 ++-
.../src/lse/math/games/builder/view/Main.mxml | 217 +++++---
.../math/games/builder/view/OutputWindow.mxml | 14 +-
.../games/builder/viewmodel/MatrixInput.as | 333 ------------
.../games/builder/viewmodel/MatrixPainter.as | 2 +-
.../math/games/builder/viewmodel/TreeGrid.as | 71 ++-
.../viewmodel/TreeGridActionFactory.as | 24 +-
.../builder/viewmodel/TreeGridPainter.as | 18 +-
.../builder/viewmodel/TreeGridSetPainter.as | 36 +-
.../viewmodel/action/AddChildAction.as | 11 +-
.../viewmodel/action/ChangePlayerAction.as | 20 +-
.../builder/viewmodel/action/CutAction.as | 8 +-
.../builder/viewmodel/action/DeleteAction.as | 8 +-
.../viewmodel/action/DissolveAction.as | 10 +-
.../viewmodel/action/LabelChangeAction.as | 6 +-
.../viewmodel/action/MakeChanceAction.as | 20 +-
.../builder/viewmodel/action/MergeAction.as | 4 +-
.../viewmodel/action/PayChangeAction.as | 6 +-
.../viewmodel/action/PerfectRecallAction.as | 2 +
.../builder/viewmodel/action/RotateAction.as | 32 +-
gui-builder/src/util/Log.as | 5 +-
gui-builder/test/src/TestSuite.as | 2 +
web-service/war/builder/index.jsp | 41 +-
37 files changed, 1750 insertions(+), 1319 deletions(-)
delete mode 100644 gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLReader.as
rename gui-builder/src/lse/math/games/builder/io/{ExtensiveFormXMLWriter.as => XMLExporter.as} (59%)
create mode 100644 gui-builder/src/lse/math/games/builder/io/XMLImporter.as
rename gui-builder/src/lse/math/games/builder/presenter/{ActionHandler.as => TreeActionHandler.as} (76%)
create mode 100644 gui-builder/src/lse/math/games/builder/settings/FileSettings.as
delete mode 100644 gui-builder/src/lse/math/games/builder/viewmodel/MatrixInput.as
diff --git a/gui-builder/src/lse/math/games/builder/fig/FigFontManager.as b/gui-builder/src/lse/math/games/builder/fig/FigFontManager.as
index f2c067c..fb10208 100644
--- a/gui-builder/src/lse/math/games/builder/fig/FigFontManager.as
+++ b/gui-builder/src/lse/math/games/builder/fig/FigFontManager.as
@@ -168,6 +168,12 @@ package lse.math.games.builder.fig
return baseFonts;
}
+ /** Returns true if the font is available */
+ public static function isFontAvailable(fontName:String):Boolean
+ {
+ return (_fontFamilyEnums.hasOwnProperty(fontName));
+ }
+
/** Returns a font's code in the enum of fonts of the fig*/
public static function figEnumValue(fontFamily:String, weight:String, posture:String):int
{
diff --git a/gui-builder/src/lse/math/games/builder/fig/TreeGridFigWriter.as b/gui-builder/src/lse/math/games/builder/fig/TreeGridFigWriter.as
index 36ce331..3df6afd 100644
--- a/gui-builder/src/lse/math/games/builder/fig/TreeGridFigWriter.as
+++ b/gui-builder/src/lse/math/games/builder/fig/TreeGridFigWriter.as
@@ -62,6 +62,7 @@ package lse.math.games.builder.fig
var graphics:FigGraphics = new FigGraphics(buffer);
graphics.addColor(grid.player1Color);
graphics.addColor(grid.player2Color);
+ //TODO: 3PL
//Saves onto the file the results of all the painter operations that form the tree
painter.paint(graphics, width, height);
diff --git a/gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLReader.as b/gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLReader.as
deleted file mode 100644
index 5bab196..0000000
--- a/gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLReader.as
+++ /dev/null
@@ -1,323 +0,0 @@
-package lse.math.games.builder.io
-{
- import flash.utils.Dictionary;
-
- import lse.math.games.builder.model.ExtensiveForm;
- import lse.math.games.builder.model.Iset;
- import lse.math.games.builder.model.Move;
- import lse.math.games.builder.model.Node;
- import lse.math.games.builder.model.Outcome;
- import lse.math.games.builder.model.Player;
- import lse.math.games.builder.model.Rational;
-
- import mx.controls.Alert;
-
- /**
- * TODO: This class needs to be adapted to the new standard format in
- * https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B331281Yuj61ZTM2Y2M0YzMtODQyNi00NGVmLWI1MjctMDY0Mzc2ZGM2MjFj&hl=en_US
- *
- * Also, a new NormalFormXMLReader and NormalFormXMLWriter will most probably be needed after the normalform importing is worked out
- *
- * @author Mark Egesdal
- */
- public class ExtensiveFormXMLReader
- {
- private var nodes:Dictionary;
- private var isets:Dictionary;
- private var isetObjToId:Dictionary;
- private var singletons:Vector.;
- private var moves:Dictionary;
- private var players:Dictionary;
-
- private var xml:XML = null;
- private var tree:ExtensiveForm = null;
-
- public function ExtensiveFormXMLReader(xml:XML)
- {
- this.xml = xml;
- }
-
- public function load(tree:ExtensiveForm):ExtensiveForm
- {
- this.tree = tree;
- tree.clearTree();
-
- nodes = new Dictionary();
- isets = new Dictionary();
- isetObjToId = new Dictionary();
- singletons = new Vector.();
- moves = new Dictionary();
- players = new Dictionary();
-
- for each(var child:XML in xml.children()) {
- if (child.name() == "iset") {
- processIset(child);
- } else if (child.name() == "node") {
- processNode(child, null);
- } else if (child.name() == "outcome") {
- processOutcome(child, null);
- } else {
- trace("Ignoring unknown element:\r\n" + child);
- }
- }
-
- var iset:Iset = null;
- for (var isetId:String in isets) {
- iset = isets[isetId] as Iset;
- if (iset != tree.root.iset) {
- tree.addIset(iset);
- }
- }
- for each (iset in singletons) {
- if (iset != tree.root.iset) {
- tree.addIset(iset);
- }
- }
-
- hookupAndVerifyMoves();
-
- return tree;
- }
-
- //TODO: there has got to be a more efficient algorithm
- private function hookupAndVerifyMoves():void
- {
- for (var iset:Iset = tree.root.iset; iset != null; iset = iset.nextIset) {
-
- iset.sort();
-
- //for each child of the first node, hook up move
- var baseline:Node = iset.firstNode;
- for (var baselineChild:Node = baseline.firstChild, childIdx:int = 0; baselineChild != null; baselineChild = baselineChild.sibling, ++childIdx)
- {
- iset.assignMove(baselineChild.reachedby);
-
- // make sure all the rest of the nodes have the child with the same move
- // TODO: it does not necessarily need to be at the same index
- for (var baselineMate:Node = baseline.nextInIset; baselineMate != null; baselineMate = baselineMate.nextInIset)
- {
- var mateChild:Node = baselineMate.firstChild;
- for (var i:int = 0; i < childIdx; ++i) {
- mateChild = mateChild.sibling;
- }
- if (mateChild.reachedby != baselineChild.reachedby) {
- if (mateChild.reachedby == null) {
- throw new Error("node does not contain an incoming move");
- } else {
- throw new Error("Iset " + iset.idx + " is inconsistent for node " + baselineMate.number /*+ " at " + baselineMate.setIdx*/ + " for child " + mateChild.number + " at " + childIdx + " with move " + mateChild.reachedby);
- }
- }
- }
- }
- }
- }
-
- private function getPlayer(playerId:String):Player
- {
- if (playerId == Player.CHANCE_NAME) {
- return Player.CHANCE;
- }
-
- var player:Player = players[playerId];
- if (player == null) {
- player = new Player(playerId, tree);
- players[playerId] = player;
- }
- return player;
- }
-
- private function processIset(elem:XML):void
- {
- var id:String = elem.@id;
- var iset:Iset = isets[id];
-
- if (iset == null) {
- var player:Player = (elem.@player != undefined) ? getPlayer(elem.@player) : Player.CHANCE;
- iset = new Iset(player);
- isets[id] = iset;
- isetObjToId[iset] = id;
- }
-
- for each (var child:XML in elem.children())
- {
- if (child.name() == "node") {
- processNode(child, null);
- } else {
- trace("Ignoring unknown element:\r\n" + child);
- }
- }
- }
-
- private function processNode(elem:XML, parentNode:Node):void
- {
- //init
- var node:Node = null;
- if (elem.@id != undefined)
- {
- var id:String = elem.@id;
- node = nodes[id];
-
- if (node == null) {
- trace("XMLReader: creating new node " + id);
- node = tree.createNode();
- nodes[id] = node;
- } else {
- trace("XMLReader: processing previously created node " + id);
-
- }
- } else {
- node = tree.createNode();
- }
-
- //assign parent
- if (parentNode == null && elem.@parent != undefined)
- {
- var parentId:String = elem.@parent;
- parentNode = nodes[parentId];
-
- if (parentNode == null) {
- parentNode = tree.createNode();
- nodes[parentId] = parentNode;
- }
- }
- if (parentNode != null) {
- parentNode.addChild(node);
- } else {
- tree.root = node;
- }
-
- // process iset
- var isetId:String = null;
- if (elem.parent() != null && elem.parent().name() == "iset") {
- isetId = elem.parent().@id;
- if (elem.@iset != undefined) trace("Warning: @iset attribute is set for a node nested in an iset tag. Ignored.");
- } else if (elem.@iset != undefined) {
- isetId = elem.@iset;
- }
-
- var iset:Iset = null;
- var player:Player = (elem.@player != undefined) ? getPlayer(elem.@player) : Player.CHANCE;
- if (isetId == null) {
- iset = new Iset(player);
- singletons.push(iset); // root is already taken care of
- } else {
- //look it up in the map, if it doesn't exist create it and add it
- iset = isets[isetId];
- if (iset == null) {
- iset = new Iset(player);
- isets[isetId] = iset;
- isetObjToId[iset] = isetId;
- } else {
- if (player != Player.CHANCE) {
- if (iset.player != Player.CHANCE && player != iset.player) {
- trace("Warning: @player attribute conflicts with earlier iset player assignment. Ignored.");
- }
- while (iset.player != player) {
- iset.changePlayer(tree.firstPlayer);
- }
- }
- }
- }
- iset.insertNode(node);
-
- // set up the moves
- processMove(elem, node, parentNode);
-/* if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parentNode != null && parentNode.iset != null) ? String(parentNode.iset.idx) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
-
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- node.reachedby = move;
- } else if (parentNode != null) {
- // assume this comes from a chance node with a probability of zero
- node.reachedby = new Move();
- }
-
- if (elem.@prob != undefined && node.reachedby != null) {
- node.reachedby.prob = Rational.parse(elem.@prob);
- }
-*/
- for each (var child:XML in elem.children()) {
- if (child.name() == "node") {
- processNode(child, node);
- } else if (child.name() == "outcome") {
- processOutcome(child, node);
- } /*else {
- trace("Ignoring unknown element:\r\n" + child);
- }*/
- }
- }
-
- private function processOutcome(elem:XML, parent:Node):void
- {
- // Create wrapping node
- // get parent from dictionary... if it doesn't exist then the outcome must be the root
- var wrapNode:Node = parent != null ? parent.newChild() : tree.createNode();
- if (parent == null) {
- tree.root = wrapNode;
- }
-
- // set up the moves
- processMove(elem, wrapNode, parent);
- /* if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parent != null && parent.iset != null) ? String(parent.iset.idx) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- wrapNode.reachedby = move;
- }
-
- if (elem.@prob != undefined && wrapNode.reachedby != null) {
- wrapNode.reachedby.prob = Rational.parse(elem.@prob);
- }*/
-
- var outcome:Outcome = wrapNode.makeTerminal();
- for each (var child:XML in elem.children()) {
- if (child.name() == "payoff") {
- var playerId:String = child.@player;
- var payoff:Rational = Rational.parse(child.@value);
-
- var player:Player = players[playerId];
- if (player == null) {
- player = new Player(playerId, tree);
- players[playerId] = player;
- }
- outcome.setPay(player, payoff);
- } /*else {
- trace("Ignoring unknown element:\r\n" + child);
- }*/
- }
- }
-
- private function processMove(elem:XML, node:Node, parent:Node):void
- {
- if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parent != null && parent.iset != null) ? String(isetObjToId[parent.iset]) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- node.reachedby = move;
- } else if (parent != null) {
- // assume this comes from a chance node with a probability of zero
- node.reachedby = new Move();
- }
-
- if (elem.@prob != undefined && node.reachedby != null) {
- node.reachedby.prob = Rational.parse(elem.@prob);
- }
- }
- }
-}
diff --git a/gui-builder/src/lse/math/games/builder/io/FileManager.as b/gui-builder/src/lse/math/games/builder/io/FileManager.as
index d2cc62b..8bfe07f 100644
--- a/gui-builder/src/lse/math/games/builder/io/FileManager.as
+++ b/gui-builder/src/lse/math/games/builder/io/FileManager.as
@@ -10,6 +10,7 @@ package lse.math.games.builder.io
import flash.utils.setTimeout;
import lse.math.games.builder.presenter.TreeGridPresenter;
+ import lse.math.games.builder.settings.FileSettings;
import lse.math.games.builder.settings.UserSettings;
import util.Log;
@@ -40,7 +41,7 @@ package lse.math.games.builder.io
private var controller:TreeGridPresenter;
private var settings:UserSettings = UserSettings.instance;
- private var treeStorage:SharedObject;
+ private var cookies:SharedObject;
private var log:Log = Log.instance;
@@ -52,10 +53,10 @@ package lse.math.games.builder.io
setTimeout(autosave, AUTOSAVE_INTERVAL);
//Look if there is an autosave, and load it if so
- treeStorage = SharedObject.getLocal( "autosave", "/" );
- if(treeStorage != null && treeStorage.data["treeXML"] !=null)
+ cookies = SharedObject.getLocal( "autosave", "/" );
+ if(cookies != null && cookies.data[""] !=null)
{
- setTimeout(askLoadTree, 3000); //Leave 3 seconds for the creation of canvas
+ setTimeout(askLoadFile, 3000); //Leave 3 seconds for the creation of canvas
}
//Add callback for the askBeforeQuit function
@@ -98,10 +99,10 @@ package lse.math.games.builder.io
if(settings.cookiesStorable /*&& autosave_on */)
{
- if(treeStorage == null)
- treeStorage = SharedObject.getLocal( "autosave", "/" );
+ if(cookies == null)
+ cookies = SharedObject.getLocal( "autosave", "/" );
- treeStorage.setProperty("treeXML", value);
+ cookies.setProperty("", value);
unsavedChanges = false;
}
}
@@ -136,37 +137,38 @@ package lse.math.games.builder.io
* It returns true if there are unsaved changes, false if there aren't.
*/
private function askBeforeQuit():Boolean {
-
- if(treeStorage != null)
- treeStorage.clear();
+ if(cookies != null)
+ cookies.clear();
return _unsavedChanges;
}
//Asks if to load a saved tree
- private function askLoadTree():void {
- PromptTwoButtons.show(loadAutoSavedTree, "There is " +
- "an auto-saved tree from last execution. Would you like to load it?")
+ private function askLoadFile():void {
+ PromptTwoButtons.show(loadAutoSavedFile, "There is " +
+ "an auto-saved file from last execution. Would you like to load it?")
}
/* Loads a tree saved via autosave */
- private function loadAutoSavedTree():void {
+ private function loadAutoSavedFile():void {
if(PromptTwoButtons.buttonPressed == PromptTwoButtons.OK)
{
- backupXML = treeStorage.data["treeXML"] as XML;
- controller.loadTreeFromXML(_backupXML);
+ backupXML = cookies.data["autosave"] as XML;
+ //TODO #33 check the type of thing stored, call correspondant function
+ controller.loadFromXML(_backupXML);
} else {
clear();
}
}
- /** Resets the filename */
+ /** Resets the filename, backup & cookies */
public function clear():void {
filename = "Untitled";
backupXML = null;
- treeStorage = SharedObject.getLocal( "autosave", "/" );
- if(treeStorage!=null)
- treeStorage.clear();
+ FileSettings.instance.clear();
+ cookies = SharedObject.getLocal( "autosave", "/" );
+ if(cookies!=null)
+ cookies.clear();
}
/*
@@ -227,16 +229,16 @@ package lse.math.games.builder.io
/**
* Opens a dialog for saving the tree in xml format
*/
- public function saveXML(treeXML:XML):void
+ public function saveXML(xml:XML):void
{
- backupXML = treeXML;
+ backupXML = xml;
fr = new FileReference();
fr.addEventListener(Event.COMPLETE, onSaveComplete);
fr.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
- fr.save(treeXML.toXMLString(), filename+".xml");
+ fr.save(xml.toXMLString(), filename+".xml");
}
/**
@@ -295,8 +297,9 @@ package lse.math.games.builder.io
//read the bytes of the file as a string
var text:String = fr.data.readUTFBytes(fr.data.bytesAvailable);
- var xml:XML = new XML(text);
- controller.loadTreeFromXML(xml);
+ var xml:XML = new XML(text);
+
+ controller.loadFromXML(xml);
backupXML = xml;
filename = getNameFromFile(fr);
@@ -317,8 +320,8 @@ package lse.math.games.builder.io
unsavedChanges = false;
//As the user has its tree saved as a .xml, he wouldn't like to have it also as a SharedObject
- if(treeStorage != null)
- treeStorage.clear();
+ if(cookies != null)
+ cookies.clear();
fr = null;
}
diff --git a/gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLWriter.as b/gui-builder/src/lse/math/games/builder/io/XMLExporter.as
similarity index 59%
rename from gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLWriter.as
rename to gui-builder/src/lse/math/games/builder/io/XMLExporter.as
index 67f84db..a4ba00f 100644
--- a/gui-builder/src/lse/math/games/builder/io/ExtensiveFormXMLWriter.as
+++ b/gui-builder/src/lse/math/games/builder/io/XMLExporter.as
@@ -1,119 +1,135 @@
-package lse.math.games.builder.io
-{
- import lse.math.games.builder.model.ExtensiveForm;
- import lse.math.games.builder.model.Iset;
- import lse.math.games.builder.model.Node;
- import lse.math.games.builder.model.Player;
-
- /**
- * This class needs to be adapted to follow the new XML standard format in:
- * https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0B331281Yuj61ZTM2Y2M0YzMtODQyNi00NGVmLWI1MjctMDY0Mzc2ZGM2MjFj&hl=en_US
- *
- * @author Mark Egesdal
- */
- public class ExtensiveFormXMLWriter
- {
- public function write(tree:ExtensiveForm):XML
- {
- var xml:XML = ;
-
- var isets:Vector. = new Vector.();
- xml.appendChild(getNodeElem(tree.root, isets, tree));
-
- /* Suspending writing Ahmad's way... perhaps I can be more clever with how I order the isets, but this way
- * seems to lose the left-to-right ordering of the tree
- for (var h:Iset = tree.root.iset; h != null; h = h.nextIset) {
- xml.appendChild(getIsetElem(h, tree));
- }*/
- return xml;
- }
-
- private function getNodeElem(n:Node, isets:Vector., tree:ExtensiveForm):XML
- {
- var nodeElem:XML;
- if (n.outcome == null) {
- nodeElem = ;
-
- if (n.iset != null && n.iset.numNodes > 1) {
- nodeElem.@iset = n.iset.idx;
- }
- if (isets.indexOf(n.iset) < 0 && n.iset.player != Player.CHANCE) {
- nodeElem.@player = n.iset.player.name;
- isets.push(n.iset);
- }
-
- for (var child:Node = n.firstChild; child != null; child = child.sibling) {
- nodeElem.appendChild(getNodeElem(child, isets, tree));
- }
- } else {
- nodeElem = ;
-
- for (var player:Player = tree.firstPlayer; player != null; player = player.nextPlayer)
- {
- var payoffElem:XML = ;
- payoffElem.@player = player.name;
- payoffElem.@value = n.outcome.pay(player); // TODO: write out as fraction?
- nodeElem.appendChild(payoffElem);
- }
- }
-
- if (n.reachedby != null && n.parent.iset.player == Player.CHANCE) {
- nodeElem.@prob = n.reachedby.label; // TODO: write out as a fraction
- } else if (n.reachedby != null) {
- nodeElem.@move = n.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
- }
- return nodeElem;
- }
-
- private function getIsetElem(h:Iset, tree:ExtensiveForm):XML
- {
- var isetElem:XML;
- if (h.numNodes > 1) {
- isetElem =
- isetElem.@id = h.idx;
- if (h.player != Player.CHANCE) isetElem.@player = h.player.name;
-
- for (var n:Node = h.firstNode; n != null; n = n.nextInIset) {
- isetElem.appendChild(getNodeElemForIset(n, tree));
- }
- } else {
- isetElem = getNodeElemForIset(h.firstNode, tree);
- if (h.player != Player.CHANCE) isetElem.@player = h.player.name;
- }
- return isetElem;
- }
-
- private function getNodeElemForIset(node:Node, tree:ExtensiveForm):XML
- {
- var nodeElem:XML = ;
- nodeElem.@id = node.number;
- if (node.parent != null) {
- nodeElem.@parent = node.parent.number;
- }
- if (node.reachedby != null && node.reachedby.isChance) {
- nodeElem.@prob = node.reachedby.prob; // TODO: write out as a fraction
- } else if (node.reachedby != null) {
- nodeElem.@move = node.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
- }
-
- for (var child:Node = node.firstChild; child != null; child = child.sibling) {
- if (child.outcome != null) {
- var outcomeElem:XML = ;
- if (child.reachedby != null && child.reachedby.isChance) {
- outcomeElem.@prob = child.reachedby.prob; // TODO: write out as a fraction
- } else {
- outcomeElem.@move = child.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
- }
- for (var player:Player = tree.firstPlayer; player != null; player = player.nextPlayer) {
- var payoffElem:XML = ;
- payoffElem.@player = player.name;
- payoffElem.@value = child.outcome.pay(player); // TODO: write out as fraction?
- outcomeElem.appendChild(payoffElem);
- }
- nodeElem.appendChild(outcomeElem);
- }
- }
- return nodeElem;
- }
- }
+package lse.math.games.builder.io
+{
+ import lse.math.games.builder.model.ExtensiveForm;
+ import lse.math.games.builder.model.Iset;
+ import lse.math.games.builder.model.Node;
+ import lse.math.games.builder.model.Player;
+
+ import util.Log;
+
+ /**
+ * TODO: Document
+ *
+ * @author Mark Egesdal
+ */
+ //TODO: Do something with gameDescription info
+ //TODO: In the future, write node and iset names & maybe? payoffs in non-outcomes
+ //TODO #33 writeMatrix
+ //TODO #33 write players first, when they are in the spec
+ public class XMLExporter
+ {
+ private var log:Log = Log.instance;
+
+
+
+ public function writeTree(tree:ExtensiveForm):XML
+ {
+ var xml:XML =
+
+
+
+
+ ;
+
+ //TODO loadSettings
+
+ xml.extensiveForm.appendChild(getNodeElem(tree.root, tree));
+
+ return xml;
+ }
+
+ private function getNodeElem(n:Node, tree:ExtensiveForm):XML
+ {
+ var nodeElem:XML;
+ if (!n.isLeaf) {
+ nodeElem = ;
+
+ if (n.iset != null)
+ {
+ if(n.iset.numNodes > 1)
+ nodeElem.@iset = n.iset.idx;
+
+ if (n.iset.player != Player.CHANCE) {
+ nodeElem.@player = n.iset.player.name;
+ }
+ }
+
+ for (var child:Node = n.firstChild; child != null; child = child.sibling) {
+ nodeElem.appendChild(getNodeElem(child, tree));
+ }
+ } else {
+ nodeElem = ;
+
+ if(n.outcome != null)
+ for (var player:Player = tree.firstPlayer; player != null; player = player.nextPlayer)
+ {
+ var payoffElem:XML = ;
+ payoffElem.@player = player.name;
+ payoffElem.@value = n.outcome.pay(player).toString();
+ nodeElem.appendChild(payoffElem);
+ }
+ }
+
+ if (n.reachedby != null)
+ {
+ if(n.parent.iset.player == Player.CHANCE) {
+ nodeElem.@prob = n.reachedby.label;
+ } else {
+ nodeElem.@move = n.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
+ }
+ }
+ return nodeElem;
+ }
+
+ private function getIsetElem(h:Iset, tree:ExtensiveForm):XML
+ {
+ var isetElem:XML;
+ if (h.numNodes > 1) {
+ isetElem =
+ isetElem.@id = h.idx;
+ if (h.player != Player.CHANCE) isetElem.@player = h.player.name;
+
+ for (var n:Node = h.firstNode; n != null; n = n.nextInIset) {
+ isetElem.appendChild(getNodeElemForIset(n, tree));
+ }
+ } else {
+ isetElem = getNodeElemForIset(h.firstNode, tree);
+ if (h.player != Player.CHANCE) isetElem.@player = h.player.name;
+ }
+ return isetElem;
+ }
+
+ private function getNodeElemForIset(node:Node, tree:ExtensiveForm):XML
+ {
+ var nodeElem:XML = ;
+ nodeElem.@id = node.number;
+ if (node.parent != null) {
+ nodeElem.@parent = node.parent.number;
+ }
+ if (node.reachedby != null && node.reachedby.isChance) {
+ nodeElem.@prob = node.reachedby.prob; // TODO: write out as a fraction
+ } else if (node.reachedby != null) {
+ nodeElem.@move = node.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
+ }
+
+ for (var child:Node = node.firstChild; child != null; child = child.sibling) {
+ if (child.outcome != null) {
+ var outcomeElem:XML = ;
+ if (child.reachedby != null && child.reachedby.isChance) {
+ outcomeElem.@prob = child.reachedby.prob; // TODO: write out as a fraction
+ } else {
+ outcomeElem.@move = child.reachedby.label; // TODO: add a unique constraint in the program to prevent errors here?
+ }
+ for (var player:Player = tree.firstPlayer; player != null; player = player.nextPlayer) {
+ var payoffElem:XML = ;
+ payoffElem.@player = player.name;
+ payoffElem.@value = child.outcome.pay(player); // TODO: write out as fraction?
+ outcomeElem.appendChild(payoffElem);
+ }
+ nodeElem.appendChild(outcomeElem);
+ }
+ }
+ return nodeElem;
+ }
+ }
}
\ No newline at end of file
diff --git a/gui-builder/src/lse/math/games/builder/io/XMLImporter.as b/gui-builder/src/lse/math/games/builder/io/XMLImporter.as
new file mode 100644
index 0000000..8c97c53
--- /dev/null
+++ b/gui-builder/src/lse/math/games/builder/io/XMLImporter.as
@@ -0,0 +1,488 @@
+package lse.math.games.builder.io
+{
+ import flash.utils.Dictionary;
+
+ import lse.math.games.builder.fig.FigFontManager;
+ import lse.math.games.builder.model.ExtensiveForm;
+ import lse.math.games.builder.model.Iset;
+ import lse.math.games.builder.model.Move;
+ import lse.math.games.builder.model.Node;
+ import lse.math.games.builder.model.NormalForm;
+ import lse.math.games.builder.model.Outcome;
+ import lse.math.games.builder.model.Player;
+ import lse.math.games.builder.model.Rational;
+ import lse.math.games.builder.settings.FileSettings;
+ import lse.math.games.builder.settings.SCodes;
+ import lse.math.games.builder.viewmodel.TreeGrid;
+
+ import util.Log;
+
+ /**
+ * XMLImporter loads trees and matrixes from XML data.
+ *
+ * Instructions to use it:
+ *
Make an instance of it calling the constructor with the xml you want to read
+ *
Check the type of info stored: an Ext Form Tree, a Strat Form Matri, or UNKNOWN (Broken)
+ *
Call the corresponding loader
+ *
+ * @author Mark Egesdal & alfongj
+ */
+ //TODO: Do something with gameDescription info
+ //TODO: In the future, load node and iset names & maybe? payoffs in non-outcomes
+ //TODO #33 loadMatrix
+ //TODO #33 load players first, when they are in the spec
+ public class XMLImporter
+ {
+ //Types of info contained:
+ /** The XML file is not of a known type */
+ public const UNKNOWN:int = -1;
+ /** The XML file represents a tree in Extensive Form */
+ public const EF:int = 1;
+ /** The XML file represents a matrix in Strategic Form */
+ public const SF:int = 2;
+
+ //File header properties
+ private var _version:int;
+ private var _type:int;
+ private var _displayInfo:Boolean = false; //If the XML contains the tag
+ private var _gameDescInfo:Boolean = false; //If the XML contains the tag
+
+ //Objects contained
+ private var nodes:Dictionary;
+ private var isets:Dictionary;
+ private var isetObjToId:Dictionary;
+ private var singletons:Vector.;
+ private var moves:Dictionary;
+ private var players:Dictionary;
+
+ private var xml:XML = null;
+ private var fileSettings:FileSettings;
+ private var tree:ExtensiveForm = null;
+ private var matrix:NormalForm = null;
+ private var log:Log = Log.instance;
+ private var lastIsetIdx:int = 0;
+
+
+
+ /** Stores a reference to the xml to be loaded and analyses the data in it */
+ public function XMLImporter(xml:XML)
+ {
+ this.xml = xml;
+
+ analyseData();
+ }
+
+ /**
+ * Version number of the XML file being read.
+ * The old version will be considered version 0.
+ * An unknown version will be considered version -1
+ */
+ public function get version():int { return _version; }
+
+ /**
+ * Type of the file being read. It can be:
+ *
'EF': Extensive Form
+ *
'SF': Strategic Form
+ *
'BROKEN': None of them
+ */
+ public function get type():int { return _type; }
+
+ /** If the xml file contains any display info (i.e., inside tags) */
+ public function get displayInfo():Boolean { return _displayInfo; }
+
+ /** If the xml file contains any game description info (i.e., inside tags) */
+ public function get gameDescInfo():Boolean { return _gameDescInfo; }
+
+
+
+ //Populates version, type, gameDescInfo and displayInfo properties
+ private function analyseData():void {
+ //ANALYSE VERSION INFO
+ var firstChild:XML = xml[0];
+ if(firstChild.name() == "extensiveForm")
+ {
+ _version = 0;
+ log.add(Log.ERROR, "Warning: This file is of an old format. Although gte is still "+
+ "capable of opening it, it may not be supported in future versions, so please overwrite "+
+ "it now with an updated file by pressing the 'Save' button (Ctrl+S)");
+ }
+ else if(firstChild.name() == "gte")
+ {
+ //TODO #33: Once version is included in the spec, return it
+ _version = 1
+ } else _version = -1;
+
+ //ANALYSE TYPE, DISPINFO & GAMEDESCRIPTIONINFO
+ if(_version == -1)
+ _type = UNKNOWN;
+ if(_version == 0)
+ _type = EF;
+ else {
+ var ef:Boolean = false;
+ var sf:Boolean = false;
+
+ for each(var header:XML in firstChild.children())
+ {
+ var name:String = header.name();
+ if(name==null)
+ log.add(Log.ERROR_THROW, "Corrupt XML file: empty child of ");
+
+ if(name == "display")
+ if(header.child("*").length()>0)
+ _displayInfo = true;
+ if(name == "gameDescription")
+ if(header.text().length()>0)
+ _gameDescInfo = true;
+ if(name == "extensiveForm")
+ ef = true;
+ if(name == "strategicForm")
+ sf = true;
+ }
+
+ if(ef){
+ _type = EF;
+
+ if(sf)
+ log.add(Log.ERROR_HIDDEN, "The XML file being loaded contained info for "+
+ "both an EF and a SF game. Ignoring the lattest");
+ } else {
+ if(sf)
+ _type = SF;
+ else {
+ log.add(Log.ERROR, "Corrupt XML file: couldn't find any game information.");
+ _type = UNKNOWN;
+ }
+ }
+ }
+ }
+
+ /** Loads into a extensive form tree the xml data */
+ public function loadTree(tree:ExtensiveForm):ExtensiveForm
+ {
+ //Clear previous file settings (from another file, possibly)
+ fileSettings = FileSettings.instance;
+ fileSettings.clear();
+
+ lastIsetIdx = 0;
+
+ if(_type != EF)
+ {
+ log.add(Log.ERROR_THROW, "Tried to load a tree from a non-tree game file");
+ return null;
+ }
+ else {
+ if(_displayInfo) //Load settings, if any
+ {
+ loadSettingsOnTree(tree as TreeGrid);
+ }
+
+ this.tree = tree;
+ tree.clearTree();
+
+ nodes = new Dictionary();
+ isets = new Dictionary();
+ isetObjToId = new Dictionary();
+ singletons = new Vector.();
+ moves = new Dictionary();
+ players = new Dictionary();
+
+ //Depending on the version, the tree data will be in a different part
+ var childrenList:XMLList;
+ if(_version == 0)
+ childrenList = xml.children();
+ else
+ childrenList = xml.extensiveForm.children();
+
+ //Start processing the tree
+ for each(var child:XML in childrenList) {
+ if (child.name() == "node") {
+ processNode(child, null);
+ } else if (child.name() == "outcome") {
+ processOutcome(child, null);
+ } else {
+ log.add(Log.ERROR_HIDDEN, "Ignoring unknown element: " + child);
+ }
+ }
+
+ //Add the found isets to the tree
+ var iset:Iset = null;
+ for (var isetId:String in isets) {
+ iset = isets[isetId] as Iset;
+ if (iset != tree.root.iset) {
+ tree.addIset(iset);
+ }
+ }
+ for each (iset in singletons) {
+ if (iset != tree.root.iset) {
+ tree.addIset(iset);
+ }
+ }
+
+ hookupAndVerifyMoves();
+
+ //TODO: 3PL
+ while(tree.numPlayers<2)
+ {
+ tree.newPlayer(""+(tree.numPlayers+1));
+ }
+
+ return tree;
+ }
+ }
+
+ //Parses all settings found under the tags and loads them into the tree
+ //Mustn't be called if _displayInfo is false
+ private function loadSettingsOnTree(tree:TreeGrid):void
+ {
+ for each(var child:XML in xml.display.children())
+ {
+ if (child.name() == "color") {
+ var player:XMLList = child.@player;
+ if(player!=null)
+ {
+ if(player.toString()=="1")
+ {
+ fileSettings.setValue(SCodes.FILE_PLAYER_1_COLOR, getColorFromHexString(child.text()));
+ } else if(player.toString()=="2")
+ fileSettings.setValue(SCodes.FILE_PLAYER_2_COLOR, getColorFromHexString(child.text()));
+ }
+ } else if (child.name() == "font") {
+ var fontFamily:String = child.text();
+ if(FigFontManager.isFontAvailable(fontFamily))
+ fileSettings.setValue(SCodes.FILE_FONT, fontFamily);
+ } else if (child.name() == "strokeWidth") {
+ var width:int = int(child.text());
+ if(width>=1)
+ fileSettings.setValue(SCodes.FILE_STROKE_WIDTH, width);
+ } else if (child.name() == "nodeDiameter") {
+ var nDiam:Number = Number(child.text());
+ if(nDiam>0)
+ fileSettings.setValue(SCodes.FILE_NODE_DIAMETER, nDiam);
+ } else if (child.name() == "isetDiameter") {
+ var iDiam:Number = Number(child.text());
+ if(iDiam>0)
+ fileSettings.setValue(SCodes.FILE_ISET_DIAMETER, iDiam);
+ } else if (child.name() == "levelDistance") {
+ var distance:int = int(child.text());
+ if(distance>=1)
+ fileSettings.setValue(SCodes.FILE_LEVEL_DISTANCE, distance);
+ } else {
+ log.add(Log.ERROR_HIDDEN, "Ignoring unknown settings element: " + child);
+ }
+ }
+ }
+
+ /* Parses a node with its move and iset info, adds it to the tree,
+ * and acts recursively by processing its children nodes and outcomes
+ */
+ private function processNode(elem:XML, parentNode:Node):void
+ {
+ //init
+ var node:Node = null;
+ if (elem.@id != undefined)
+ {
+ var id:String = elem.@id;
+ node = nodes[id];
+
+ if (node == null) { //Creating a new node
+ node = tree.createNode();
+ nodes[id] = node; //TODO #46 createNode(id)
+ }
+ } else {
+ node = tree.createNode();
+ }
+
+ //assign parent
+ if (parentNode == null && elem.@parent != undefined)
+ {
+ var parentId:String = elem.@parent;
+
+ parentNode = nodes[parentId];
+
+ if (parentNode == null) {
+ parentNode = tree.createNode(); //TODO #46 createNode(parentId)
+ nodes[parentId] = parentNode;
+ }
+ }
+ if (parentNode != null) {
+ parentNode.addChild(node);
+ } else {
+ tree.root = node;
+ }
+
+ // process iset
+ var isetId:String = null;
+ if (elem.@iset != undefined) {
+ isetId = elem.@iset;
+ }
+
+ var iset:Iset = null;
+ var player:Player = (elem.@player != undefined) ? getPlayer(elem.@player) : Player.CHANCE;
+ if (isetId == null) {
+ iset = new Iset(player);
+ iset.idx = lastIsetIdx++; //This idx is different from isetId. It's not useful inside this class
+ singletons.push(iset); // root is already taken care of
+ } else {
+ //look it up in the map, if it doesn't exist create it and add it
+ iset = isets[isetId];
+ if (iset == null) {
+ iset = new Iset(player);
+ iset.idx = lastIsetIdx++; //This idx is different from isetId. It's not useful inside this class
+ isets[isetId] = iset;
+ isetObjToId[iset] = isetId;
+ } else {
+ if (player != Player.CHANCE) {
+ if (iset.player != Player.CHANCE && player != iset.player) {
+ log.add(Log.ERROR_HIDDEN, "Warning: @player attribute conflicts with earlier iset player assignment. Ignored.");
+ }
+ while (iset.player != player) {
+ iset.changePlayer(tree.firstPlayer);
+ }
+ }
+ }
+ }
+ iset.insertNode(node);
+
+ // set up the moves
+ processMove(elem, node, parentNode);
+
+ for each (var child:XML in elem.children()) {
+ if (child.name() == "node") {
+ processNode(child, node);
+ } else if (child.name() == "outcome") {
+ processOutcome(child, node);
+ } else if (child.name() == "payoff") {
+ log.add(Log.HINT, "The tree contained interior payoffs, which aren't currently "+
+ "supported in gte and therefore have been ignored.");
+ } else {
+ log.add(Log.ERROR_HIDDEN, "Ignoring unknown element: " + child);
+ }
+ }
+ }
+
+ /* Parses an outcome, creates it and its wrapping node, and inserts it to its parent */
+ private function processOutcome(elem:XML, parent:Node):void
+ {
+ // Create wrapping node
+ // get parent from dictionary... if it doesn't exist then the outcome must be the root
+ var wrapNode:Node = parent != null ? parent.newChild() : tree.createNode();
+ if (parent == null) {
+ tree.root = wrapNode;
+ }
+
+ // set up the moves
+ processMove(elem, wrapNode, parent);
+
+ if(elem.child("*").length() == 0)
+ {
+ if(tree.numPlayers == 0)
+ tree.newPlayer("1");
+ wrapNode.makeNonTerminal();
+
+ //TODO: ERROR parsing non terminal leaves: they dont draw labels
+ } else
+ {
+ var outcome:Outcome = wrapNode.makeTerminal();
+ for each (var child:XML in elem.children()) {
+ if (child.name() == "payoff") {
+ var playerId:String = child.@player;
+ var payoff:Rational = Rational.parse(child.@value);
+
+ var player:Player = players[playerId];
+ if (player == null) {
+ player = new Player(playerId, tree);
+ players[playerId] = player;
+ }
+ outcome.setPay(player, payoff);
+ } else {
+ log.add(Log.ERROR_HIDDEN, "Ignoring unknown element: " + child);
+ }
+ }
+ }
+ }
+
+ /* Parses, creates, processes and inserts a move into its node */
+ private function processMove(elem:XML, node:Node, parent:Node):void
+ {
+ if (elem.@move != undefined) {
+ var moveId:String = elem.@move;
+ var moveIsetId:String = (parent != null && parent.iset != null) ? String(isetObjToId[parent.iset]) : "";
+ var move:Move = moves[moveIsetId + "::" + moveId];
+ if (move == null) {
+ move = new Move();
+ move.label = moveId;
+ moves[moveIsetId + "::" + moveId] = move;
+ }
+ node.reachedby = move;
+ } else if (parent != null) {
+ // assume this comes from a chance node with a probability of zero
+ node.reachedby = new Move();
+ }
+
+ if (elem.@prob != undefined && node.reachedby != null) {
+ node.reachedby.prob = Rational.parse(elem.@prob);
+ }
+ }
+
+ //TODO: there has got to be a more efficient algorithm
+ private function hookupAndVerifyMoves():void
+ {
+ for (var iset:Iset = tree.root.iset; iset != null; iset = iset.nextIset) {
+
+ iset.sort();
+
+ //for each child of the first node, hook up move
+ var baseline:Node = iset.firstNode;
+ for (var baselineChild:Node = baseline.firstChild, childIdx:int = 0; baselineChild != null; baselineChild = baselineChild.sibling, ++childIdx)
+ {
+ iset.assignMove(baselineChild.reachedby);
+
+ // make sure all the rest of the nodes have the child with the same move
+ // TODO: it does not necessarily need to be at the same index
+ for (var baselineMate:Node = baseline.nextInIset; baselineMate != null; baselineMate = baselineMate.nextInIset)
+ {
+ var mateChild:Node = baselineMate.firstChild;
+ for (var i:int = 0; i < childIdx; ++i) {
+ mateChild = mateChild.sibling;
+ }
+ if (mateChild.reachedby != baselineChild.reachedby) {
+ if (mateChild.reachedby == null) {
+ log.add(Log.ERROR_THROW, "node does not contain an incoming move");
+ } else {
+ log.add(Log.ERROR_THROW, "Iset " + iset.idx + " is inconsistent for node " + baselineMate.number /*+ " at " + baselineMate.setIdx*/ + " for child " + mateChild.number + " at " + childIdx + " with move " + mateChild.reachedby);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Returns in a uint a color from the following hex formats:
+ //#RRGGBB, 0xRRGGBB, RRGGBB
+ private function getColorFromHexString(hex:String):uint
+ {
+ if(hex.indexOf("#")==0)
+ hex = hex.substr(1);
+
+ if(hex.indexOf("0x")!=0)
+ hex = "0x"+hex;
+
+ return uint(hex);
+ }
+
+ //Returns a player from a String ID
+ private function getPlayer(playerId:String):Player
+ {
+ if (playerId == Player.CHANCE_NAME) {
+ return Player.CHANCE;
+ }
+
+ var player:Player = players[playerId];
+ if (player == null) {
+ player = new Player(playerId, tree);
+ players[playerId] = player;
+ }
+ return player;
+ }
+ }
+}
diff --git a/gui-builder/src/lse/math/games/builder/model/ExtensiveForm.as b/gui-builder/src/lse/math/games/builder/model/ExtensiveForm.as
index de43a4b..c0348bf 100644
--- a/gui-builder/src/lse/math/games/builder/model/ExtensiveForm.as
+++ b/gui-builder/src/lse/math/games/builder/model/ExtensiveForm.as
@@ -1,5 +1,7 @@
package lse.math.games.builder.model
{
+ import flash.net.FileReference;
+
import util.Log;
/**
@@ -18,6 +20,8 @@ package lse.math.games.builder.model
private var _firstPlayer:Player = null;
private var lastNodeNumber:int = 0;
+ private var lastOrderedNodeNumber:int = 0;
+ private var lastOrderedIsetNumber:int = 0;
private var log:Log = Log.instance;
@@ -42,6 +46,18 @@ package lse.math.games.builder.model
return count;
}
+ /** Number of players in the tree */
+ public function get numPlayers():int {
+ var count:int = 0;
+ var player:Player = _firstPlayer;
+ while(player!=null)
+ {
+ count++;
+ player = player.nextPlayer;
+ }
+ return count;
+ }
+
/** Player who moves first in the tree */
//TODO: Explain if other relations inside player or something must change also, when set
public function set firstPlayer(player:Player):void { _firstPlayer = player; }
@@ -77,6 +93,39 @@ package lse.math.games.builder.model
return new Node(this, number);
}
+ /**
+ * Assigns nodes and isets ids in pre-order. It should be called after all
+ * actions that might change the tree pre-order representation.
+ */
+ public function orderIds():void
+ {
+ //Reset all iset numbers
+ var h:Iset = root.iset;
+ while(h!=null)
+ {
+ h.idx = -1;
+ h = h.nextIset;
+ }
+
+ lastOrderedNodeNumber = 0;
+ lastOrderedIsetNumber = 0;
+ recOrderIds(_root);
+ }
+
+ //Recursively adds new idxs to nodes and isets
+ private function recOrderIds(node:Node):void
+ {
+ node.number = lastOrderedNodeNumber++;
+ if(node.iset!=null && node.iset.idx == -1) node.iset.idx = lastOrderedIsetNumber++;
+
+ var child:Node = node.firstChild;
+ while(child!=null)
+ {
+ recOrderIds(child);
+ child = child.sibling;
+ }
+ }
+
/** Searchs for a node with a determinate 'number' (id). If it finds it, it returns it, else it returns null */
public function getNodeById(number:int):Node
{
@@ -110,8 +159,8 @@ package lse.math.games.builder.model
/**
* Adds an Iset to the tree, at the end of the linked list of isets
- * (which doesn't directly relate to the physiscal position in the tree).
- * If the Iset was already in the list, it does nothing
+ * (which doesn't directly relate to the spatial location in the tree).
+ * If the Iset was already in the list, it does nothing.
* @return (int) The added isets' idx after insertion
*/
public function addIset(toAdd:Iset):int
@@ -126,13 +175,13 @@ package lse.math.games.builder.model
idx = h.idx;
log.add(Log.ERROR_HIDDEN, "Pretended to add an iset equal to the one existing with idx "+idx);
break;
- } else if (h.nextIset == null) {
+ } else if (h.nextIset == null || h.nextIset.idx>toAdd.idx) {
break;
}
h = h.nextIset;
}
if (idx == -1) {
- h.insertAfter(toAdd);
+ h.insertAfter(toAdd, false);
}
return toAdd.idx;
}
@@ -251,10 +300,20 @@ package lse.math.games.builder.model
}
}
+ /** Save a TXT representation of the tree */
+ public function saveTreeTXT():void
+ {
+ new FileReference().save(printTree(), "treedump.txt");
+ }
+
+ private var treeLog:String = "";
+
//used for debugging
- public function printTree():void
+ public function printTree():String
{
+ treeLog = "";
recPrintTree(root);
+ return treeLog;
}
private function recPrintTree(x:Node):void // preorder: node, then children
@@ -265,13 +324,13 @@ package lse.math.games.builder.model
}
var y:Node = x.firstChild;
- log.add(Log.DEBUG, indent + x.toString() + ((y == null) ? " (leaf)" : ""));
+ treeLog += (indent + x.toString() + ((y == null) ? " (leaf)" : ("")) +"\n");
while (y != null)
{
recPrintTree(y);
y = y.sibling;
- }
+ }
}
public function toString():String
diff --git a/gui-builder/src/lse/math/games/builder/model/Iset.as b/gui-builder/src/lse/math/games/builder/model/Iset.as
index afb32e0..f553391 100644
--- a/gui-builder/src/lse/math/games/builder/model/Iset.as
+++ b/gui-builder/src/lse/math/games/builder/model/Iset.as
@@ -481,6 +481,7 @@ package lse.math.games.builder.model
public function get nextIset():Iset { return _nextIset; }
public function get prevIset():Iset { return _prevIset; }
public function get idx():int { return _idx; }
+ public function set idx(value:int):void { _idx = value; }
/** Creates a new iset and appends it at the end of the linked list */
public function newIset(player:Player):Iset
@@ -504,9 +505,9 @@ package lse.math.games.builder.model
/**
* Inserts an Iset after this one in the linked list of Isets,
- * updating the idx's accordingly.
+ * updating the idx's accordingly if modifyIdx is true
*/
- public function insertAfter(toAdd:Iset):void
+ public function insertAfter(toAdd:Iset, modifyIdx:Boolean):void
{
toAdd._nextIset = _nextIset;
_nextIset = toAdd;
@@ -517,12 +518,16 @@ package lse.math.games.builder.model
toAdd._prevIset = this;
- toAdd._idx = _idx + 1;
- for (var h:Iset = toAdd._nextIset; h != null; h = h._nextIset) {
- ++h._idx;
+ if(modifyIdx)
+ {
+ toAdd._idx = _idx + 1;
+ for (var h:Iset = toAdd._nextIset; h != null; h = h._nextIset) {
+ ++h._idx;
+ }
}
}
+
//Removes this Iset from the LinkedList
internal function remove():void
{
diff --git a/gui-builder/src/lse/math/games/builder/model/Node.as b/gui-builder/src/lse/math/games/builder/model/Node.as
index b9556d4..b99c394 100644
--- a/gui-builder/src/lse/math/games/builder/model/Node.as
+++ b/gui-builder/src/lse/math/games/builder/model/Node.as
@@ -60,6 +60,7 @@ package lse.math.games.builder.model
/** Number (or id) of this node inside the tree */
public function get number():int { return _number; } // for specification of tree
+ public function set number(value:int):void { _number = value; }
/** First child of this node. Can be null if there isn't any */
public function get firstChild():Node { return _firstchild; }
@@ -264,7 +265,7 @@ package lse.math.games.builder.model
if (_father != null) {
_iset = new Iset(
(_father.iset.player != Player.CHANCE && _father.iset.player.nextPlayer != null) ? _father.iset.player.nextPlayer : _tree.firstPlayer);
- _father.iset.insertAfter(_iset);
+ _father.iset.insertAfter(_iset, true);
} else {
_iset = new Iset(_tree.firstPlayer);
//trace("Node.makeNonTerminal(): new root iset");
diff --git a/gui-builder/src/lse/math/games/builder/presenter/ActionHandler.as b/gui-builder/src/lse/math/games/builder/presenter/TreeActionHandler.as
similarity index 76%
rename from gui-builder/src/lse/math/games/builder/presenter/ActionHandler.as
rename to gui-builder/src/lse/math/games/builder/presenter/TreeActionHandler.as
index ab4de0e..d478f30 100644
--- a/gui-builder/src/lse/math/games/builder/presenter/ActionHandler.as
+++ b/gui-builder/src/lse/math/games/builder/presenter/TreeActionHandler.as
@@ -1,164 +1,169 @@
-package lse.math.games.builder.presenter
-{
- import flash.utils.getTimer;
-
- import lse.math.games.builder.io.ExtensiveFormXMLReader;
- import lse.math.games.builder.io.ExtensiveFormXMLWriter;
- import lse.math.games.builder.io.FileManager;
- import lse.math.games.builder.viewmodel.DepthAdjuster;
- import lse.math.games.builder.viewmodel.TreeGrid;
-
- import util.Log;
-
- /**
- * Class that handles Action executing, as well as undoing and redoing, and reseting the workspace either
- * to the default (just root) tree, or to one loaded via an xml container.
- *
- * @author Mark
- */
- public class ActionHandler
- {
- //TODO: SETTING
- private const MINIMUM_BUFFER_SIZE:int = 10; //Number of actions that will be undoable, as a minimum
- private const MAXIMUM_TIME_UNDO:int = 1000; //Maximum milliseconds that the 'undo' command should take
-
- private var _undone:Vector. = new Vector.();
- private var _history:Vector. = new Vector.();
- private var _xml:XML = null; //TODO: store as an actual TreeGrid obj? It would imply making it and its properties clonable
- //however, the time lost in creating and accesing the _xml is small, lower than 20ms, so I think it is not worth changing
- private var _fileManager:FileManager;
-
- private var log:util.Log = Log.instance;
-
-
-
- public function ActionHandler(fileManager:FileManager) {
- _fileManager = fileManager;
- }
-
- /** Executes action, and stores it in 'history' vector, if it changes Data */
- public function processAction(action:IAction, grid:TreeGrid):void
- {
- if (action != null) {
- if (action.changesData) { // TODO: else add it to a pending list of actions todo
-
- while(_undone.length>0) _undone.pop(); //Empty the 'undone' queue
- action.doAction(grid);
- _fileManager.unsavedChanges = true;
- manageBuffer(action, grid);
- } else
- action.doAction(grid);
- }
- }
-
- /*
- * Pushes the action into the buffer of done actions.
- * If the list of actions exceeds in processing time MAXIMUM_TIME_UNDO
- * and in length MINIMUM_BUFFER_SIDE, it deletes the last stored action,
- * and updates with it the recovery _xml.
- */
- private function manageBuffer(action:IAction, grid:TreeGrid):void
- {
- _history.push(action);
-
- var totalTimeInBuffer:int = 0;
- var i:int = _history.length;
- while(--i) totalTimeInBuffer += _history[i].timeElapsed;
-
- if(totalTimeInBuffer > MAXIMUM_TIME_UNDO && _history.length > MINIMUM_BUFFER_SIZE)
- {
- var recGrid:TreeGrid = new TreeGrid();
- initTree(recGrid); //Create a treegrid from the recovery xml
-
- _history.shift().doAction(recGrid); //Update the recovery grid while
- //erasing the last action
-
- var xmlWriter:ExtensiveFormXMLWriter = new ExtensiveFormXMLWriter();
- _xml = xmlWriter.write(recGrid); //Store the grid into xml again
- }
- }
-
- /**
- * Undoes last action by resetting the tree and reapplying all actions that had been done.
- * @return True if there was operation to undo, False if not
- */
- public function undo(grid:TreeGrid):Boolean
- {
- if (_history.length > 0) {
- initTree(grid);
- _undone.push(_history.pop());
-
- var redoStack:Vector. = new Vector.();
- while (_history.length > 0) {
- redoStack.push(_history.pop());
- }
-
- while (redoStack.length > 0)
- {
- var todo:IAction = redoStack.pop();
- todo.doAction(grid);
- _history.push(todo);
- }
-
- _fileManager.unsavedChanges = true;
-
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Repeats last undone Action.
- * @return True if there was operation to redo, False if not
- */
- public function redo(grid:TreeGrid):Boolean
- {
- if (_undone.length != 0)
- {
- var todo:IAction = _undone.pop();
- todo.doAction(grid);
- _history.push(todo);
-
- _fileManager.unsavedChanges = true;
-
- return true;
- } else {
- return false;
- }
- }
-
- //Restores tree from a xml file or creates a default one (just the root)
- private function initTree(grid:TreeGrid):void
- {
- if (_xml != null) {
- var reader:ExtensiveFormXMLReader = new ExtensiveFormXMLReader(_xml);
- reader.load(grid);
-
- var depthAdjuster:IAction = new DepthAdjuster();
- depthAdjuster.doAction(grid);
- } else {
- grid.clearTree();
- grid.defaultTree();
- }
- }
-
- /** Loads a tree from a xml file, and resets history and undone data */
- public function load(xml:XML, grid:TreeGrid):void
- {
- _xml = xml;
- initTree(grid);
- _undone = new Vector.();
- _history = new Vector.();
- }
-
- /** Creates the default tree (just the root) and resets history and undone data */
- public function reset(grid:TreeGrid):void
- {
- _xml = null;
- initTree(grid);
- _undone = new Vector.();
- _history = new Vector.();
- }
- }
+package lse.math.games.builder.presenter
+{
+ import flash.utils.getTimer;
+
+ import lse.math.games.builder.io.XMLExporter;
+ import lse.math.games.builder.io.FileManager;
+ import lse.math.games.builder.io.XMLImporter;
+ import lse.math.games.builder.settings.SCodes;
+ import lse.math.games.builder.settings.Settings;
+ import lse.math.games.builder.settings.UserSettings;
+ import lse.math.games.builder.viewmodel.DepthAdjuster;
+ import lse.math.games.builder.viewmodel.TreeGrid;
+
+ import util.Log;
+
+ //TODO #33: Do an equivalent class for matrixes and matrix actions
+
+ /**
+ * Class that handles Action executing, as well as undoing and redoing, and reseting the workspace either
+ * to the default (just root) tree, or to one loaded via an xml container.
+ *
+ * @author Mark
+ */
+ public class TreeActionHandler
+ {
+ private const MAXIMUM_TIME_UNDO:int = 1000; //When the undo buffer actions sum up more than these ms,
+ //it starts trimming, always keeping at least the
+ //MINIMUM_BUFFER_SIZE in settings.
+
+ private var _undone:Vector. = new Vector.();
+ private var _history:Vector. = new Vector.();
+ private var _xml:XML = null;
+ private var _fileManager:FileManager;
+ private var settings:UserSettings = UserSettings.instance;
+ private var log:util.Log = Log.instance;
+
+
+
+ public function TreeActionHandler(fileManager:FileManager) {
+ _fileManager = fileManager;
+ }
+
+ /** Executes action, and stores it in 'history' vector, if it changes Data */
+ public function processAction(action:IAction, grid:TreeGrid):void
+ {
+ if (action != null) {
+ if (action.changesData) { // TODO: else add it to a pending list of actions todo
+
+ while(_undone.length>0) _undone.pop(); //Empty the 'undone' queue
+ action.doAction(grid);
+ _fileManager.unsavedChanges = true;
+ manageBuffer(action, grid);
+ } else
+ action.doAction(grid);
+ }
+ }
+
+ /*
+ * Pushes the action into the buffer of done actions.
+ * If the list of actions exceeds in processing time MAXIMUM_TIME_UNDO
+ * and in length MINIMUM_BUFFER_SIDE, it deletes the last stored action,
+ * and updates with it the recovery _xml.
+ */
+ private function manageBuffer(action:IAction, grid:TreeGrid):void
+ {
+ _history.push(action);
+
+ var totalTimeInBuffer:int = 0;
+ var i:int = _history.length;
+ while(--i) totalTimeInBuffer += _history[i].timeElapsed;
+
+ if(totalTimeInBuffer > MAXIMUM_TIME_UNDO
+ && _history.length > (settings.getValue(SCodes.MINIMUM_BUFFER_SIZE) as int))
+ {
+ var recGrid:TreeGrid = new TreeGrid();
+ initTree(recGrid); //Create a treegrid from the recovery xml
+
+ _history.shift().doAction(recGrid); //Update the recovery grid while
+ //erasing the last action
+
+ var xmlWriter:XMLExporter = new XMLExporter();
+ _xml = xmlWriter.writeTree(recGrid); //Store the grid into xml again
+ }
+ }
+
+ /**
+ * Undoes last action by resetting the tree and reapplying all actions that had been done.
+ * @return True if there was operation to undo, False if not
+ */
+ public function undo(grid:TreeGrid):Boolean
+ {
+ if (_history.length > 0) {
+ initTree(grid);
+ _undone.push(_history.pop());
+
+ var redoStack:Vector. = new Vector.();
+ while (_history.length > 0) {
+ redoStack.push(_history.pop());
+ }
+
+ while (redoStack.length > 0)
+ {
+ var todo:IAction = redoStack.pop();
+ todo.doAction(grid);
+ _history.push(todo);
+ }
+
+ _fileManager.unsavedChanges = true;
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Repeats last undone Action.
+ * @return True if there was operation to redo, False if not
+ */
+ public function redo(grid:TreeGrid):Boolean
+ {
+ if (_undone.length != 0)
+ {
+ var todo:IAction = _undone.pop();
+ todo.doAction(grid);
+ _history.push(todo);
+
+ _fileManager.unsavedChanges = true;
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //Restores tree from a xml file or creates a default one (just the root)
+ private function initTree(grid:TreeGrid):void
+ {
+ if (_xml != null) {
+ var reader:XMLImporter = new XMLImporter(_xml);
+ reader.loadTree(grid);
+
+ var depthAdjuster:IAction = new DepthAdjuster();
+ depthAdjuster.doAction(grid);
+ } else {
+ grid.clearTree();
+ grid.defaultTree();
+ }
+ }
+
+ /** Loads a tree from a xml file, and resets history and undone data */
+ public function load(xml:XML, grid:TreeGrid):void
+ {
+ _xml = xml;
+ initTree(grid);
+ _undone = new Vector.();
+ _history = new Vector.();
+ }
+
+ /** Creates the default tree (just the root) and resets history and undone data */
+ public function reset(grid:TreeGrid):void
+ {
+ _xml = null;
+ initTree(grid);
+ _undone = new Vector.();
+ _history = new Vector.();
+ }
+ }
}
\ No newline at end of file
diff --git a/gui-builder/src/lse/math/games/builder/presenter/TreeGridPresenter.as b/gui-builder/src/lse/math/games/builder/presenter/TreeGridPresenter.as
index 0b3ccd7..4465a90 100644
--- a/gui-builder/src/lse/math/games/builder/presenter/TreeGridPresenter.as
+++ b/gui-builder/src/lse/math/games/builder/presenter/TreeGridPresenter.as
@@ -20,7 +20,7 @@ package lse.math.games.builder.presenter
import lse.math.games.builder.fig.FigFontManager;
import lse.math.games.builder.fig.TreeGridFigWriter;
- import lse.math.games.builder.io.ExtensiveFormXMLWriter;
+ import lse.math.games.builder.io.XMLExporter;
import lse.math.games.builder.io.FileManager;
import lse.math.games.builder.model.Iset;
import lse.math.games.builder.model.Node;
@@ -28,6 +28,7 @@ package lse.math.games.builder.presenter
import lse.math.games.builder.model.Player;
import lse.math.games.builder.model.Rational;
import lse.math.games.builder.model.Strategy;
+ import lse.math.games.builder.settings.FileSettings;
import lse.math.games.builder.view.Canvas;
import lse.math.games.builder.view.MouseScroller;
import lse.math.games.builder.viewmodel.TreeGrid;
@@ -44,11 +45,13 @@ package lse.math.games.builder.presenter
/**
* @author Mark Egesdal
*/
+
+ //TODO: #33 Presenter & MatrixGridPresenter
public class TreeGridPresenter
{
private var _canvas:Canvas;
private var _fileManager:FileManager;
- private var _actionHandler:ActionHandler;
+ private var _treeActionHandler:TreeActionHandler;
private var _grid:TreeGrid;
private var _gridData:ArrayCollection = new ArrayCollection();
@@ -57,8 +60,7 @@ package lse.math.games.builder.presenter
private var log:Log = Log.instance;
-// private var _log:Log = Log.instance;
-// private var _lastLogMessage:String = _log.lastMessage;
+
//private var _modelDirty:Boolean = true;
@@ -66,16 +68,9 @@ package lse.math.games.builder.presenter
{
_gridData.addEventListener("collectionChange", onOutcomeEdit);
_fileManager = new FileManager(this);
- _actionHandler = new ActionHandler(_fileManager);
+ _treeActionHandler = new TreeActionHandler(_fileManager);
}
-// //TODO: This doesn't update the gui
-// public function get lastLogMessage():String
-// {
-// _lastLogMessage = _log.lastMessage;
-// return _lastLogMessage;
-// }
-
public function set grid(value:TreeGrid):void {
_grid = value;
}
@@ -393,7 +388,7 @@ package lse.math.games.builder.presenter
{
var action:IAction = getAction(_grid);
if (action != null) {
- _actionHandler.processAction(action, _grid);
+ _treeActionHandler.processAction(action, _grid);
invalidate(action.changesData, action.changesSize, action.changesDisplay);
}
}
@@ -410,7 +405,7 @@ package lse.math.games.builder.presenter
selectedNode = -1;
var action:IAction = getClickAction(_grid, x, y);
if (action != null) {
- _actionHandler.processAction(action, _grid);
+ _treeActionHandler.processAction(action, _grid);
invalidate(action.changesData, action.changesSize, action.changesDisplay);
}
}
@@ -418,7 +413,7 @@ package lse.math.games.builder.presenter
public function undo():void
{
- if (_actionHandler.undo(_grid)) {
+ if (_treeActionHandler.undo(_grid)) {
invalidate(true, true, true);
} else {
log.add(Log.HINT, "No more operations to undo");
@@ -427,7 +422,7 @@ package lse.math.games.builder.presenter
public function redo():void
{
- if (_actionHandler.redo(_grid)) {
+ if (_treeActionHandler.redo(_grid)) {
invalidate(true, true, true);
} else {
log.add(Log.HINT, "No more operations to redo");
@@ -450,7 +445,7 @@ package lse.math.games.builder.presenter
}
}
if (chain != null) {
- _actionHandler.processAction(chain, _grid);
+ _treeActionHandler.processAction(chain, _grid);
invalidate(chain.changesData, chain.changesSize, chain.changesDisplay);
}
}
@@ -497,7 +492,7 @@ package lse.math.games.builder.presenter
public function clear():void
{
resetZoom();
- _actionHandler.reset(_grid);
+ _treeActionHandler.reset(_grid);
fileManager.clear();
invalidate(true, true, true);
}
@@ -545,22 +540,31 @@ package lse.math.games.builder.presenter
* Returns a XML file with the current tree packaged in it
*/
public function saveCurrentTreeToXML():XML {
- var xmlWriter:ExtensiveFormXMLWriter = new ExtensiveFormXMLWriter();
- return xmlWriter.write(_grid);
+ var xmlWriter:XMLExporter = new XMLExporter();
+ return xmlWriter.writeTree(_grid);
}
/**
- * Loads a tree from xml, deleting any previous states
+ * Loads a tree/matrix from xml, deleting any previous states
*/
- public function loadTreeFromXML(xml:XML):void
+ public function loadFromXML(xml:XML):void
{
- _actionHandler.load(xml, _grid);
- isZeroSum = false;
+ //TODO #33 check what type of data is inside the xml
+ loadTreeFromXML(xml);
+
invalidate(true, true, true);
}
+ private function loadTreeFromXML(xml:XML):void
+ {
+ _treeActionHandler.load(xml, _grid);
+ isZeroSum = false;
+ }
+
+ //TODO #33 loadMatrixFromXML
+
/**
- * Opens a dialog for selecting and opening a tree in xml format
+ * Opens a dialog for selecting and opening a file in xml format
*/
public function open():void
{
@@ -569,6 +573,8 @@ package lse.math.games.builder.presenter
// URL Request Handler below here...
public function runAlgorithm(algo:Object, seed:String):void
+ //TODO #33: Although the functionality should be the same, depending on the nf or ef mode,
+ //the data for running the algo might need to be generated
{
if (algo == null || algo.service == null || algo.service == undefined
|| algo.url == null || algo.url == undefined) {
@@ -603,8 +609,8 @@ package lse.math.games.builder.presenter
private function getTreeParam():String
{
- var xmlWriter:ExtensiveFormXMLWriter = new ExtensiveFormXMLWriter();
- var treeXML:XML = xmlWriter.write(_grid);
+ var xmlWriter:XMLExporter = new XMLExporter();
+ var treeXML:XML = xmlWriter.writeTree(_grid);
XML.prettyPrinting = false;
var value:String = treeXML.toXMLString();
XML.prettyPrinting = true;
diff --git a/gui-builder/src/lse/math/games/builder/settings/FileSettings.as b/gui-builder/src/lse/math/games/builder/settings/FileSettings.as
new file mode 100644
index 0000000..86a473e
--- /dev/null
+++ b/gui-builder/src/lse/math/games/builder/settings/FileSettings.as
@@ -0,0 +1,123 @@
+package lse.math.games.builder.settings
+{
+ import flash.errors.IllegalOperationError;
+
+ import mx.controls.Alert;
+
+ /**
+ * This class stores the file in use's settings.
+ *
+ * It is a singleton, and instead of calling the constructor directly, you
+ * should use FileSettings.instance.
+ *
+ * Instructions:
+ *
+ *
Check that a setting is stored using hasValue.
+ *
Store and access run-time values of the settings using getValue and setValue functions.
+ *
Delete all settings with clear() everytime you close a file (or open a new one)
+ *
Set these settings as the default ones with setAsDefault()
+ *
+ *
+ * @see SCodes SCodes - For reference on the actual Settings that there exist
+ * @see Settings Settings - for the graphic settings editor, and how to add new settings
+ *
+ * @author alfongj
+ */
+ public class FileSettings
+ {
+ private static var _instance:FileSettings = null;
+
+ private var data:Object;
+
+ /**
+ * DO NOT CALL THE CONSTRUCTOR DIRECTLY, INSTEAD USE FileSettings.instance
+ * This acts like a private constructor
+ */
+ public function FileSettings( lock:Class ){
+ if( lock != FileSettingsSingletonLock ){
+ throw new IllegalOperationError( "Settings is a Singleton, please use the static instance method instead." );
+ } else {
+ clear();
+ }
+ }
+
+ /**
+ * The Singleton instance of the Settings to use when accessing properties and methods of the Settings.
+ */
+ public static function get instance():FileSettings
+ {
+ if(_instance == null)
+ {
+ _instance = new FileSettings(FileSettingsSingletonLock);
+ }
+
+ return _instance;
+ }
+
+
+ /** Returns true if it contains value for a specified key */
+ public function hasValue( key:Object ):Boolean {
+ return data.hasOwnProperty(key);
+ }
+
+ /**
+ * Retrieves a value in the settings by the specified key.
+ *
+ * @param key (Object) the key that the desired setting data was saved under
+ * @return (Object) returns the data saved by key
+ */
+ public function getValue( key:Object ):Object {
+ return data[key];
+ }
+
+ /**
+ * Saves a value into the settings under the specified key.
+ *
+ * @param key (String) the key under which to save the value
+ * @param value (Object) the value to be saved
+ */
+ public function setValue( key:String, value:Object ):void {
+ data[key] = value;
+ }
+
+
+
+ /** Clears the settings. Should be called when a new file is opened */
+ public function clear():void
+ {
+ data = new Object();
+ loadDefaults();
+ }
+
+ /* Loads all stored values from user's local 'flash cookies' */
+ private function loadDefaults():void
+ {
+ var defSettings:UserSettings = UserSettings.instance;
+
+ defSettings.getValue("dummy"); //Run this in case defSettings are not loaded
+
+ for(var key:String in defSettings.data)
+ {
+ if(key.indexOf("DEFAULT")==0)
+ {
+ var newKey:String = "FILE"+key.substr(7);
+ data[newKey] = defSettings.data[key];
+ }
+ }
+ }
+
+ /** Sets the current file settings as the default ones */
+ public function setAsDefault():void
+ {
+ var defSettings:UserSettings = UserSettings.instance;
+ for(var key:String in data)
+ {
+ var defKey:String = "DEFAULT"+key.substr(4);
+ defSettings.setValue( defKey, data[key] );
+ }
+ }
+ }
+}
+
+//Dummy private class for making the constructor artificially private
+class FileSettingsSingletonLock {}
\ No newline at end of file
diff --git a/gui-builder/src/lse/math/games/builder/settings/SCodes.as b/gui-builder/src/lse/math/games/builder/settings/SCodes.as
index bf6c9e7..e3b76a0 100644
--- a/gui-builder/src/lse/math/games/builder/settings/SCodes.as
+++ b/gui-builder/src/lse/math/games/builder/settings/SCodes.as
@@ -3,10 +3,10 @@ package lse.math.games.builder.settings
/**
* Enum containing each Setting code, with a brief description of what the associated content should be and mean.
*
- * When adding a new setting, its key inside UserSettings.as and Settings.mxml
+ * When adding a new setting, its key inside UserSettings.as / FileSetting.as and Settings.mxml
* must be the same and taken from here, for reference purposes
*
- * You can call defaultSettings() to load a default value for each setting
+ * You can call defaultSettings() to load a default value for each setting (except from File Settings)
*/
public final class SCodes
{
@@ -16,37 +16,106 @@ package lse.math.games.builder.settings
*
false: Settings are discarded once the user closes the browser window
*
Default: false
*/
- public static var STORE_SETTINGS_LOCALLY:String = "STORE_SETTINGS_LOCALLY";
+ public static const STORE_SETTINGS_LOCALLY:String = "STORE_SETTINGS_LOCALLY";
/**
*
true: The output after running an algo, instead of in an external pop-up, will be shown in an internal flash one
*
false: The output will be shown in a browser pop-up
*
Default: false
*/
- public static var DISPLAY_OUTPUT_INTERNALLY:String = "DISPLAY_OUTPUT_INTERNALLY";
+ public static const DISPLAY_OUTPUT_INTERNALLY:String = "DISPLAY_OUTPUT_INTERNALLY";
- /* <--- GRAPHIC SETTINGS ---> */
+ /**
+ * int containing the number of undoable actions, at least, that the user would like to keep
+ *
Default: 10
+ */
+ public static const MINIMUM_BUFFER_SIZE:String = "MINIMUM_BUFFER_SIZE";
+
+
+
+ /* <--- DEFAULT GRAPHIC SETTINGS (applied to trees with no graphic information) ---> */
/**
* uint with player 1's color
*
Default: Red
*/
- public static var PLAYER_1_COLOR:String = "PLAYER_1_COLOR";
+ public static const DEFAULT_PLAYER_1_COLOR:String = "DEFAULT_PLAYER_1_COLOR";
/**
* uint with player 2's color
*
Default: Blue
*/
- public static var PLAYER_2_COLOR:String = "PLAYER_2_COLOR";
+ public static const DEFAULT_PLAYER_2_COLOR:String = "DEFAULT_PLAYER_2_COLOR";
/**
* String with the default font family to be used
*
Default: Times
*/
- public static var DEFAULT_FONT:String = "DEFAULT_FONT";
- //It is called DEFAULT because in the future there might be also more specific ones, such as payoff_font or player_font
- //and then this one will be the used in whatever's not got a specific one
+ public static const DEFAULT_FONT:String = "DEFAULT_FONT";
+
+ /**
+ * Number representing the width of the strokes of lines for drawing isets and moves
+ *
Default: 1.0
+ */
+ public static const DEFAULT_STROKE_WIDTH:String = "DEFAULT_STROKE_WIDTH";
+
+ /**
+ * int representing the diameter of nodes
+ *
Default: 7
+ */
+ public static const DEFAULT_NODE_DIAMETER:String = "DEFAULT_NODE_DIAMETER";
+
+ /**
+ * Number representing the diameter of isets
+ *
Default: 25
+ */
+ public static const DEFAULT_ISET_DIAMETER:String = "DEFAULT_ISET_DIAMETER";
+
+ /**
+ * int representing the distance between two consecutive node levels
+ *
Default: 75
+ */
+ public static const DEFAULT_LEVEL_DISTANCE:String = "DEFAULT_LEVEL_DISTANCE";
+
+
+
+ /* <--- FILE GRAPHIC SETTINGS (settings not stored in the users PC but on XML files. Loaded with FileSettings) ---> */
+ //NOTE: All of these must have their "DEFAULT_" counterpart, else FileSettings.setAsDefault() will need to be modified
+ /** uint with player 1's color */
+ public static const FILE_PLAYER_1_COLOR:String = "FILE_PLAYER_1_COLOR";
+
+ /** uint with player 2's color */
+ public static const FILE_PLAYER_2_COLOR:String = "FILE_PLAYER_2_COLOR";
+
+ /** String with the FILE font family to be used */
+ public static const FILE_FONT:String = "FILE_FONT";
+
+ /** int representing the width of the strokes of lines for drawing isets and moves */
+ public static const FILE_STROKE_WIDTH:String = "FILE_STROKE_WIDTH";
+
+ /** Number representing the diameter of nodes */
+ public static const FILE_NODE_DIAMETER:String = "FILE_NODE_DIAMETER";
+
+ /** Number representing the diameter of isets */
+ public static const FILE_ISET_DIAMETER:String = "FILE_ISET_DIAMETER";
+
+ /** int representing the distance between two consecutive node levels */
+ public static const FILE_LEVEL_DISTANCE:String = "FILE_LEVEL_DISTANCE";
+
+
+
+
+ /* <--- OTHER SETTINGS (Not shown under the Settings panel) ---> */
+
+ /**
+ * Boolean with the current expand status of the webcontainer of the GUI
+ *
Default: False
+ */
+ public static const EXPANDED:String = "EXPANDED";
+
+ /* <--- DEFAULT SETTINGS ---> */
+
/** Creates a default entry for each setting that a UserSetting object should have*/
public static function defaultSettings():void
{
@@ -55,12 +124,17 @@ package lse.math.games.builder.settings
//GENERAL SETTINGS
settings.setValue(STORE_SETTINGS_LOCALLY, false);
settings.setValue(DISPLAY_OUTPUT_INTERNALLY, false);
+ settings.setValue(MINIMUM_BUFFER_SIZE, 10);
//GRAPHIC SETTINGS
- settings.setValue(PLAYER_1_COLOR, 0xFF0000);
- settings.setValue(PLAYER_2_COLOR, 0x0000FF);
+ settings.setValue(DEFAULT_PLAYER_1_COLOR, 0xFF0000);
+ settings.setValue(DEFAULT_PLAYER_2_COLOR, 0x0000FF);
settings.setValue(DEFAULT_FONT, "Times");
-
-
+ settings.setValue(DEFAULT_STROKE_WIDTH, 1);
+ settings.setValue(DEFAULT_NODE_DIAMETER, new Number(7));
+ settings.setValue(DEFAULT_ISET_DIAMETER, new Number(25));
+ settings.setValue(DEFAULT_LEVEL_DISTANCE, 75);
+ //OTHER SETTINGS
+ settings.setValue(EXPANDED, false);
}
}
}
\ No newline at end of file
diff --git a/gui-builder/src/lse/math/games/builder/settings/Settings.mxml b/gui-builder/src/lse/math/games/builder/settings/Settings.mxml
index 852d72a..b7b97bd 100644
--- a/gui-builder/src/lse/math/games/builder/settings/Settings.mxml
+++ b/gui-builder/src/lse/math/games/builder/settings/Settings.mxml
@@ -25,7 +25,7 @@
*
Set the id of the color picker/toggle/textinput... to the same as the identifier that you defined earlier
*
Set the 'creationComplete' hanler to get the property of the item (e.g., 'selectedColor', 'selected', etc)
* with settings.getValue(SCodes.THE_ID_YOU_CREATED) as WhateverTypeItShouldBe
- *
Set the 'change' behaviour of your setting, which will normally just be setSetting(SCodes.THE_ID_YOU_CREATED,
+ *
Set the 'change' behaviour of your setting, which will normally just be setGlobalSetting/setFileSetting(SCodes.THE_ID_YOU_CREATED,
* THE_ID_YOU_CREATED.valueYouReInterestedIn)
*
*
Finally, don't forget to use your settings value wherever you need it with
@@ -40,7 +40,8 @@
private var unsavedChanges:Boolean = false;
- private var settings:UserSettings = UserSettings.instance;
+ private var glbSettings:UserSettings = UserSettings.instance;
+ private var fileSettings:FileSettings = FileSettings.instance;
private var _controller:TreeGridPresenter;
private var log:Log = Log.instance;
@@ -49,35 +50,56 @@
public function set controller(value:TreeGridPresenter):void { _controller = value; }
- //Sets a setting
- private function setSetting(key:String, value:Object):void
+ //Sets a global setting
+ private function setGlobalSetting(key:String, value:Object):void
{
if(!unsavedChanges)
{
- if(settings.getValue(key) == null)
+ if(glbSettings.getValue(key) == null)
unsavedChanges = true;
- else if(settings.getValue(key) != value)
+ else if(glbSettings.getValue(key) != value)
unsavedChanges = true;
}
- settings.setValue(key, value);
+ glbSettings.setValue(key, value);
+
+ //invalidate display
+ if(_controller != null)
+ _controller.invalidate(true, true, true);
+ else
+ log.add(Log.ERROR_HIDDEN, "No controller defined ", "Settings");
+ }
+
+ //Sets a file setting
+ private function setFileSetting(key:String, value:Object):void
+ {
+ fileSettings.setValue(key, value);
+
+ //invalidate display
+ if(_controller != null)
+ _controller.invalidate(true, true, true);
+ else
+ log.add(Log.ERROR_HIDDEN, "No controller defined ", "Settings");
}
-
+
+ //Sets the file settings as default and closes
+ private function setFileSettingsAsDefaultAndExit():void
+ {
+ fileSettings.setAsDefault();
+ if(_controller != null)
+ _controller.invalidate(true, true, true);
+ else
+ log.add(Log.ERROR_HIDDEN, "No controller defined ", "Settings");
+
+ unsavedChanges = true;
+ exit();
+ }
+
//Saves settings if necessary, and closes the settings panel
private function exit():void
{
- if(unsavedChanges)
- {
- //invalidate display
- if(_controller != null)
- _controller.invalidate(true, true, true);
- else
- log.add(Log.ERROR_HIDDEN, "No controller defined ", "Settings");
-
- //Store settings locally if the preference is activated
- if(settings.getValue(SCodes.STORE_SETTINGS_LOCALLY) as Boolean && settings.cookiesStorable && !settings.saveCookies())
- throw new Error("Couldn't store the cookies, please retry");
- }
+ if(unsavedChanges)
+ glbSettings.saveCookiesIfPossible();
PopUpManager.removePopUp(this);
}
@@ -95,68 +117,83 @@
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
-
+
+ change="setFileSetting(SCodes.FILE_PLAYER_2_COLOR,event.target.selectedColor);"/>
-
+ change="setFileSetting(SCodes.FILE_FONT, FILE_FONT.selectedItem);">
-
+
@@ -169,18 +206,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/gui-builder/src/lse/math/games/builder/settings/UserSettings.as b/gui-builder/src/lse/math/games/builder/settings/UserSettings.as
index 31e4a71..8788e13 100644
--- a/gui-builder/src/lse/math/games/builder/settings/UserSettings.as
+++ b/gui-builder/src/lse/math/games/builder/settings/UserSettings.as
@@ -5,7 +5,7 @@ package lse.math.games.builder.settings
import flash.system.Security;
import util.Log;
-
+
/**
* This class stores user settings, and can dump them to a local 'cookie-like'
* shared object, if the user allows local flash storage.
@@ -32,7 +32,7 @@ package lse.math.games.builder.settings
private const FILENAME:String = "settings";
- private var data:Object;
+ private var _data:Object;
private var _settings_RSO:SharedObject = null;
private var _loaded:Boolean = false;
@@ -49,7 +49,7 @@ package lse.math.games.builder.settings
throw new IllegalOperationError( "Settings is a Singleton, please use the static instance method instead." );
} else {
_settings_RSO = SharedObject.getLocal( FILENAME, "/" );
- data = new Object();
+ _data = new Object();
}
}
@@ -66,11 +66,8 @@ package lse.math.games.builder.settings
return _instance;
}
- /** If the settings have been loaded from local storage */
- public function get loaded():Boolean
- {
- return _loaded;
- }
+ /* Returns the data array, necessary for loading defaults in FileSettings */
+ internal function get data():Object {return _data;}
/**
* Retrieves a value in the settings by the specified key.
@@ -81,7 +78,7 @@ package lse.math.games.builder.settings
public function getValue( key:Object ):Object {
if(!_loaded)
firstLoad();
- return data[key];
+ return _data[key];
}
/**
@@ -91,7 +88,9 @@ package lse.math.games.builder.settings
* @param value (Object) the value to be saved
*/
public function setValue( key:String, value:Object ):void {
- data[key] = value;
+ if(!_loaded)
+ firstLoad();
+ _data[key] = value;
}
/**
@@ -122,10 +121,26 @@ package lse.math.games.builder.settings
{
if(_loaded)
log.add(Log.ERROR_HIDDEN, "Warning: Non-saved settings are potentially being overwriting ");
+
+ var prevLoadedStatus:Boolean = _loaded;
+
+ _loaded = true; //this should be here, else we enter an infinite loop
SCodes.defaultSettings();
+ _loaded = prevLoadedStatus; //Now we restore to the previous status
loadCookies();
}
+ /* Loads all stored values from user's local 'flash cookies' */
+ private function loadCookies():void
+ {
+ for(var key:String in _settings_RSO.data)
+ {
+ _data[key] = _settings_RSO.data[key];
+ }
+
+ _loaded = true;
+ }
+
/**
* Checks if user allows 'cookies' storage, and if there is space available.
* If there isn't, it prompts the user to accept them
@@ -138,28 +153,34 @@ package lse.math.games.builder.settings
Security.showSettings();
}
- /** Loads all stored values from user's local 'flash cookies' */
- public function loadCookies():void
+ /**
+ * Saves cookies if the preference is activated, and if cookies are storable.
+ * @return True if they are saved correctly.
+ */
+ public function saveCookiesIfPossible():Boolean
{
- for(var key:String in _settings_RSO.data)
+ var saved:Boolean = false;
+ if(getValue(SCodes.STORE_SETTINGS_LOCALLY) as Boolean && cookiesStorable)
{
- data[key] = _settings_RSO.data[key];
+ saved = saveCookies();
+ if(!saved)
+ log.add(Log.ERROR, "Couldn't store the cookies for an unknown error, please retry");
}
- _loaded = true;
+ return saved;
}
- /**
+ /*
* Saves all stored values onto user's local 'flash cookies'.
*
* @return (Boolean) true if the values were successfully saved
*/
- public function saveCookies():Boolean
+ private function saveCookies():Boolean
{
- for(var key:String in data)
+ for(var key:String in _data)
{
- _settings_RSO.setProperty( key, data[key] );
- if(_settings_RSO.data[key] != data[key])
+ _settings_RSO.setProperty( key, _data[key] );
+ if(_settings_RSO.data[key] != _data[key])
return false;
}
diff --git a/gui-builder/src/lse/math/games/builder/view/Main.mxml b/gui-builder/src/lse/math/games/builder/view/Main.mxml
index eab520f..859ffdf 100644
--- a/gui-builder/src/lse/math/games/builder/view/Main.mxml
+++ b/gui-builder/src/lse/math/games/builder/view/Main.mxml
@@ -37,7 +37,6 @@
public var xfalgos:Array = new Array();
//TODO: If possible, move the folowing two to the
- [Bindable]
private var log:Log = Log.instance;
[Bindable]
@@ -45,10 +44,36 @@
private var fileManager:FileManager;
private var eventManager:EventManager = EventManager.instance;
- private var settings:UserSettings = UserSettings.instance;
+ private var settings:UserSettings = UserSettings.instance;
-
+
+ /* <--- --- TOOLBARS-RELATED FUNCTIONS --- ---> */
+
+ //Executes the clear() function from the TreeGridController, epending on the button pressed as a result of the prompt
+ private function clearDependingOnPromptResult():void
+ {
+ if(PromptTwoButtons.buttonPressed == PromptTwoButtons.OK)
+ controller.clear();
+ }
+
+ //Pops up the -internal or external- output window
+ private function showOutput(text:String):void {
+ if (ExternalInterface.available && !settings.getValue(SCodes.DISPLAY_OUTPUT_INTERNALLY) as Boolean) {
+ ExternalInterface.call('writeSolution', text);
+ log.add(Log.HINT, "You don't see the output? Then you must allow popups " +
+ "in your browser. Don't forget to save your changes before. Or you could " +
+ "activate the 'Display output internally' setting in the Settings panel.");
+ }
+ else {
+ var o:OutputWindow = new OutputWindow();
+ PopUpManager.addPopUp(o, this, false);
+ o.setText(text);
+ PopUpManager.centerPopUp(o);
+ }
+ }
+
+ //Populates from the external html container's params the list of algos
private function initVars():void
{
// FOR TESTING ONLY... comment this and uncomment one below before building for prod
@@ -88,43 +113,34 @@
}
}
- // Handles click on the canvas
- private function handleClickOnCanvas():void
- {
- if(opModeBar2.selectedIndex <= 7)
- controller.doActionAt(canvas.mouseX, canvas.mouseY);
- else
- treePainter.selectAndEdit(controller, canvas.mouseX, canvas.mouseY);
- }
-
-
-
- /* <--- --- TOOLBARS-RELATED FUNCTIONS --- ---> */
-
//Pops up the settings edition window
private function showSettings():void
{
var s:Settings = new Settings();
s.controller = controller;
- PopUpManager.addPopUp(s, this, true);
+ PopUpManager.addPopUp(s, this, false);
PopUpManager.centerPopUp(s);
}
- //Pops up the -internal or external- output window
- private function showOutput(text:String):void {
- if (ExternalInterface.available && !settings.getValue(SCodes.DISPLAY_OUTPUT_INTERNALLY) as Boolean) {
- ExternalInterface.call('writeSolution', text);
- log.add(Log.HINT, "You don't see the output? Then you must allow popups " +
- "in your browser. Don't forget to save your changes before. Or you could " +
- "activate the 'Display output internally' setting in the Settings panel.");
- }
- else {
- var o:OutputWindow = new OutputWindow();
- PopUpManager.addPopUp(o, this, false);
- PopUpManager.centerPopUp(o);
- o.height = canvas.height-50;
- o.setText(text);
- }
+ [Bindable]
+ private var expanded:Boolean = false;
+
+ //Checks the expand setting, and updates the 'expanded' var & the webcontainer accordingly
+ private function updateExpandStatus():void
+ {
+ expanded = settings.getValue(SCodes.EXPANDED) as Boolean;
+ ExternalInterface.call("expand", expanded);
+ updateLogLineDimensions();
+ }
+
+ //Should be called from the expand button, and changes the expand status, updating everything
+ private function switchExpandStatus():void
+ {
+ expanded = !expanded;
+ settings.setValue(SCodes.EXPANDED, expanded);
+ settings.saveCookiesIfPossible();
+ ExternalInterface.call("expand", expanded);
+ updateLogLineDimensions();
}
//Return the action corresponding to the button pressed in opModeBar2
@@ -169,11 +185,17 @@
}
}
- //Executes the clear() function from the TreeGridController, epending on the button pressed as a result of the prompt
- private function clearDependingOnPromptResult():void
+
+
+ /* <--- --- CANVAS-RELATED FUNCTIONS --- ---> */
+
+ // Handles click on the canvas
+ private function handleClickOnCanvas():void
{
- if(PromptTwoButtons.buttonPressed == PromptTwoButtons.OK)
- controller.clear();
+ if(opModeBar2.selectedIndex <= 7)
+ controller.doActionAt(canvas.mouseX, canvas.mouseY);
+ else
+ treePainter.selectAndEdit(controller, canvas.mouseX, canvas.mouseY);
}
@@ -188,22 +210,35 @@
private var lastLogLineTimeoutId:int = -1;
- //Updates the LogLine with the text from
+ //Updates the LogLine with the text from a HINT event
private function updateLogLine(evt:TextEvent):void
{
logLine.text = evt.text;
if(lastLogLineTimeoutId != -1)
clearTimeout(lastLogLineTimeoutId);
- var optimalMsForReading:int = Math.max(3000, 1000+evt.text.length*67);
+ var optimalMsForReading:int = Math.max(3000, evt.text.length*67);
//These ms are calculated from average lowest reading speed in english (200 wpm)
- //and average of letters per word in english (4.5), plus two extra sources of extra
- //time: counting the non-letter characters as letters, and giving one sec at the start for noticing
- //there is something written.
+ //and average of letters per word in english (4.5), plus a source of extra
+ //time: counting the non-letter characters as letters
lastLogLineTimeoutId = setTimeout(clearLogLine, optimalMsForReading);
}
+ //Changes the dimensions according to the expanded status
+ private function updateLogLineDimensions():void
+ {
+ if(expanded)
+ {
+ logLineContainer.left = 1;
+ logLineContainer.right = 1;
+ } else
+ {
+ logLineContainer.left = 0;
+ logLineContainer.right = 0;
+ }
+ }
+
//Erases the logLine text
private function clearLogLine():void {
lastLogLineTimeoutId = -1;
@@ -329,6 +364,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -403,6 +488,7 @@
+
@@ -411,48 +497,13 @@
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gui-builder/src/lse/math/games/builder/view/OutputWindow.mxml b/gui-builder/src/lse/math/games/builder/view/OutputWindow.mxml
index 99ad4f8..5fdf93c 100644
--- a/gui-builder/src/lse/math/games/builder/view/OutputWindow.mxml
+++ b/gui-builder/src/lse/math/games/builder/view/OutputWindow.mxml
@@ -1,12 +1,13 @@
maxLength) maxLength = line.length;
+ }
+
+ this.width = Math.max(200, maxLength*7+100);
+ this.height = Math.min(parent.height - 150, 14*textInLines.length + 70);
}
protected function closeHandler(event:CloseEvent):void
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/MatrixInput.as b/gui-builder/src/lse/math/games/builder/viewmodel/MatrixInput.as
deleted file mode 100644
index dfc02b5..0000000
--- a/gui-builder/src/lse/math/games/builder/viewmodel/MatrixInput.as
+++ /dev/null
@@ -1,333 +0,0 @@
-package lse.math.games.builder.viewmodel
-{
- //TODO: Remove unnecesary ones
- import flash.utils.Dictionary;
-
- import lse.math.games.builder.model.ExtensiveForm;
- import lse.math.games.builder.model.Iset;
- import lse.math.games.builder.model.Move;
- import lse.math.games.builder.model.Node;
- import lse.math.games.builder.model.Outcome;
- import lse.math.games.builder.model.Player;
- import lse.math.games.builder.model.Rational;
-
- import mx.controls.Alert;
-
- /**
- * This class handles the input of a Tree in Strategic Form via text editing the payoff matrixes of the players
- * TODO: Change the current functions (taken from ExtFormXMLReader) and use them as necessary
- * TODO: Complete all functionality
- * TODO: Try to make it for more than 2 players. If not, wirte a to-do alerting it
- * TODO: It must throw an action, or be handled by an action or something, that can be undone
- *
- * @author alfongj
- */
- public class MatrixInput
- {
- /*private var nodes:Dictionary;
- private var isets:Dictionary;
- private var isetObjToId:Dictionary;
- private var singletons:Vector.;
- private var moves:Dictionary;
- private var players:Dictionary;
-
- private var xml:XML = null;
- private var tree:ExtensiveForm = null;
-
- public function MatrixInput(xml:XML)
- {
- //TODO
- this.xml = xml;
- }
-
- public function load(tree:ExtensiveForm):ExtensiveForm
- {
- //TODO
- this.tree = tree;
- tree.clearTree();
-
- nodes = new Dictionary();
- isets = new Dictionary();
- isetObjToId = new Dictionary();
- singletons = new Vector.();
- moves = new Dictionary();
- players = new Dictionary();
-
- for each(var child:XML in xml.children()) {
- if (child.name() == "iset") {
- processIset(child);
- } else if (child.name() == "node") {
- processNode(child, null);
- } else if (child.name() == "outcome") {
- processOutcome(child, null);
- } else {
- trace("Ignoring unknown element:\r\n" + child);
- }
- }
-
- var iset:Iset = null;
- for (var isetId:String in isets) {
- iset = isets[isetId] as Iset;
- if (iset != tree.root.iset) {
- tree.addIset(iset);
- }
- }
- for each (iset in singletons) {
- if (iset != tree.root.iset) {
- tree.addIset(iset);
- }
- }
-
- hookupAndVerifyMoves();
-
- return tree;
- }
-
- //there has got to be a more efficient algorithm
- private function hookupAndVerifyMoves():void
- {
- //TODO
- for (var iset:Iset = tree.root.iset; iset != null; iset = iset.nextIset) {
-
- iset.sort();
-
- //for each child of the first node, hook up move
- var baseline:Node = iset.firstNode;
- for (var baselineChild:Node = baseline.firstChild, childIdx:int = 0; baselineChild != null; baselineChild = baselineChild.sibling, ++childIdx)
- {
- iset.assignMove(baselineChild.reachedby);
-
- // make sure all the rest of the nodes have the child with the same move
- // TODO: it does not necessarily need to be at the same index
- for (var baselineMate:Node = baseline.nextInIset; baselineMate != null; baselineMate = baselineMate.nextInIset)
- {
- var mateChild:Node = baselineMate.firstChild;
- for (var i:int = 0; i < childIdx; ++i) {
- mateChild = mateChild.sibling;
- }
- if (mateChild.reachedby != baselineChild.reachedby) {
- if (mateChild.reachedby == null) {
- throw new Error("node does not contain an incoming move");
- } else {
- throw new Error("Iset " + iset.idx + " is inconsistent for node " + baselineMate.number /*+ " at " + baselineMate.setIdx*/ + " for child " + mateChild.number + " at " + childIdx + " with move " + mateChild.reachedby);
- }
- }
- }
- }
- }
- }
-
- private function getPlayer(playerId:String):Player
- {
- //TODO
- if (playerId == Player.CHANCE_NAME) {
- return Player.CHANCE;
- }
-
- var player:Player = players[playerId];
- if (player == null) {
- player = new Player(playerId, tree);
- players[playerId] = player;
- }
- return player;
- }
-
- private function processIset(elem:XML):void
- {
- //TODO
- var id:String = elem.@id;
- var iset:Iset = isets[id];
-
- if (iset == null) {
- var player:Player = (elem.@player != undefined) ? getPlayer(elem.@player) : Player.CHANCE;
- iset = new Iset(player, tree);
- isets[id] = iset;
- isetObjToId[iset] = id;
- }
-
- for each (var child:XML in elem.children())
- {
- if (child.name() == "node") {
- processNode(child, null);
- } else {
- trace("Ignoring unknown element:\r\n" + child);
- }
- }
- }
-
- private function processNode(elem:XML, parentNode:Node):void
- {
- //TODO
- //init
- var node:Node = null;
- if (elem.@id != undefined)
- {
- var id:String = elem.@id;
- node = nodes[id];
-
- if (node == null) {
- trace("XMLReader: creating new node " + id);
- node = tree.createNode();
- nodes[id] = node;
- } else {
- trace("XMLReader: processing previously created node " + id);
-
- }
- } else {
- node = tree.createNode();
- }
-
- //assign parent
- if (parentNode == null && elem.@parent != undefined)
- {
- var parentId:String = elem.@parent;
- parentNode = nodes[parentId];
-
- if (parentNode == null) {
- parentNode = tree.createNode();
- nodes[parentId] = parentNode;
- }
- }
- if (parentNode != null) {
- parentNode.addChild(node);
- } else {
- tree.root = node;
- }
-
- // process iset
- var isetId:String = null;
- if (elem.parent() != null && elem.parent().name() == "iset") {
- isetId = elem.parent().@id;
- if (elem.@iset != undefined) trace("Warning: @iset attribute is set for a node nested in an iset tag. Ignored.");
- } else if (elem.@iset != undefined) {
- isetId = elem.@iset;
- }
-
- var iset:Iset = null;
- var player:Player = (elem.@player != undefined) ? getPlayer(elem.@player) : Player.CHANCE;
- if (isetId == null) {
- iset = new Iset(player, tree);
- singletons.push(iset); // root is already taken care of
- } else {
- //look it up in the map, if it doesn't exist create it and add it
- iset = isets[isetId];
- if (iset == null) {
- iset = new Iset(player, tree);
- isets[isetId] = iset;
- isetObjToId[iset] = isetId;
- } else {
- if (player != Player.CHANCE) {
- if (iset.player != Player.CHANCE && player != iset.player) {
- trace("Warning: @player attribute conflicts with earlier iset player assignment. Ignored.");
- }
- while (iset.player != player) {
- iset.changePlayer(tree.firstPlayer);
- }
- }
- }
- }
- iset.insertNode(node);
-
- // set up the moves
- processMove(elem, node, parentNode);
-/* if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parentNode != null && parentNode.iset != null) ? String(parentNode.iset.idx) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
-
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- node.reachedby = move;
- } else if (parentNode != null) {
- // assume this comes from a chance node with a probability of zero
- node.reachedby = new Move();
- }
-
- if (elem.@prob != undefined && node.reachedby != null) {
- node.reachedby.prob = Rational.parse(elem.@prob);
- }
-*/
- for each (var child:XML in elem.children()) {
- if (child.name() == "node") {
- processNode(child, node);
- } else if (child.name() == "outcome") {
- processOutcome(child, node);
- } /*else {
- trace("Ignoring unknown element:\r\n" + child);
- }*/
- }
- }
-
- private function processOutcome(elem:XML, parent:Node):void
- {
- //TODO
- // Create wrapping node
- // get parent from dictionary... if it doesn't exist then the outcome must be the root
- var wrapNode:Node = parent != null ? parent.newChild() : tree.createNode();
- if (parent == null) {
- tree.root = wrapNode;
- }
-
- // set up the moves
- processMove(elem, wrapNode, parent);
- /* if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parent != null && parent.iset != null) ? String(parent.iset.idx) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- wrapNode.reachedby = move;
- }
-
- if (elem.@prob != undefined && wrapNode.reachedby != null) {
- wrapNode.reachedby.prob = Rational.parse(elem.@prob);
- }*/
-
- var outcome:Outcome = wrapNode.makeTerminal();
- for each (var child:XML in elem.children()) {
- if (child.name() == "payoff") {
- var playerId:String = child.@player;
- var payoff:Rational = Rational.parse(child.@value);
-
- var player:Player = players[playerId];
- if (player == null) {
- player = new Player(playerId, tree);
- players[playerId] = player;
- }
- outcome.setPay(player, payoff);
- } /*else {
- trace("Ignoring unknown element:\r\n" + child);
- }*/
- }
- }
-
- private function processMove(elem:XML, node:Node, parent:Node):void
- {
- //TODO
- if (elem.@move != undefined) {
- var moveId:String = elem.@move;
- var moveIsetId:String = (parent != null && parent.iset != null) ? String(isetObjToId[parent.iset]) : "";
- var move:Move = moves[moveIsetId + "::" + moveId];
- if (move == null) {
- move = new Move();
- move.label = moveId;
- moves[moveIsetId + "::" + moveId] = move;
- }
- node.reachedby = move;
- } else if (parent != null) {
- // assume this comes from a chance node with a probability of zero
- node.reachedby = new Move();
- }
-
- if (elem.@prob != undefined && node.reachedby != null) {
- node.reachedby.prob = Rational.parse(elem.@prob);
- }
- } */
- }
-}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/MatrixPainter.as b/gui-builder/src/lse/math/games/builder/viewmodel/MatrixPainter.as
index bcff9ac..d04d460 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/MatrixPainter.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/MatrixPainter.as
@@ -106,7 +106,7 @@ package lse.math.games.builder.viewmodel
g.fillRect(0, 0, width, height);
g.color = 0x000000;
- g.stroke = this.scale * _grid.linewidth;
+ g.stroke = this.scale * _grid.strokeWidth;
paintMatrix(g, width, height, nf);
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGrid.as b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGrid.as
index f1af183..50f653d 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGrid.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGrid.as
@@ -3,6 +3,7 @@ package lse.math.games.builder.viewmodel
import lse.math.games.builder.model.ExtensiveForm;
import lse.math.games.builder.model.Iset;
import lse.math.games.builder.model.Node;
+ import lse.math.games.builder.settings.FileSettings;
import lse.math.games.builder.settings.SCodes;
import lse.math.games.builder.settings.UserSettings;
@@ -22,10 +23,7 @@ package lse.math.games.builder.viewmodel
* @author Mark Egesdal
*/
public class TreeGrid extends ExtensiveForm
- {
- public static const NODE_DIAM:Number = 7; //TODO: SETTING
- public static const ISET_DIAM:Number = 25; //TODO: SETTING
-
+ {
//TODO: Let rotation adjust these margins... or at least account
//for the label sizes in the min measurements
public static const MIN_MARGIN_TOP:Number = 24;
@@ -35,18 +33,15 @@ package lse.math.games.builder.viewmodel
public var scale:Number = 1.0; //Current scale of the canvas
private var _rotate:int = 0;
- private var _leveldistance:int;
- private var _linewidth:Number;
- private var _ovallinewidth:Number;
private var _mergeBase:Iset = null;
private var _selectedNodeId:int = -1;
private var _isZeroSum:Boolean = true;
private var _isNormalReduced:Boolean = true;
- private var _maxPayoff:Number = 25; //TODO: PREFERENCE
+ private var _maxPayoff:Number = 25; //TODO: SETTING
- private var userSettings:UserSettings = UserSettings.instance;
+ private var fileSettings:FileSettings = FileSettings.instance;
private var log:Log = Log.instance;
@@ -54,12 +49,8 @@ package lse.math.games.builder.viewmodel
public function TreeGrid()
{
defaultTree();
- defaultSettings();
}
- //TODO: For all settings that can be chosen either from userSettings or from currentTreeSettings,
- //the getters should be the ones that control from which of the sources they return
-
/** Direction of the tree, being 0 root-up, 1 root-left, 2 root-down, 3 root-right */
public function get rotate():int { return _rotate; }
public function set rotate(value:int):void
@@ -72,14 +63,32 @@ package lse.math.games.builder.viewmodel
_rotate = value;
}
+ /* <--- --- GRAPHIC SETTINGS GETTERS --- ---> */
+
+ /** Color of nodes, labels and payoffs of the first player */
+ public function get player1Color():uint { return fileSettings.getValue(SCodes.FILE_PLAYER_1_COLOR) as uint; }
+
+ /** Color of nodes, labels and payoffs of the second player */
+ public function get player2Color():uint { return fileSettings.getValue(SCodes.FILE_PLAYER_2_COLOR) as uint; }
+
+ //TODO: 3PL Check wherever player1Color was used, and those might all have to be modified
+
+ /** Font family used as a default for labels in nodes, isets, labels and payoffs */
+ public function get fontFamily():String { return fileSettings.getValue(SCodes.FILE_FONT) as String; }
+
+ /** Diameter in pixels of node points */
+ public function get nodeDiameter():Number { return fileSettings.getValue(SCodes.FILE_NODE_DIAMETER) as Number;}
+
+ /** Diameter in pixels of iset rounded ends */
+ public function get isetDiameter():Number { return fileSettings.getValue(SCodes.FILE_ISET_DIAMETER) as Number;}
+
/** Vertical distance in points/pixels between nodes in two consecutive levels */
- public function get leveldistance():int { return _leveldistance; }
+ public function get leveldistance():int { return fileSettings.getValue(SCodes.FILE_LEVEL_DISTANCE) as int; }
/** Width in points/pixels of lines connecting nodes and lines forming isets */
- public function get linewidth():int { return _linewidth; }
+ public function get strokeWidth():Number { return fileSettings.getValue(SCodes.FILE_STROKE_WIDTH) as Number; }
- /** Width in points/pixels of curves. Should be the same as linewidth, for aesthetical reasons */
- public function get ovallinewidth():int { return _ovallinewidth; }
+ /*<--- --- SELECTED THINGS --- ---> */
/** Id corresponding to the selected node. -1 if there is no node currently selected */
public function get selectedNodeId():int { return _selectedNodeId; }
@@ -87,16 +96,9 @@ package lse.math.games.builder.viewmodel
/** Iset 'selected' as a base for merging with another. Null if there isn't one selected */
public function get mergeBase():Iset { return _mergeBase; }
- public function set mergeBase(value:Iset):void { _mergeBase = value; }
-
- /** Color of nodes, labels and payoffs of the first player */
- public function get player1Color():uint { return userSettings.getValue(SCodes.PLAYER_1_COLOR) as uint; }
-
- /** Color of nodes, labels and payoffs of the second player */
- public function get player2Color():uint { return userSettings.getValue(SCodes.PLAYER_2_COLOR) as uint; }
+ public function set mergeBase(value:Iset):void { _mergeBase = value; }
- /** Font family used as a default for labels in nodes, isets, labels and payoffs */
- public function get fontFamily():String { return userSettings.getValue(SCodes.DEFAULT_FONT) as String; }
+ /* <--- --- OTHERS --- ---> */
/** If each pair of payoffs sum 0 (two player only) */
//TODO: 3PLAYERCHECK
@@ -119,23 +121,12 @@ package lse.math.games.builder.viewmodel
public function defaultTree():void
{
this.newPlayer("1");
- this.newPlayer("2");
+ this.newPlayer("2"); //TODO 3PL
this.root = createNode();
this.root.makeNonTerminal();
}
- /** Gives default values for some settings */
- //TODO: Remove when SETTINGS system is finished
- public function defaultSettings():void
- {
- _rotate = 0;
- _leveldistance = 75;
- _linewidth = 1.0; // line width for drawing Moves
- _ovallinewidth = 1.0; // line width for drawing Isets
- //TODO: SETTINGS
- }
-
// Creates a TreeGridNode with a determinate 'number' (id)
override protected function newNode(number:int):Node {
return new TreeGridNode(this, number);
@@ -334,7 +325,7 @@ package lse.math.games.builder.viewmodel
*/
private function coordsInNode(node:Node, x:int, y:int):Boolean
{
- var halfSide:Number = NODE_DIAM*scale;
+ var halfSide:Number = nodeDiameter*scale;
var n:TreeGridNode = node as TreeGridNode;
return ((n.xpos - halfSide < x)&&
(x < halfSide + n.xpos) &&
@@ -361,7 +352,7 @@ package lse.math.games.builder.viewmodel
private function coordsInIset(h:Iset, x:Number, y:Number):Boolean
{
var found:Boolean = true;
- var radius:Number = ISET_DIAM * scale / 2;
+ var radius:Number = isetDiameter * scale / 2;
var node:Node = getNodeInIsetBeforeCoords(h, x, y, radius);
if (node == null) {
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridActionFactory.as b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridActionFactory.as
index 9b590e6..eb57aa1 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridActionFactory.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridActionFactory.as
@@ -80,17 +80,17 @@ package lse.math.games.builder.viewmodel
return chain;
}
- [Deprecated(replacement="orientationXXX()")]
- public function rotateRight(grid:TreeGrid):IAction
- {
- return new RotateAction(RotateAction.CLOCKWISE);
- }
-
- [Deprecated(replacement="orientationXXX()")]
- public function rotateLeft(grid:TreeGrid):IAction
- {
- return new RotateAction(RotateAction.COUNTERCLOCKWISE);
- }
+// [Deprecated(replacement="orientationXXX()")]
+// public function rotateRight(grid:TreeGrid):IAction
+// {
+// return new RotateAction(RotateAction.CLOCKWISE);
+// }
+//
+// [Deprecated(replacement="orientationXXX()")]
+// public function rotateLeft(grid:TreeGrid):IAction
+// {
+// return new RotateAction(RotateAction.COUNTERCLOCKWISE);
+// }
/** Displays the tree with root on top */
public function orientationUp(grid:TreeGrid):IAction
@@ -143,7 +143,7 @@ package lse.math.games.builder.viewmodel
{
var beforeCut:Node = null;
for (var h:Iset = grid.root.iset; h != null; h = h.nextIset) {
- beforeCut = grid.getNodeInIsetBeforeCoords(h, x, y, TreeGrid.ISET_DIAM * grid.scale/2);
+ beforeCut = grid.getNodeInIsetBeforeCoords(h, x, y, grid.isetDiameter * grid.scale/2);
if (beforeCut != null) {
break;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridPainter.as b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridPainter.as
index d868a04..86dc767 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridPainter.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridPainter.as
@@ -68,12 +68,12 @@ package lse.math.games.builder.viewmodel
_minBreadth = 0;
} else {
//TODO: calculate based on leaf label height/widths
- _minBreadth = this.scale * ((_leafCount + 1) * TreeGrid.ISET_DIAM + _leafCount * TreeGrid.NODE_DIAM + 2 * _grid.ovallinewidth);
+ _minBreadth = this.scale * ((_leafCount + 1) * _grid.isetDiameter + _leafCount * _grid.nodeDiameter + 2 * _grid.strokeWidth);
}
var maxdepth:int = _grid.maxDepth();
//TODO: calculate leveldistance dynamically based on label height/width
- _minDepth = this.scale * (maxdepth * _grid.leveldistance + TreeGrid.ISET_DIAM + 2 * _grid.ovallinewidth);
+ _minDepth = this.scale * (maxdepth * _grid.leveldistance + _grid.isetDiameter + 2 * _grid.strokeWidth);
}
override public function paint(g:IGraphics, width:Number, height:Number):void
@@ -115,7 +115,7 @@ package lse.math.games.builder.viewmodel
marginRight += marginAdjustLR;
}
- var leafDistance:Number = (( -_leafCount * this.scale * TreeGrid.ISET_DIAM) +
+ var leafDistance:Number = (( -_leafCount * this.scale * _grid.isetDiameter) +
(grid.rotate == 0 || grid.rotate == 2 ? width - marginLeft - marginRight : height - marginTop - marginBottom))
/ (_leafCount + 1);
@@ -127,7 +127,7 @@ package lse.math.games.builder.viewmodel
// Graphics painting
private function paintTree(g:IGraphics, grid:TreeGrid):void
{
- g.stroke = this.scale * grid.linewidth;
+ g.stroke = this.scale * grid.strokeWidth;
recPaintTree(g, grid, grid.root as TreeGridNode);
}
@@ -157,9 +157,9 @@ package lse.math.games.builder.viewmodel
if (n.outcome == null) {
g.color = getNodeColor(n, grid, selectionFound);
if (n.iset.player == Player.CHANCE) {
- g.fillRect(n.xpos - this.scale * TreeGrid.NODE_DIAM/2, n.ypos - scale * TreeGrid.NODE_DIAM/2, scale * TreeGrid.NODE_DIAM, scale * TreeGrid.NODE_DIAM);
+ g.fillRect(n.xpos - this.scale * grid.nodeDiameter/2, n.ypos - scale * grid.nodeDiameter/2, scale * grid.nodeDiameter, scale * grid.nodeDiameter);
} else {
- g.fillCircle(n.xpos, n.ypos, this.scale * TreeGrid.NODE_DIAM / 2);
+ g.fillCircle(n.xpos, n.ypos, this.scale * grid.nodeDiameter / 2);
}
}
@@ -170,7 +170,7 @@ package lse.math.games.builder.viewmodel
{
var color:uint = isSelected ? 0xFFD700 : 0x000000;
if (!isSelected && n.iset != null && n.iset.player != Player.CHANCE) {
- color = (grid.firstPlayer == n.iset.player ? grid.player1Color : grid.player2Color);
+ color = (grid.firstPlayer == n.iset.player ? grid.player1Color : grid.player2Color);
if (n.iset == grid.mergeBase) {
color ^= 0xFFFFFF; // complement
color &= 0x7FFF7F; // not too bright, and greenish
@@ -392,7 +392,7 @@ package lse.math.games.builder.viewmodel
if (n.isLeaf)
{
var breadthPos:Number = (drawnumber + 1) * leafdistance +
- this.scale * TreeGrid.ISET_DIAM * (drawnumber + 0.5);
+ this.scale * _grid.isetDiameter * (drawnumber + 0.5);
if (grid.rotate == 0 || grid.rotate == 2) {
n.xpos = breadthPos + marginLeft;
@@ -425,7 +425,7 @@ package lse.math.games.builder.viewmodel
private function positionNodeDepth(n:TreeGridNode, grid:TreeGrid, width:Number, height:Number):void
{
- var depthPos:Number = this.scale * (n.depth * grid.leveldistance + TreeGrid.ISET_DIAM / 2);
+ var depthPos:Number = this.scale * (n.depth * grid.leveldistance + _grid.isetDiameter / 2);
if (grid.rotate == 0) {
n.ypos = depthPos + marginTop;
} else if (grid.rotate == 1) {
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridSetPainter.as b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridSetPainter.as
index 9b59b4a..e717080 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridSetPainter.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/TreeGridSetPainter.as
@@ -58,7 +58,7 @@ package lse.math.games.builder.viewmodel
override public function paint(g:IGraphics, width:Number, height:Number):void
{
- g.stroke = this.scale * _grid.ovallinewidth;
+ g.stroke = this.scale * _grid.strokeWidth;
paintGrid(g, width, height, _grid);
}
@@ -103,7 +103,7 @@ package lse.math.games.builder.viewmodel
var group:Vector. = depthGroups[key];
var first:TreeGridNode = group[0];
var last:TreeGridNode = group[group.length - 1];
- paintSameDepthGroup(g, first, last);
+ paintSameDepthGroup(g, first, last, grid);
keys.push(key);
}
// extract and sort the keys by depth
@@ -131,10 +131,10 @@ package lse.math.games.builder.viewmodel
// else draw at the top of the first group
if (!isLabelPositioned) {
- positionSingletonSetLabel(h, grid, label, this.scale * TreeGrid.ISET_DIAM/2);
+ positionSingletonSetLabel(h, grid, label, this.scale * grid.isetDiameter/2);
}
} else {
- positionSingletonSetLabel(h, grid, label, this.scale * TreeGrid.NODE_DIAM/2);
+ positionSingletonSetLabel(h, grid, label, this.scale * grid.nodeDiameter/2);
}
}
h = h.nextIset;
@@ -157,11 +157,11 @@ package lse.math.games.builder.viewmodel
{
var x:Number, y:Number;
if (grid.rotate == 0 || grid.rotate == 2) {
- x = first.xpos != last.xpos ? (first.xpos + last.xpos) / 2 - label.width / 2 : first.xpos + this.scale * TreeGrid.ISET_DIAM;
+ x = first.xpos != last.xpos ? (first.xpos + last.xpos) / 2 - label.width / 2 : first.xpos + this.scale * grid.isetDiameter;
y = first.ypos + label.ascent / 2;
} else {
x = first.xpos - label.width / 2;
- y = first.ypos != last.ypos ? (first.ypos + last.ypos) / 2 + label.ascent / 2 : first.ypos + this.scale * TreeGrid.ISET_DIAM;
+ y = first.ypos != last.ypos ? (first.ypos + last.ypos) / 2 + label.ascent / 2 : first.ypos + this.scale * grid.isetDiameter;
}
this.moveLabel(label, x, y);
}
@@ -214,14 +214,14 @@ package lse.math.games.builder.viewmodel
var mid:Number = (intersectionRight + intersectionLeft) / 2;
if (grid.rotate == 0 || grid.rotate == 2) {
startX = mid;
- startY = top[0].ypos + (grid.rotate == 0 ? this.scale * TreeGrid.ISET_DIAM / 2 : - this.scale * TreeGrid.ISET_DIAM / 2);
+ startY = top[0].ypos + (grid.rotate == 0 ? this.scale * grid.isetDiameter / 2 : - this.scale * grid.isetDiameter / 2);
endX = mid;
- endY = bottom[0].ypos + (grid.rotate == 2 ? this.scale * TreeGrid.ISET_DIAM / 2 : - this.scale * TreeGrid.ISET_DIAM / 2);
+ endY = bottom[0].ypos + (grid.rotate == 2 ? this.scale * grid.isetDiameter / 2 : - this.scale * grid.isetDiameter / 2);
} else {
startY = mid;
- startX = top[0].xpos + (grid.rotate == 1 ? this.scale * TreeGrid.ISET_DIAM / 2 : - this.scale * TreeGrid.ISET_DIAM / 2);
+ startX = top[0].xpos + (grid.rotate == 1 ? this.scale * grid.isetDiameter / 2 : - this.scale * grid.isetDiameter / 2);
endY = mid;
- endX = bottom[0].xpos + (grid.rotate == 3 ? this.scale * TreeGrid.ISET_DIAM / 2 : - this.scale * TreeGrid.ISET_DIAM / 2);
+ endX = bottom[0].xpos + (grid.rotate == 3 ? this.scale * grid.isetDiameter / 2 : - this.scale * grid.isetDiameter / 2);
}
} else {
// we go node to node
@@ -248,8 +248,8 @@ package lse.math.games.builder.viewmodel
var slope:Number = (endY - startY) / (endX - startX);
var angle:Number = Math.atan(slope);
- var deltaX:Number = Math.cos(angle) * this.scale * TreeGrid.ISET_DIAM / 2;
- var deltaY:Number = Math.sin(angle) * this.scale * TreeGrid.ISET_DIAM / 2;
+ var deltaX:Number = Math.cos(angle) * this.scale * grid.isetDiameter / 2;
+ var deltaY:Number = Math.sin(angle) * this.scale * grid.isetDiameter / 2;
//trace("angle " + int(angle/Math.PI * 180) + " deltaX " + int(deltaX) + " deltaY " + int(deltaY) + " startX " + int(startX) + " startY " + int(startY) + " endX " + int(endX) + " endY " + int(endY));
if (endX < startX) { // quadrant 2 & 3
@@ -265,14 +265,14 @@ package lse.math.games.builder.viewmodel
g.drawDashedLine(startX, startY, endX, endY);
}
- private function paintSameDepthGroup(g:IGraphics, first:TreeGridNode, last:TreeGridNode):void
+ private function paintSameDepthGroup(g:IGraphics, first:TreeGridNode, last:TreeGridNode, grid:TreeGrid):void
{
- var x:Number = (first.xpos < last.xpos ? first.xpos : last.xpos) - this.scale * TreeGrid.ISET_DIAM / 2;
- var y:Number = (first.ypos < last.ypos ? first.ypos : last.ypos) - this.scale * TreeGrid.ISET_DIAM / 2;
- var width:Number = Math.abs(last.xpos - first.xpos) + this.scale * TreeGrid.ISET_DIAM;
- var height:Number = Math.abs(last.ypos - first.ypos) + this.scale * TreeGrid.ISET_DIAM;
+ var x:Number = (first.xpos < last.xpos ? first.xpos : last.xpos) - this.scale * grid.isetDiameter / 2;
+ var y:Number = (first.ypos < last.ypos ? first.ypos : last.ypos) - this.scale * grid.isetDiameter / 2;
+ var width:Number = Math.abs(last.xpos - first.xpos) + this.scale * grid.isetDiameter;
+ var height:Number = Math.abs(last.ypos - first.ypos) + this.scale * grid.isetDiameter;
- g.drawRoundRect(x, y, width, height, this.scale * TreeGrid.ISET_DIAM);
+ g.drawRoundRect(x, y, width, height, this.scale * grid.isetDiameter);
}
private function getSetColor(h:Iset, grid:TreeGrid):uint
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/AddChildAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/AddChildAction.as
index 06ea341..3949f97 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/AddChildAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/AddChildAction.as
@@ -11,6 +11,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.viewmodel.DepthAdjuster;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Adds children to all the nodes in a selected iset/ in a selected node's iset.
* If the nodes are leaves, then two children per node are added, else just one
@@ -24,6 +26,7 @@ package lse.math.games.builder.viewmodel.action
private var _isetId:int = -1;
private var _nodeId:int = -1;
private static var _depthAdjuster:IAction = new DepthAdjuster(); //TODO: remove and use ActionChain or onAdd decorator
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -55,12 +58,16 @@ package lse.math.games.builder.viewmodel.action
node.makeNonTerminal();
addChildrenTo(node.iset, grid);
_depthAdjuster.doAction(grid);
- }
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "AddChildAction");
+ } else
+ log.add(Log.ERROR, "Couldn't find any iset with idx "+_isetId, "AddChildAction");
var labeler:AutoLabeller = new AutoLabeller;
labeler.doAction(grid);
+ grid.orderIds();
+
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/ChangePlayerAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/ChangePlayerAction.as
index 98e7759..dc83212 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/ChangePlayerAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/ChangePlayerAction.as
@@ -7,6 +7,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Changes the player of all nodes inside selected Iset/selected node's Iset
*
Changes Data
@@ -17,7 +19,8 @@ package lse.math.games.builder.viewmodel.action
public class ChangePlayerAction implements IAction
{
private var _isetId:int = -1;
- private var _nodeId:int = -1;
+ private var _nodeId:int = -1;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -32,15 +35,20 @@ package lse.math.games.builder.viewmodel.action
}
public function doAction(grid:TreeGrid):void
- {
+ {
var prevTime:int = getTimer();
var iset:Iset = grid.getIsetById(_isetId);
if (iset == null) {
- var node:Node = grid.getNodeById(_nodeId);
- if (node != null) {
- iset = node.makeNonTerminal();
- }
+ if(_nodeId >= 0)
+ {
+ var node:Node = grid.getNodeById(_nodeId);
+ if (node != null) {
+ iset = node.makeNonTerminal();
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "ChangePlayerAction");
+ } else
+ log.add(Log.ERROR, "Couldn't find any iset with idx "+_isetId, "ChangePlayerAction");
} else {
iset.changePlayer(grid.firstPlayer);
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/CutAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/CutAction.as
index 1835528..9b8d388 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/CutAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/CutAction.as
@@ -6,6 +6,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.AutoLabeller;
import lse.math.games.builder.viewmodel.TreeGrid;
+
+ import util.Log;
/**
* Divides the iset of selected node into two parts, one on the left ending in the Iset,
@@ -18,6 +20,7 @@ package lse.math.games.builder.viewmodel.action
public class CutAction implements IAction
{
private var _nodeId:int = -1;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -40,7 +43,10 @@ package lse.math.games.builder.viewmodel.action
var labeler:AutoLabeller = new AutoLabeller;
labeler.doAction(grid);
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "CutAction");
+
+ grid.orderIds();
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/DeleteAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/DeleteAction.as
index d46ed4d..1def871 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/DeleteAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/DeleteAction.as
@@ -7,6 +7,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.viewmodel.AutoLabeller;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Removes a node and its children
*
Is undoable
@@ -18,6 +20,7 @@ package lse.math.games.builder.viewmodel.action
public class DeleteAction implements IAction
{
private var _nodeId:int = -1;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -40,7 +43,10 @@ package lse.math.games.builder.viewmodel.action
var labeler:AutoLabeller = new AutoLabeller;
labeler.doAction(grid);
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "DeleteAction");
+
+ grid.orderIds();
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/DissolveAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/DissolveAction.as
index f804edb..90ce358 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/DissolveAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/DissolveAction.as
@@ -7,6 +7,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.viewmodel.AutoLabeller;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Dissolves selected Iset
*
Changes Data
@@ -16,7 +18,8 @@ package lse.math.games.builder.viewmodel.action
*/
public class DissolveAction implements IAction
{
- private var _isetId:int = -1;
+ private var _isetId:int = -1;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -39,7 +42,10 @@ package lse.math.games.builder.viewmodel.action
var labeler:AutoLabeller = new AutoLabeller;
labeler.doAction(grid);
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any iset with idx "+_isetId, "DissolveAction");
+
+ grid.orderIds();
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/LabelChangeAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/LabelChangeAction.as
index 9c629fd..8ca614f 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/LabelChangeAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/LabelChangeAction.as
@@ -6,6 +6,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.model.Node;
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.TreeGrid;
+
+ import util.Log;
/**
* Changes a selected node's label to a new one
@@ -18,6 +20,7 @@ package lse.math.games.builder.viewmodel.action
{
private var _nodeId:int;
private var _label:String;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -41,7 +44,8 @@ package lse.math.games.builder.viewmodel.action
if (move != null) {
move.label = _label;
}
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "LabelChangeAction");
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/MakeChanceAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/MakeChanceAction.as
index c075f5a..710e119 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/MakeChanceAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/MakeChanceAction.as
@@ -7,6 +7,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Makes a node or all nodes in iset to be chances (eliminating player data and replacing move labels with probabilities)
*
Changes Data
@@ -18,6 +20,7 @@ package lse.math.games.builder.viewmodel.action
{
private var _isetId:int = -1;
private var _nodeId:int = -1;
+ private var log:Log = Log.instance;
private var _onDissolve:IAction;
@@ -44,11 +47,16 @@ package lse.math.games.builder.viewmodel.action
var iset:Iset = grid.getIsetById(_isetId);
if (iset == null) {
- var node:Node = grid.getNodeById(_nodeId);
- if (node != null) {
- iset = node.makeNonTerminal();
- iset.makeChance();
- }
+ if(_nodeId >= 0)
+ {
+ var node:Node = grid.getNodeById(_nodeId);
+ if (node != null) {
+ iset = node.makeNonTerminal();
+ iset.makeChance();
+ } else
+ log.add(Log.ERROR, "Couldn't find any node with idx "+_nodeId, "MakeChanceAction");
+ } else
+ log.add(Log.ERROR, "Couldn't find any iset with idx "+_isetId, "MakeChanceAction");
} else {
var dissolve:Boolean = iset.numNodes > 1;
iset.makeChance();
@@ -57,6 +65,8 @@ package lse.math.games.builder.viewmodel.action
}
}
+ grid.orderIds();
+
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/MergeAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/MergeAction.as
index e04346b..da93f14 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/MergeAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/MergeAction.as
@@ -16,7 +16,7 @@ package lse.math.games.builder.viewmodel.action
public class MergeAction implements IAction
{
private var _mergeId:int = -1;
- private var _baseId:int = -1;
+ private var _baseId:int = -1;
private var _onMerge:IAction;
@@ -60,6 +60,8 @@ package lse.math.games.builder.viewmodel.action
grid.mergeBase = null;
}
+ grid.orderIds();
+
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/PayChangeAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/PayChangeAction.as
index 095f627..c96556a 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/PayChangeAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/PayChangeAction.as
@@ -8,6 +8,8 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
* Changes the payoffs of a terminal node
@@ -21,6 +23,7 @@ package lse.math.games.builder.viewmodel.action
private var _nodeId:int;
private var _pay1:Rational;
private var _pay2:Rational;
+ private var log:Log = Log.instance;
private var _timeElapsed:int = 0;
@@ -47,7 +50,8 @@ package lse.math.games.builder.viewmodel.action
outcome.setPay(grid.firstPlayer, _pay1);
if(_pay2!=null)
outcome.setPay(grid.firstPlayer.nextPlayer, _pay2);
- }
+ } else
+ log.add(Log.ERROR, "Couldn't find any suitable node with idx "+_nodeId, "PayChangeAction");
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/PerfectRecallAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/PerfectRecallAction.as
index f56d93c..75deedf 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/PerfectRecallAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/PerfectRecallAction.as
@@ -32,6 +32,8 @@ package lse.math.games.builder.viewmodel.action
var labeler:AutoLabeller = new AutoLabeller;
labeler.doAction(grid);
+ grid.orderIds();
+
_timeElapsed = getTimer() - prevTime;
}
diff --git a/gui-builder/src/lse/math/games/builder/viewmodel/action/RotateAction.as b/gui-builder/src/lse/math/games/builder/viewmodel/action/RotateAction.as
index 17aa2fa..a571d5a 100644
--- a/gui-builder/src/lse/math/games/builder/viewmodel/action/RotateAction.as
+++ b/gui-builder/src/lse/math/games/builder/viewmodel/action/RotateAction.as
@@ -5,19 +5,19 @@ package lse.math.games.builder.viewmodel.action
import lse.math.games.builder.presenter.IAction;
import lse.math.games.builder.viewmodel.TreeGrid;
+ import util.Log;
+
/**
- * Rotates the tree clock or counterclockwise
+ * Rotates the tree to a certain orientation.
*
NOT Changes Data
*
Changes Size
*
Changes Display
- * @author Mark Egesdal
+ * @author Mark Egesdal & alfongj
*/
public class RotateAction implements IAction
{
- [Deprecated]
- public static const CLOCKWISE:String = "clockwise";
- [Deprecated]
- public static const COUNTERCLOCKWISE:String = "counterclockwise";
+ //public static const CLOCKWISE:String = "clockwise";
+ //public static const COUNTERCLOCKWISE:String = "counterclockwise";
//Root positions
public static const UP:String = "up";
@@ -37,9 +37,9 @@ package lse.math.games.builder.viewmodel.action
{
switch(direction)
{
- case CLOCKWISE:
- case COUNTERCLOCKWISE:
- trace("Rotation direction " + direction + " is deprecated. Please check the Documentation");
+// case CLOCKWISE:
+// case COUNTERCLOCKWISE:
+// trace("Rotation direction " + direction + " is deprecated. Please check the Documentation");
case UP:
case DOWN:
case RIGHT:
@@ -47,7 +47,7 @@ package lse.math.games.builder.viewmodel.action
_direction = direction;
break;
default:
- throw new Error("Rotate direction must be one of 'clockwise' or 'counterclockwise'");
+ Log.instance.add(Log.ERROR_HIDDEN, "Rotate direction must be UP, DOWN, RIGHT or LEFT");
}
}
@@ -56,12 +56,12 @@ package lse.math.games.builder.viewmodel.action
switch(_direction)
{
- case CLOCKWISE:
- grid.rotateRight();
- break;
- case COUNTERCLOCKWISE:
- grid.rotateLeft();
- break;
+// case CLOCKWISE:
+// grid.rotateRight();
+// break;
+// case COUNTERCLOCKWISE:
+// grid.rotateLeft();
+// break;
case UP:
grid.rotate = 0;
break;
diff --git a/gui-builder/src/util/Log.as b/gui-builder/src/util/Log.as
index d143803..70b6178 100644
--- a/gui-builder/src/util/Log.as
+++ b/gui-builder/src/util/Log.as
@@ -149,8 +149,9 @@ package util
public function saveLogDump() : void
{
//TODO: I don't know the reason why, but the save method is ignoring the new line characters. In NotePad++ it is displayed correctly, not so in Notepad
- var fr:FileReference = new FileReference;
- fr.save(logDump(), "log.txt");
+// var fr:FileReference = new FileReference;
+// fr.save(logDump(), "log.txt");
+ //TODO: Better post to the dev in charge, should be a setting that enables it
}
/** Returns a String with the content of the arraylist of lines (last LOG_MAX_LENGTH lines as a default, or 'numLines' if specified)*/
diff --git a/gui-builder/test/src/TestSuite.as b/gui-builder/test/src/TestSuite.as
index 1b7ffef..d03b33f 100644
--- a/gui-builder/test/src/TestSuite.as
+++ b/gui-builder/test/src/TestSuite.as
@@ -16,5 +16,7 @@ package
public var playerTest:lse.math.games.builder.model.PlayerTest;
public var rationalTest:lse.math.games.builder.model.RationalTest;
public var strategyTest:lse.math.games.builder.model.StrategyTest;
+
+ public var nodePriorityQueueTest:lse.math.games.builder.viewmodel.NodePriorityQueueTest;
}
}
\ No newline at end of file
diff --git a/web-service/war/builder/index.jsp b/web-service/war/builder/index.jsp
index 3d24a53..9c0fcbd 100644
--- a/web-service/war/builder/index.jsp
+++ b/web-service/war/builder/index.jsp
@@ -27,15 +27,12 @@
allowFullscreen: "true",
allowScriptAccess: "always",
bgcolor: "#FFFFFF",
- wmode: "transparent"
};
var attributes = {
id:"GuiBuilder"
};
attributes.align = "middle";
- var fullwindow = true;
-
swfobject.embedSWF(
"GuiBuilder.swf",
"flashContainer",
@@ -79,23 +76,10 @@
outputWindow.resizeTo(500,desiredHeight);
}
- //Expands / Contracts the gui
- function expand()
+ //Expands / Contracts the gui if setting is true / false
+ function expand(setting)
{
- if(fullwindow) //Contract
- {
- document.getElementById("titleContainer").style.display = "";
- document.getElementById("creditsContainer").style.display = "";
-
- document.getElementById("GTEContainer").style.padding = "2px 5px 5px 5px";
- document.getElementById("GTEContainer").style.border ="1px solid #808080";
-
- document.getElementById("GTEContainer").style.height = "580px";
- document.getElementById("GTEContainer").style.width = "85%";
-
- document.getElementById("expandButton").innerHTML = "Expand";
- }
- else //Expand
+ if(setting) //Expand
{
//Hide title and credits
document.getElementById("titleContainer").style.display = "none";
@@ -108,12 +92,18 @@
//Maximize GTEContainer & solutionContainer
document.getElementById("GTEContainer").style.height = "100%";
document.getElementById("GTEContainer").style.width = "100%";
+ }
+ else //Contract
+ {
+ document.getElementById("titleContainer").style.display = "";
+ document.getElementById("creditsContainer").style.display = "";
- //Change button text
- document.getElementById("expandButton").innerHTML = "Contract";
+ document.getElementById("GTEContainer").style.padding = "2px 5px 5px 5px";
+ document.getElementById("GTEContainer").style.border ="1px solid #808080";
+
+ document.getElementById("GTEContainer").style.height = "580px";
+ document.getElementById("GTEContainer").style.width = "85%";
}
-
- fullwindow = !fullwindow;
}
//Returns the flashmovie
@@ -142,7 +132,7 @@
object:focus { outline:none; }
-
+