mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
r20937: Update to latest Finite State Machine with properly-handled blocked events
(This used to be commit 98eeba919c
)
This commit is contained in:
parent
a8a702a6c9
commit
926aed2c82
@ -5,7 +5,7 @@
|
||||
http://qooxdoo.org
|
||||
|
||||
Copyright:
|
||||
2006 by Derrell Lipman
|
||||
2006, 2007 by Derrell Lipman
|
||||
|
||||
License:
|
||||
LGPL 2.1: http://www.gnu.org/licenses/lgpl.html
|
||||
@ -24,16 +24,11 @@
|
||||
/**
|
||||
* A finite state machine.
|
||||
*
|
||||
* See {@see qx.util.finitestatemacine.State} for details on creating States,
|
||||
* and {@see qx.util.finitestatemacine.Transitions} for details on creating
|
||||
* See {@link qx.util.finitestatemacine.State} for details on creating States,
|
||||
* and {@link qx.util.finitestatemacine.Transitions} for details on creating
|
||||
* transitions between states.
|
||||
*
|
||||
* *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 machineName {string} The name of this finite state machine
|
||||
* @param machineName {String} The name of this finite state machine
|
||||
*
|
||||
*/
|
||||
qx.OO.defineClass("qx.util.fsm.FiniteStateMachine", qx.core.Target,
|
||||
@ -201,7 +196,7 @@ qx.Proto.addState = function(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}
|
||||
* @param bDispose {Boolean}
|
||||
* If <i>true</i>, then dispose the old state object. If <i>false</i>, the
|
||||
* old state object is returned for disposing by the caller.
|
||||
*
|
||||
@ -242,7 +237,7 @@ qx.Proto.replaceState = function(state, bDispose)
|
||||
* Add an object (typically a widget) that is to be accessed during state
|
||||
* transitions, to the finite state machine.
|
||||
*
|
||||
* @param friendlyName {string}
|
||||
* @param friendlyName {String}
|
||||
* The friendly name to used for access to the object being added.
|
||||
*
|
||||
* @param obj {Object}
|
||||
@ -301,9 +296,9 @@ qx.Proto.addObject = function(friendlyName, obj, groupNames)
|
||||
|
||||
|
||||
/**
|
||||
* Remove an object which had previously been added by {@see #addObject}.
|
||||
* Remove an object which had previously been added by {@link #addObject}.
|
||||
*
|
||||
* @param friendlyName {string}
|
||||
* @param friendlyName {String}
|
||||
* The friendly name associated with an object, specifying which object is
|
||||
* to be removed.
|
||||
*/
|
||||
@ -330,10 +325,10 @@ qx.Proto.removeObject = function(friendlyName)
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an object previously saved via {@see #addObject}, using its
|
||||
* Retrieve an object previously saved via {@link #addObject}, using its
|
||||
* Friendly Name.
|
||||
*
|
||||
* @param friendlyName {string}
|
||||
* @param friendlyName {String}
|
||||
* The friendly name of the object to be retrieved.
|
||||
*
|
||||
* @return {Object}
|
||||
@ -351,8 +346,8 @@ qx.Proto.getObject = function(friendlyName)
|
||||
*
|
||||
* @param obj {Object} The object for which the friendly name is desired
|
||||
*
|
||||
* @return {string}
|
||||
* If the object has been previously registered via {@see #addObject}, then
|
||||
* @return {String}
|
||||
* If the object has been previously registered via {@link #addObject}, then
|
||||
* the friendly name of the object is returned; otherwise, null.
|
||||
*/
|
||||
qx.Proto.getFriendlyName = function(obj)
|
||||
@ -363,10 +358,10 @@ qx.Proto.getFriendlyName = function(obj)
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the list of objects which have registered, via {@see addObject} as
|
||||
* Retrieve the list of objects which have registered, via {@link addObject} as
|
||||
* being members of the specified group.
|
||||
*
|
||||
* @param groupName {string}
|
||||
* @param groupName {String}
|
||||
* The name of the group for which the member list is desired.
|
||||
*
|
||||
* @return {Array}
|
||||
@ -417,7 +412,7 @@ qx.Proto.displayAllObjects = function()
|
||||
* @param obj {Object}
|
||||
* The object to be recursively displayed
|
||||
*/
|
||||
qx.Proto.debugObject = function(obj)
|
||||
qx.Proto.debugObject = function(obj, initialMessage)
|
||||
{
|
||||
thisClass = this;
|
||||
|
||||
@ -457,6 +452,11 @@ qx.Proto.debugObject = function(obj)
|
||||
}
|
||||
}
|
||||
|
||||
if (initialMessage)
|
||||
{
|
||||
this.debug(initialMessage);
|
||||
}
|
||||
|
||||
displayObj(obj, 0);
|
||||
};
|
||||
|
||||
@ -523,7 +523,7 @@ qx.Proto.start = function()
|
||||
* 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}
|
||||
* @param bCurrent {Boolean}
|
||||
* When <i>true</i>, then push the current state onto the stack. This might
|
||||
* be used in a transition, before the state has changed. When
|
||||
* <i>false</i>, then push the previous state onto the stack. This might be
|
||||
@ -593,7 +593,7 @@ qx.Proto.copyEvent = function(event)
|
||||
* @param event {qx.event.type.Event}
|
||||
* The event to be enqueued
|
||||
*
|
||||
* @param bAddAtHead {boolean}
|
||||
* @param bAddAtHead {Boolean}
|
||||
* If <i>true</i>, put the event at the head of the queue for immediate
|
||||
* processing. If <i>false</i>, place the event at the tail of the queue so
|
||||
* that it receives in-order processing.
|
||||
@ -603,7 +603,7 @@ qx.Proto.enqueueEvent = function(event, bAddAtHead)
|
||||
// Add the event to the event queue
|
||||
if (bAddAtHead)
|
||||
{
|
||||
// Put event at the head of the queue
|
||||
// Put event at the head of the queue
|
||||
this._eventQueue.push(event);
|
||||
}
|
||||
else
|
||||
@ -673,10 +673,13 @@ qx.Proto._processEvents = function()
|
||||
var event = this._eventQueue.pop();
|
||||
|
||||
// Run the finite state machine with this event
|
||||
this._run(event);
|
||||
var bDispose = this._run(event);
|
||||
|
||||
// We can now dispose the event
|
||||
event.dispose();
|
||||
// If we didn't block (and re-queue) the event, dispose it.
|
||||
if (bDispose)
|
||||
{
|
||||
event.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// We're no longer processing events
|
||||
@ -691,6 +694,10 @@ qx.Proto._processEvents = function()
|
||||
* current state handles this event type), queued (if the current state
|
||||
* blocks this event type), or discarded (if the current state neither
|
||||
* handles nor blocks this event type).
|
||||
*
|
||||
* @return {Boolean}
|
||||
* Whether the event should be disposed. If it was blocked, we've pushed it
|
||||
* back onto the event queue, and it should not be disposed.
|
||||
*/
|
||||
qx.Proto._run = function(event)
|
||||
{
|
||||
@ -749,12 +756,12 @@ qx.Proto._run = function(event)
|
||||
// See if we actually found this event type
|
||||
if (! e)
|
||||
{
|
||||
if (this.debugEvents)
|
||||
if (debugEvents)
|
||||
{
|
||||
this.debug(this.getName() + ": Event '" + event.getType() + "'" +
|
||||
" not handled. Ignoring.");
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We might have found a constant (PREDICATE or BLOCKED) or an object with
|
||||
@ -772,7 +779,7 @@ qx.Proto._run = function(event)
|
||||
this.debug(this.getName() + ": Could not find friendly name for '" +
|
||||
event.getType() + "' on '" + event.getTarget() + "'");
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
action = e[friendly];
|
||||
@ -790,8 +797,13 @@ qx.Proto._run = function(event)
|
||||
|
||||
case qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED:
|
||||
// This event is blocked. Enqueue it for later, and get outta here.
|
||||
if (debugEvents)
|
||||
{
|
||||
this.debug(this.getName() + ": Event '" + event.getType() + "'" +
|
||||
" blocked. Re-queuing.");
|
||||
}
|
||||
this._blockedEvents.unshift(event);
|
||||
return;
|
||||
return false;
|
||||
|
||||
default:
|
||||
// See if we've been given an explicit transition name
|
||||
@ -833,12 +845,11 @@ qx.Proto._run = function(event)
|
||||
|
||||
case null:
|
||||
// Transition indicates not to try further transitions
|
||||
return;
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw new Error("Transition " + thisState + ":" + t +
|
||||
" returned a value other than true, false, or null.");
|
||||
return;
|
||||
}
|
||||
|
||||
// We think we can transition to the next state. Set next state.
|
||||
@ -971,15 +982,14 @@ qx.Proto._run = function(event)
|
||||
}
|
||||
currentState.getAutoActionsAfterOnentry()(this);
|
||||
|
||||
// Add the blocked events to the pending event queue
|
||||
if (this._blockedEvents.length > 0)
|
||||
// Add any blocked events back onto the pending event queue
|
||||
var e;
|
||||
for (var i = 0; i < this._blockedEvents.length; i++)
|
||||
{
|
||||
this._eventQueue.unshift(this._blockedEvents);
|
||||
e = this._blockedEvents.pop();
|
||||
this._eventQueue.unshift(e);
|
||||
}
|
||||
|
||||
// The blocked event list is now empty
|
||||
this._blockedEvents = [ ];
|
||||
|
||||
// Ensure that all actions have been flushed
|
||||
qx.ui.core.Widget.flushGlobalQueues();
|
||||
|
||||
@ -990,7 +1000,7 @@ qx.Proto._run = function(event)
|
||||
}
|
||||
|
||||
// See ya!
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (debugTransitions)
|
||||
@ -999,6 +1009,8 @@ qx.Proto._run = function(event)
|
||||
": event '" + event.getType() + "'" +
|
||||
": no transition found. No state change.");
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@ -1137,7 +1149,7 @@ qx.Settings.setDefault(
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
* @param actionType {string}
|
||||
* @param actionType {String}
|
||||
* The name of the action being validated (for debug messages)
|
||||
*
|
||||
* @param propValue {Object}
|
||||
@ -1383,4 +1395,4 @@ qx.Proto.dispose = function()
|
||||
this._states = null;
|
||||
|
||||
return qx.core.Target.prototype.dispose.call(this);
|
||||
}
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ qx.Proto.buildFsm = function(module)
|
||||
"to build its custom finite state machine.");
|
||||
};
|
||||
|
||||
qx.Proto.addAwaitRpcResultState = function(module)
|
||||
qx.Proto.addAwaitRpcResultState = function(module, blockedEvents)
|
||||
{
|
||||
var fsm = module.fsm;
|
||||
var _this = this;
|
||||
@ -47,104 +47,124 @@ qx.Proto.addAwaitRpcResultState = function(module)
|
||||
* "failed" (on RPC)
|
||||
* "execute" on swat.main.fsmUtils.abort_rpc
|
||||
*/
|
||||
var state = new qx.util.fsm.State(
|
||||
"State_AwaitRpcResult",
|
||||
|
||||
var stateInfo =
|
||||
{
|
||||
"autoActionsBeforeOnentry" :
|
||||
{
|
||||
"autoActionsBeforeOnentry" :
|
||||
{
|
||||
// The name of a function.
|
||||
"setEnabled" :
|
||||
[
|
||||
{
|
||||
// We want to enable objects in the group
|
||||
// swat.main.fsmUtils.enable_during_rpc
|
||||
"parameters" : [ true ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(true) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.enable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.enable_during_rpc" ]
|
||||
},
|
||||
|
||||
{
|
||||
// We want to disable objects in the group
|
||||
// swat.main.fsmUtils.disable_during_rpc
|
||||
"parameters" : [ false ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(false) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.disable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.disable_during_rpc" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"autoActionsBeforeOnexit" :
|
||||
{
|
||||
// The name of a function.
|
||||
"setEnabled" :
|
||||
[
|
||||
{
|
||||
// We want to re-disable objects we had enabled, in the group
|
||||
// swat.main.fsmUtils.enable_during_rpc
|
||||
"parameters" : [ false ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(false) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.enable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.enable_during_rpc" ]
|
||||
},
|
||||
|
||||
{
|
||||
// We want to re-enable objects we had disabled, in the group
|
||||
// swat.main.fsmUtils.disable_during_rpc
|
||||
"parameters" : [ true ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(true) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.disable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.disable_during_rpc" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"onentry" :
|
||||
function(fsm, event)
|
||||
// The name of a function.
|
||||
"setEnabled" :
|
||||
[
|
||||
{
|
||||
var bAuthCompleted = false;
|
||||
// We want to enable objects in the group
|
||||
// swat.main.fsmUtils.enable_during_rpc
|
||||
"parameters" : [ true ],
|
||||
|
||||
// See if we just completed an authentication
|
||||
if (fsm.getPreviousState() == "State_Authenticate" &&
|
||||
event.getType() == "complete")
|
||||
{
|
||||
bAuthCompleted = true;
|
||||
}
|
||||
|
||||
// If we didn't just complete an authentication and we're coming
|
||||
// from some other state...
|
||||
if (! bAuthCompleted &&
|
||||
fsm.getPreviousState() != "State_AwaitRpcResult")
|
||||
{
|
||||
// ... then push the previous state onto the state stack
|
||||
fsm.pushState(false);
|
||||
}
|
||||
// Call this.getObject(<object>).setEnabled(true) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.enable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.enable_during_rpc" ]
|
||||
},
|
||||
|
||||
"events" :
|
||||
{
|
||||
"execute" :
|
||||
{
|
||||
"swat.main.fsmUtils.abort_rpc" :
|
||||
"Transition_AwaitRpcResult_to_AwaitRpcResult_via_button_abort"
|
||||
// We want to disable objects in the group
|
||||
// swat.main.fsmUtils.disable_during_rpc
|
||||
"parameters" : [ false ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(false) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.disable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.disable_during_rpc" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"autoActionsBeforeOnexit" :
|
||||
{
|
||||
// The name of a function.
|
||||
"setEnabled" :
|
||||
[
|
||||
{
|
||||
// We want to re-disable objects we had enabled, in the group
|
||||
// swat.main.fsmUtils.enable_during_rpc
|
||||
"parameters" : [ false ],
|
||||
|
||||
// Call this.getObject(<object>).setEnabled(false) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.enable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.enable_during_rpc" ]
|
||||
},
|
||||
|
||||
"completed" :
|
||||
"Transition_AwaitRpcResult_to_PopStack_via_complete",
|
||||
{
|
||||
// We want to re-enable objects we had disabled, in the group
|
||||
// swat.main.fsmUtils.disable_during_rpc
|
||||
"parameters" : [ true ],
|
||||
|
||||
"failed" :
|
||||
qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE
|
||||
// Call this.getObject(<object>).setEnabled(true) on
|
||||
// state entry, for each <object> in the group called
|
||||
// "swat.main.fsmUtils.disable_during_rpc".
|
||||
"groups" : [ "swat.main.fsmUtils.disable_during_rpc" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"onentry" :
|
||||
function(fsm, event)
|
||||
{
|
||||
var bAuthCompleted = false;
|
||||
|
||||
// See if we just completed an authentication
|
||||
if (fsm.getPreviousState() == "State_Authenticate" &&
|
||||
event.getType() == "complete")
|
||||
{
|
||||
bAuthCompleted = true;
|
||||
}
|
||||
|
||||
// If we didn't just complete an authentication and we're coming
|
||||
// from some other state...
|
||||
if (! bAuthCompleted &&
|
||||
fsm.getPreviousState() != "State_AwaitRpcResult")
|
||||
{
|
||||
// ... then push the previous state onto the state stack
|
||||
fsm.pushState(false);
|
||||
}
|
||||
},
|
||||
|
||||
"events" :
|
||||
{
|
||||
"execute" :
|
||||
{
|
||||
"swat.main.fsmUtils.abort_rpc" :
|
||||
"Transition_AwaitRpcResult_to_AwaitRpcResult_via_button_abort"
|
||||
},
|
||||
|
||||
"completed" :
|
||||
"Transition_AwaitRpcResult_to_PopStack_via_complete",
|
||||
|
||||
"failed" :
|
||||
qx.util.fsm.FiniteStateMachine.EventHandling.PREDICATE
|
||||
}
|
||||
};
|
||||
|
||||
// If there are blocked events specified...
|
||||
if (blockedEvents)
|
||||
{
|
||||
// ... then add them to the state info events object
|
||||
for (var blockedEvent in blockedEvents)
|
||||
{
|
||||
// Ensure it's not already there. Avoid programmer headaches.
|
||||
if (stateInfo["events"][blockedEvent])
|
||||
{
|
||||
throw new Error("Attempt to add blocked event " +
|
||||
blockedEvent + " but it is already handled");
|
||||
}
|
||||
});
|
||||
|
||||
// Add the event.
|
||||
stateInfo["events"][blockedEvent] = blockedEvents[blockedEvent];
|
||||
}
|
||||
}
|
||||
|
||||
var state = new qx.util.fsm.State( "State_AwaitRpcResult", stateInfo);
|
||||
fsm.addState(state);
|
||||
|
||||
/*** Transitions that use a PREDICATE appear first ***/
|
||||
|
@ -377,8 +377,32 @@ qx.Proto.buildFsm = function(module)
|
||||
});
|
||||
state.addTransition(trans);
|
||||
|
||||
// Create the list of events that should be blocked while we're awaiting the
|
||||
// results of another RPC request
|
||||
blockedEvents =
|
||||
{
|
||||
// If a previously unexpanded tree node is expanded, issue a request
|
||||
// to retrieve its contents.
|
||||
"treeOpenWhileEmpty":
|
||||
{
|
||||
"tree" :
|
||||
qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
|
||||
},
|
||||
|
||||
// If the selection changes, issue a request to retrieve contents to
|
||||
// populate the attribute/value table.
|
||||
"changeSelection":
|
||||
{
|
||||
"tree:manager" :
|
||||
qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED,
|
||||
|
||||
"dbName":
|
||||
qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
|
||||
}
|
||||
}
|
||||
|
||||
// Add the AwaitRpcResult state and all of its transitions
|
||||
this.addAwaitRpcResultState(module);
|
||||
this.addAwaitRpcResultState(module, blockedEvents);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user