summaryrefslogtreecommitdiff
path: root/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js
diff options
context:
space:
mode:
Diffstat (limited to 'webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js')
-rw-r--r--webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js613
1 files changed, 613 insertions, 0 deletions
diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js
new file mode 100644
index 0000000000..a61d27ff24
--- /dev/null
+++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/State.js
@@ -0,0 +1,613 @@
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2006 by Derrell Lipman
+
+ License:
+ LGPL 2.1: http://www.gnu.org/licenses/lgpl.html
+
+ Authors:
+ * Derrell Lipman (derrell)
+
+************************************************************************ */
+
+/* ************************************************************************
+
+#module(util_fsm)
+#require(qx.util.fsm.FiniteStateMachine)
+
+************************************************************************ */
+
+/**
+ * Create a new state which may be added to a finite state machine.
+ *
+ * *EXPERIMENTAL*
+ * The interface to the finite state machine, states, and transitions is
+ * experimental. It may change in non-backward-compatible ways as more
+ * experience is gained in its use.
+ *
+ * @param
+ * stateName -
+ * The name of this state. This is the name which may be referenced in
+ * objects of class qx.util.fsm.Transition, when passing of
+ * the the transition's predicate means transition to this state.
+ *
+ * @param
+ * stateInfo -
+ * An object containing any of the following properties:
+ *
+ * onentry -
+ * A function which is called upon entry to the state. Its signature is
+ * function(fsm, event) and it is saved in the onentry property of the
+ * state object. (This function is called after the Transition's action
+ * function and after the previous state's onexit function.)
+ *
+ * In the onentry function:
+ *
+ * fsm -
+ * The finite state machine object to which this state is attached.
+ *
+ * event -
+ * The event that caused the finite state machine to run
+ *
+ * onexit -
+ * A function which is called upon exit from the state. Its signature
+ * is function(fsm, event) and it is saved in the onexit property of the
+ * state object. (This function is called after the Transition's action
+ * function and before the next state's onentry function.)
+ *
+ * In the onexit function:
+ *
+ * fsm -
+ * The finite state machine object to which this state is attached.
+ *
+ * event -
+ * The event that caused the finite state machine to run
+ *
+ * autoActionsBeforeOnentry -
+ * autoActionsAfterOnentry -
+ * auutoActionsBeforeOnexit -
+ * autoActionsAfterOnexit -
+ * Automatic actions which take place at the time specified by the
+ * property name. In all cases, the action takes place immediately
+ * before or after the specified function.
+ *
+ * The property value for each of these properties is an object which
+ * describes some number of functions to invoke on a set of specified
+ * objects (typically widgets).
+ *
+ * An example, using autoActionsBeforeOnentry, might look like this:
+ *
+ * "autoActionsBeforeOnentry" :
+ * {
+ * // The name of a function.
+ * "enabled" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ true ],
+ *
+ * // The function would be called on each object:
+ * // this.getObject("obj1").setEnabled(true);
+ * // this.getObject("obj2").setEnabled(true);
+ * "objects" : [ "obj1", "obj2" ],
+ *
+ * // And similarly for each object in each specified group.
+ * "groups" : [ "group1", "group2" ]
+ * }
+ * ],
+ *
+ * // The name of another function.
+ * "visible" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ false ],
+ *
+ * // The function would be called on each object and group, as
+ * // described above.
+ * "objects" : [ "obj3", "obj4" ],
+ * "groups" : [ "group3", "group4" ]
+ * }
+ * ]
+ * };
+ *
+ *
+ * events (required) -
+ * A description to the finite state machine of how to handle a
+ * particular event, optionally associated with a specific target object
+ * on which the event was dispatched. This should be an object
+ * containing one property for each event which is either handled or
+ * blocked. The property name should be the event name. The property
+ * value should be one of:
+ *
+ * (a) qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE
+ *
+ * (b) qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
+ *
+ * (c) a string containing the name of an explicit Transition to use
+ *
+ * (d) an object where each property name is the Friendly Name of an
+ * object (meaning that this rule applies if both the event and
+ * the event's target object's Friendly Name match), and its
+ * property value is one of (a), (b) or (c), above.
+ *
+ * This object is saved in the events property of the state object.
+ *
+ * Additional properties may be provided in stateInfo. They will not be
+ * used by the finite state machine, but will be available via
+ * this.getUserData("<propertyName>") during the state's onentry and
+ * onexit functions.
+ */
+qx.OO.defineClass("qx.util.fsm.State", qx.core.Object,
+function(stateName, stateInfo)
+{
+ // Call our superclass' constructor
+ qx.core.Object.call(this, true);
+
+ // Save the state name
+ this.setName(stateName);
+
+ // Ensure they passed in an object
+ if (typeof(stateInfo) != "object")
+ {
+ throw new Error("State info must be an object");
+ }
+
+ // Save data from the stateInfo object
+ for (var field in stateInfo)
+ {
+ // If we find one of our properties, call its setter.
+ switch(field)
+ {
+ case "onentry":
+ this.setOnentry(stateInfo[field]);
+ break;
+
+ case "onexit":
+ this.setOnexit(stateInfo[field]);
+ break;
+
+ case "autoActionsBeforeOnentry":
+ this.setAutoActionsBeforeOnentry(stateInfo[field]);
+ break;
+
+ case "autoActionsAfterOnentry":
+ this.setAutoActionsAfterOnentry(stateInfo[field]);
+ break;
+
+ case "autoActionsBeforeOnexit":
+ this.setAutoActionsBeforeOnentry(stateInfo[field]);
+ break;
+
+ case "autoActionsBeforeOnexit":
+ this.setAutoActionsBeforeOnentry(stateInfo[field]);
+ break;
+
+ case "events":
+ this.setEvents(stateInfo[field]);
+ break;
+
+ default:
+ // Anything else is user-provided data for their own use. Save it.
+ this.setUserData(field, stateInfo[field]);
+
+ // Log it in case it was a typo and they intended a built-in field
+ this.debug("State " + stateName + ": " +
+ "Adding user-provided field to state: " + field);
+
+ break;
+ }
+ }
+
+
+ // Check for required but missing properties
+ if (! this.getEvents())
+ {
+ throw new Error("The events object must be provided in new state info");
+ }
+
+
+ // Initialize the transition list
+ this.transitions = { };
+});
+
+
+
+
+/*
+---------------------------------------------------------------------------
+ PROPERTIES
+---------------------------------------------------------------------------
+*/
+
+/**
+ * The name of this state. This name may be used as a Transition's nextState
+ * value, or an explicit next state in the 'events' handling list in a State.
+ */
+qx.OO.addProperty(
+ {
+ name : "name",
+ type : "string"
+ });
+
+/**
+ * The onentry function for this state. This is documented in the
+ * constructor, and is typically provided through the constructor's stateInfo
+ * object, but it is also possible (but highly NOT recommended) to change this
+ * dynamically.
+ */
+qx.OO.addProperty(
+ {
+ name : "onentry",
+ defaultValue : function(fsm, event) { }
+ });
+
+/**
+ * The onexit function for this state. This is documented in the constructor,
+ * and is typically provided through the constructor's stateInfo object, but
+ * it is also possible (but highly NOT recommended) to change this
+ * dynamically.
+ */
+qx.OO.addProperty(
+ {
+ name : "onexit",
+ defaultValue : function(fsm, event) { }
+ });
+
+/**
+ * Automatic actions to take prior to calling the state's onentry function.
+ *
+ * The value passed to setAutoActionsBeforeOnentry() should like something
+ * akin to:
+ *
+ * "autoActionsBeforeOnentry" :
+ * {
+ * // The name of a function. This would become "setEnabled("
+ * "enabled" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ true ],
+ *
+ * // The function would be called on each object:
+ * // this.getObject("obj1").setEnabled(true);
+ * // this.getObject("obj2").setEnabled(true);
+ * "objects" : [ "obj1", "obj2" ]
+ *
+ * // And similarly for each object in each specified group.
+ * "groups" : [ "group1", "group2" ],
+ * }
+ * ];
+ * };
+ */
+qx.OO.addProperty(
+ {
+ name : "autoActionsBeforeOnentry",
+ defaultValue : function(fsm, event) { }
+ });
+
+/**
+ * Automatic actions to take after return from the state's onentry function.
+ *
+ * The value passed to setAutoActionsAfterOnentry() should like something akin
+ * to:
+ *
+ * "autoActionsAfterOnentry" :
+ * {
+ * // The name of a function. This would become "setEnabled("
+ * "enabled" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ true ],
+ *
+ * // The function would be called on each object:
+ * // this.getObject("obj1").setEnabled(true);
+ * // this.getObject("obj2").setEnabled(true);
+ * "objects" : [ "obj1", "obj2" ]
+ *
+ * // And similarly for each object in each specified group.
+ * "groups" : [ "group1", "group2" ],
+ * }
+ * ];
+ * };
+ */
+qx.OO.addProperty(
+ {
+ name : "autoActionsAfterOnentry",
+ defaultValue : function(fsm, event) { }
+ });
+
+/**
+ * Automatic actions to take prior to calling the state's onexit function.
+ *
+ * The value passed to setAutoActionsBeforeOnexit() should like something akin
+ * to:
+ *
+ * "autoActionsBeforeOnexit" :
+ * {
+ * // The name of a function. This would become "setEnabled("
+ * "enabled" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ true ],
+ *
+ * // The function would be called on each object:
+ * // this.getObject("obj1").setEnabled(true);
+ * // this.getObject("obj2").setEnabled(true);
+ * "objects" : [ "obj1", "obj2" ]
+ *
+ * // And similarly for each object in each specified group.
+ * "groups" : [ "group1", "group2" ],
+ * }
+ * ];
+ * };
+ */
+qx.OO.addProperty(
+ {
+ name : "autoActionsBeforeOnexit",
+ defaultValue : function(fsm, event) { }
+ });
+
+
+/**
+ * Automatic actions to take after returning from the state's onexit function.
+ *
+ * The value passed to setAutoActionsAfterOnexit() should like something akin
+ * to:
+ *
+ * "autoActionsBeforeOnexit" :
+ * {
+ * // The name of a function. This would become "setEnabled("
+ * "enabled" :
+ * [
+ * {
+ * // The parameter value, thus "setEnabled(true);"
+ * "parameters" : [ true ],
+ *
+ * // The function would be called on each object:
+ * // this.getObject("obj1").setEnabled(true);
+ * // this.getObject("obj2").setEnabled(true);
+ * "objects" : [ "obj1", "obj2" ]
+ *
+ * // And similarly for each object in each specified group.
+ * "groups" : [ "group1", "group2" ],
+ * }
+ * ];
+ * };
+ */
+qx.OO.addProperty(
+ {
+ name : "autoActionsAfterOnexit",
+ defaultValue : function(fsm, event) { }
+ });
+
+
+/**
+ * The object representing handled and blocked events for this state. This is
+ * documented in the constructor, and is typically provided through the
+ * constructor's stateInfo object, but it is also possible (but highly NOT
+ * recommended) to change this dynamically.
+ */
+qx.OO.addProperty(
+ {
+ name : "events"
+ });
+
+
+
+/*
+---------------------------------------------------------------------------
+ MODIFIER
+---------------------------------------------------------------------------
+*/
+
+qx.Proto._checkName = function(propValue, propData)
+{
+ // Ensure that we got a valid state name
+ if (typeof(propValue) != "string" || propValue.length < 1)
+ {
+ throw new Error("Invalid state name");
+ }
+
+ return propValue;
+};
+
+qx.Proto._checkOnentry = function(propValue, propData)
+{
+ // Validate the onentry function
+ switch(typeof(propValue))
+ {
+ case "undefined":
+ // None provided. Convert it to a null function
+ return function(fsm, event) {};
+
+ case "function":
+ // We're cool. No changes required
+ return propValue;
+
+ default:
+ throw new Error("Invalid onentry type: " + typeof(propValue));
+ return null;
+ }
+};
+
+qx.Proto._checkOnexit = function(propValue, propData)
+{
+ // Validate the onexit function
+ switch(typeof(propValue))
+ {
+ case "undefined":
+ // None provided. Convert it to a null function
+ return function(fsm, event) {};
+
+ case "function":
+ // We're cool. No changes required
+ return propValue;
+
+ default:
+ throw new Error("Invalid onexit type: " + typeof(propValue));
+ return null;
+ }
+};
+
+qx.Proto._checkEvents = function(propValue, propData)
+{
+ // Validate that events is an object
+ if (typeof(propValue) != "object")
+ {
+ throw new Error("events must be an object");
+ }
+
+ // Confirm that each property is a valid value
+ // The property value should be one of:
+ //
+ // (a) qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE
+ //
+ // (b) qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
+ //
+ // (c) a string containing the name of an explicit Transition to use
+ //
+ // (d) an object where each property name is the Friendly Name of an
+ // object (meaning that this rule applies if both the event and
+ // the event's target object's Friendly Name match), and its
+ // property value is one of (a), (b) or (c), above.
+ for (var e in propValue)
+ {
+ var action = propValue[e];
+ if (typeof(action) == "number" &&
+ action != qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE &&
+ action != qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED)
+ {
+ throw new Error("Invalid numeric value in events object: " +
+ e + ": " + action);
+ }
+ else if (typeof(action) == "object")
+ {
+ for (action_e in action)
+ {
+ if (typeof(action[action_e]) == "number" &&
+ action != qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE &&
+ action != qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED)
+ {
+ throw new Error("Invalid numeric value in events object " +
+ "(" + e + "): " +
+ action_e + ": " + action[action_e]);
+ }
+ else if (typeof(action[action_e]) != "string")
+ {
+ throw new Error("Invalid value in events object " +
+ "(" + e + "): " +
+ action_e + ": " + action[action_e]);
+ }
+ }
+ }
+ else if (typeof(action) != "string")
+ {
+ throw new Error("Invalid value in events object: " +
+ e + ": " + propValue[e]);
+ }
+ }
+
+ // We're cool. No changes required.
+ return propValue;
+};
+
+qx.Proto._checkAutoActionsBeforeOnentry = function(propValue, propData)
+{
+ return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions(
+ "autoActionsBeforeOnentry",
+ propValue,
+ propData);
+};
+
+qx.Proto._checkAutoActionsAfterOnentry = function(propValue, propData)
+{
+ return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions(
+ "autoActionsAfterOnentry",
+ propValue,
+ propData);
+};
+
+qx.Proto._checkAutoActionsBeforeOnexit = function(propValue, propData)
+{
+ return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions(
+ "autoActionsBeforeOnexit",
+ propValue,
+ propData);
+};
+
+qx.Proto._checkAutoActionsAfterOnexit = function(propValue, propData)
+{
+ return qx.util.fsm.FiniteStateMachine._commonCheckAutoActions(
+ "autoActionsAfterOnexit",
+ propValue,
+ propData);
+};
+
+
+/*
+---------------------------------------------------------------------------
+ UTILITIES
+---------------------------------------------------------------------------
+*/
+
+/**
+ * Add a transition to a state
+ *
+ * @param trans {qx.util.fsm.Transition}
+ * An object of class qx.util.fsm.Transition representing a
+ * transition which is to be a part of this state.
+ */
+qx.Proto.addTransition = function(trans)
+{
+ // Ensure that we got valid transition info
+ if (! trans instanceof qx.util.fsm.Transition)
+ {
+ throw new Error("Invalid transition: not an instance of " +
+ "qx.util.fsm.Transition");
+ }
+
+ // Add the new transition object to the state
+ this.transitions[trans.getName()] = trans;
+};
+
+
+
+
+/*
+---------------------------------------------------------------------------
+ EVENT LISTENERS
+---------------------------------------------------------------------------
+*/
+
+
+
+/*
+---------------------------------------------------------------------------
+ CLASS CONSTANTS
+---------------------------------------------------------------------------
+*/
+
+
+
+/*
+---------------------------------------------------------------------------
+ DISPOSER
+---------------------------------------------------------------------------
+*/
+
+qx.Proto.dispose = function()
+{
+ if (this.getDisposed()) {
+ return true;
+ }
+
+ return qx.core.Object.prototype.dispose.call(this);
+}