From eab632c31e376a3f3a2e18f89083cf9055d63a9f Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 3 Jan 2007 20:50:45 +0000 Subject: r20518: reapply finite state machine mods which got lost in the webapps remove/restore process (This used to be commit 1d867863b64fb39aedbf713f7f3dd17948b433ef) --- .../source/class/qx/util/fsm/FiniteStateMachine.js | 243 +++++++++++++++++++-- .../framework/source/class/qx/util/fsm/State.js | 8 +- .../source/class/qx/util/fsm/Transition.js | 5 +- .../framework/source/class/qx/util/fsm/example.txt | 26 +-- 4 files changed, 240 insertions(+), 42 deletions(-) diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js index e1a1605c83..7c293eb76b 100644 --- a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/FiniteStateMachine.js @@ -142,7 +142,7 @@ qx.OO.addProperty( { name : "maxSavedStates", type : "number", - defaultValue : 5 + defaultValue : 2 }); /* @@ -189,6 +189,55 @@ qx.Proto.addState = function(state) }; +/** + * Replace a state in the finite state machine. This is useful if initially + * "dummy" states are created which load the real state table for a series of + * operations (and possibly also load the gui associated with the new states + * at the same time). Having portions of the finite state machine and their + * associated gui pages loaded at run time can help prevent long delays at + * application start-up time. + * + * @param state {qx.util.fsm.State} + * An object of class qx.util.fsm.State representing a state + * which is to be a part of this finite state machine. + * + * @param bDispose {boolean} + * If true, then dispose the old state object. If false, the + * old state object is returned for disposing by the caller. + * + * @return {Object} + * The old state object if it was not disposed; otherwise null. + */ +qx.Proto.replaceState = function(state, bDispose) +{ + // Ensure that we got valid state info + if (! state instanceof qx.util.fsm.State) + { + throw new Error("Invalid state: not an instance of " + + "qx.util.fsm.State"); + } + + // Retrieve the name of this state + var stateName = state.getName(); + + // Save the old state object, so we can return it to be disposed + var oldState = this._states[stateName]; + + // Replace the old state with the new state object. + this._states[stateName] = state; + + // Did they request that the old state be disposed? + if (bDispose) + { + // Yup. Mark it to be disposed. + oldState._needDispose; + } + + return oldState; +}; + + + /** * Add an object (typically a widget) that is to be accessed during state * transitions, to the finite state machine. @@ -304,12 +353,12 @@ qx.Proto.getObject = function(friendlyName) * * @return {string} * If the object has been previously registered via {@see #addObject}, then - * a reference to the object is returned; otherwise, null. + * the friendly name of the object is returned; otherwise, null. */ qx.Proto.getFriendlyName = function(obj) { var hash = obj.toHashCode(); - return hash ? this.getObject(this._hashToFriendly[hash]) : null; + return hash ? this._hashToFriendly[hash] : null; }; @@ -336,6 +385,83 @@ qx.Proto.getGroupObjects = function(groupName) return a; }; + +/** + * Display all of the saved objects and their reverse mappings. + */ +qx.Proto.displayAllObjects = function() +{ + for (var friendlyName in this._friendlyToHash) + { + var hash = this._friendlyToHash[friendlyName]; + var obj = this.getObject(friendlyName); + this.debug(friendlyName + + " => " + + hash); + this.debug(" " + hash + + " => " + + this._hashToFriendly[hash]); + this.debug(" " + friendlyName + + " => " + + this.getObject(friendlyName)); + this.debug(" " + this.getObject(friendlyName) + + " => " + + this.getFriendlyName(obj)); + } +}; + + +/** + * Recursively display an object (as debug messages) + * + * @param obj {Object} + * The object to be recursively displayed + */ +qx.Proto.debugObject = function(obj) +{ + thisClass = this; + + var displayObj = function(obj, level) + { + var indentStr = ""; + for (var i = 0; i < level; i++) + { + indentStr += " "; + } + + if (typeof(obj) != "object") + { + thisClass.debug(indentStr, obj); + return; + } + + for (var prop in obj) + { + if (typeof(obj[prop]) == "object") + { + if (obj[prop] instanceof Array) + { + thisClass.debug(indentStr + prop + ": " + "Array"); + } + else + { + thisClass.debug(indentStr + prop + ": " + "Object"); + } + + displayObj(obj[prop], level + 1); + } + else + { + thisClass.debug(indentStr + prop + ": " + obj[prop]); + } + } + } + + displayObj(obj, 0); +}; + + + /** * Start (or restart, after it has terminated) the finite state machine from * the starting state. The starting state is defined as the first state added @@ -389,25 +515,39 @@ qx.Proto.start = function() /** - * Save the current state on the saved-state stack. A future transition can - * then provide, as its nextState value, the class constant: + * Save the current or previous state on the saved-state stack. A future + * transition can then provide, as its nextState value, the class constant: * * qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK * * which will cause the next state to be whatever is at the top of the * saved-state stack, and remove that top element from the saved-state stack. + * + * @param bCurrent {boolean} + * When true, then push the current state onto the stack. This might + * be used in a transition, before the state has changed. When + * false, then push the previous state onto the stack. This might be + * used in an on entry function to save the previous state to return to. */ -qx.Proto.pushState = function() +qx.Proto.pushState = function(bCurrent) { // See if there's room on the state stack for a new state - if (this.getMaxSavedStates() >= this._savedStates.length) + if (this._savedStates.length >= this.getMaxSavedStates()) { // Nope. Programmer error. throw new Error("Saved-state stack is full"); } - // Push the current state onto the saved-state stack - this._savedStates.push(this.getState()); + if (bCurrent) + { + // Push the current state onto the saved-state stack + this._savedStates.push(this.getState()); + } + else + { + // Push the previous state onto the saved-state stack + this._savedStates.push(this.getPreviousState()); + } }; @@ -427,33 +567,84 @@ qx.Proto.postponeEvent = function(event) /** - * Event listener for all event types in the finite state machine + * Copy an event * * @param event {qx.event.type.Event} - * The event that was dispatched. + * The event to be copied + * + * @return {qx.event.type.Event} + * The new copy of the provided event */ -qx.Proto.eventListener = function(event) +qx.Proto.copyEvent = function(event) { - // Events are enqueued upon receipt. Some events are then processed - // immediately; other events get processed later. We need to allow the - // event dispatcher to free the source event upon our return, so we'll clone - // it and enqueue our clone. The source event can then be disposed upon our - // return. var e = { }; for (var prop in event) { e[prop] = event[prop]; } + return e; +}; + + +/** + * Enqueue an event for processing + * + * @param event {qx.event.type.Event} + * The event to be enqueued + * + * @param bAddAtHead {boolean} + * If true, put the event at the head of the queue for immediate + * processing. If false, place the event at the tail of the queue so + * that it receives in-order processing. + */ +qx.Proto.enqueueEvent = function(event, bAddAtHead) +{ // Add the event to the event queue - this._eventQueue.unshift(e); + if (bAddAtHead) + { + // Put event at the head of the queue + this._eventQueue.push(event); + } + else + { + // Put event at the tail of the queue + this._eventQueue.unshift(event); + } if (qx.Settings.getValueOfClass("qx.util.fsm.FiniteStateMachine", "debugFlags") & qx.util.fsm.FiniteStateMachine.DebugFlags.EVENTS) { - this.debug(this.getName() + ": Queued event: " + e.getType()); + if (bAddAtHead) + { + this.debug(this.getName() + ": Pushed event: " + event.getType()); + } + else + { + this.debug(this.getName() + ": Queued event: " + event.getType()); + } } +}; + + +/** + * Event listener for all event types in the finite state machine + * + * @param event {qx.event.type.Event} + * The event that was dispatched. + */ +qx.Proto.eventListener = function(event) +{ + // Events are enqueued upon receipt. Some events are then processed + // immediately; other events get processed later. We need to allow the + // event dispatcher to free the source event upon our return, so we'll clone + // it and enqueue our clone. The source event can then be disposed upon our + // return. + var e = this.copyEvent(event); + + // Enqueue the new event on the tail of the queue + this.enqueueEvent(e, false); // Process events this._processEvents(); @@ -566,7 +757,6 @@ qx.Proto._run = function(event) return; } - // We might have found a constant (PREDICATE or BLOCKED) or an object with // each property name being the friendly name of a saved object, and the // property value being one of the constants (PREDICATE or BLOCKED). @@ -678,14 +868,14 @@ qx.Proto._run = function(event) case qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: // Switch to the state at the top of the state stack. - if (this._stateStack.length == 0) + if (this._savedStates.length == 0) { throw new Error("Attempt to transition to POP_STATE_STACK " + "while state stack is empty."); } // Pop the state stack to retrieve the state to transition to - nextState = this._stateStack.pop(); + nextState = this._savedStates.pop(); this.setNextState(nextState); break; @@ -738,7 +928,14 @@ qx.Proto._run = function(event) { this.debug(this.getName() + "#" + thisState + "#autoActionsAfterOnexit"); } - currentState.getAutoActionsAfterOnentry()(this); + currentState.getAutoActionsAfterOnexit()(this); + + // If this state has been replaced and we're supposed to dispose it... + if (currentState._needDispose) + { + // ... then dispose it now that it's no longer in use + currentState.dispose(); + } // Reset currentState to the new state object currentState = this._states[this.getNextState()]; 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 index a61d27ff24..fc054e304a 100644 --- 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 @@ -70,7 +70,7 @@ * * autoActionsBeforeOnentry - * autoActionsAfterOnentry - - * auutoActionsBeforeOnexit - + * autoActionsBeforeOnexit - * autoActionsAfterOnexit - * Automatic actions which take place at the time specified by the * property name. In all cases, the action takes place immediately @@ -181,11 +181,11 @@ function(stateName, stateInfo) break; case "autoActionsBeforeOnexit": - this.setAutoActionsBeforeOnentry(stateInfo[field]); + this.setAutoActionsBeforeOnexit(stateInfo[field]); break; - case "autoActionsBeforeOnexit": - this.setAutoActionsBeforeOnentry(stateInfo[field]); + case "autoActionsAfterOnexit": + this.setAutoActionsAfterOnexit(stateInfo[field]); break; case "events": diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js index 3d13324999..e417e23298 100644 --- a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/Transition.js @@ -86,7 +86,7 @@ * - One of the constants: * - qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE: * Remain in whatever is the current state - * - qx.util.fsm.FiniteStateMachine.StateChange.PREVIOUS_STATE: + * - qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: * Transition to the state at the top of the saved-state stack, * and remove the top element from the saved-state stack. * Elements are added to the saved-state stack using @@ -308,7 +308,8 @@ qx.Proto._checkNextState = function(propValue, propData) switch(propValue) { case qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE: - case qx.util.fsm.FiniteStateMachine.StateChange.PREVIOUS_STATE: + case qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK: + case qx.util.fsm.FiniteStateMachine.StateChange.TERMINATE: return propValue; default: diff --git a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/example.txt b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/example.txt index bb92f70083..35e8282afe 100644 --- a/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/example.txt +++ b/webapps/qooxdoo-0.6.3-sdk/frontend/framework/source/class/qx/util/fsm/example.txt @@ -3,10 +3,10 @@ var state; var trans; // Create a new finite state machine called "Test Machine" -fsm = new qx.util.finitestatemachine.Fsm("Test machine"); +fsm = new qx.util.fsm.FiniteStateMachine("Test machine"); // State S1 -state = new qx.util.finitestatemachine.State( +state = new qx.util.fsm.State( // State name "S1", @@ -58,9 +58,9 @@ state = new qx.util.finitestatemachine.State( }; // also available, in same format as actionsBeforeOnentry: - // "actionsAfterOnentry", - // "actionsBeforeOnexit" - // "actionsAfterOnexit" + // "autoActionsAfterOnentry", + // "autoActionsBeforeOnexit" + // "autoActionsAfterOnexit" // Events handled by this state, or queued for processing by a future state "events" : @@ -70,7 +70,7 @@ state = new qx.util.finitestatemachine.State( // to the state, until the predicate for a transition returns true (or // no predicate is specified for the transition, which is an implicit // "true") That transition will be used. - "complete" : qx.util.finitestatemachine.Fsm.EventHandling.PREDICATE, + "complete" : qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE, // The event type "interval" has two objects specified by their // "friendly name". The action when an event of type "interval" occurs @@ -84,7 +84,7 @@ state = new qx.util.finitestatemachine.State( // If the target of the event was the object to which we have given // the friendly name "timeout", then enqueue this event for possible // processing by a future state. - "timeout" : qx.util.finitestatemachine.Fsm.EventHandling.BLOCKED + "timeout" : qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED }, // The event type "execute", too, has two objects specified by their @@ -94,12 +94,12 @@ state = new qx.util.finitestatemachine.State( // If the target of the event was the object to which we have given // the friend name "ok", search the transitions in order looking for // one where the predicate is true - "ok" : qx.util.finitestatemachine.Fsm.EventHandling.PREDICATE + "ok" : qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE // If the target of the event was the object to which we have given // the friendly name "restart", then enqueue this event for possible // processing by a future state. - "restart" : qx.util.finitestatemachine.Fsm.EventHandling.BLOCKED + "restart" : qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED } // all events other than those which are handled or blocked are ignored. @@ -110,7 +110,7 @@ state = new qx.util.finitestatemachine.State( fsm.addState(state); // Transition from S1 to S2 due to event 1 -trans = new qx.util.finitestatemachine.Transition( +trans = new qx.util.fsm.Transition( // Transition name "S1_S2_ev1", @@ -143,7 +143,7 @@ trans = new qx.util.finitestatemachine.Transition( // the state which was found at the top of the stack. States are added to // the state stack by calling fsm.pushState() during a state's onexit // function or by a transition's action function. - "nextState" : qx.util.finintestatemachine.Fsm.StateChange.POP_STATE_STACK, + "nextState" : qx.util.fsm.FiniteStateMachine.StateChange..POP_STATE_STACK, // action taken during transisition "action" : @@ -157,7 +157,7 @@ trans = new qx.util.finitestatemachine.Transition( state.addTransition(trans); // Default transition (any event): remain in current state -trans = new qx.util.finitestatemachine.Transition( +trans = new qx.util.fsm.Transition( "S1_S1_default", { // true or undefined : always pass @@ -174,7 +174,7 @@ trans = new qx.util.finitestatemachine.Transition( }, // return to current state - "nextState" : qx.util.finitestatemacine.CURRENT_STATE, + "nextState" : qx.util.fsm.FiniteStateMachine.StateChange.CURRENT_STATE, }); state.addTransition(trans); -- cgit