Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authormike <michael.jmontcalm@gmail.com>2009-03-18 01:38:49 (GMT)
committer mike <michael.jmontcalm@gmail.com>2009-03-18 01:38:49 (GMT)
commitf5d13236595810710aaab6c9622a12dc86045166 (patch)
treecb83007c79d6d9a908cab5fdbafd1123bdbfbf93 /src
parentf72cb15d47a1844218aed65826dfae9919e8f688 (diff)
TutoriusV2 : Adding data manipulation functions for FSM and State, some
exploration too
Diffstat (limited to 'src')
-rw-r--r--src/sugar/tutorius/core.py168
1 files changed, 151 insertions, 17 deletions
diff --git a/src/sugar/tutorius/core.py b/src/sugar/tutorius/core.py
index a699bbb..4b9e985 100644
--- a/src/sugar/tutorius/core.py
+++ b/src/sugar/tutorius/core.py
@@ -94,7 +94,7 @@ class Tutorial (object):
#Swith to the next state pointed by the eventfilter
self.set_state(eventfilter.get_next_state())
-class State:
+class State(object):
"""
This is a step in a tutorial. The state represents a collection of actions
to undertake when entering the state, and a series of event filters
@@ -113,6 +113,8 @@ class State:
this state
@param tutorial The higher level container of the state
"""
+ object.__init__(self)
+
self.name = name
self._actions = action_list
@@ -176,19 +178,64 @@ class State:
# Warn the higher level that we wish to change state
self.tutorial.set_state(event_filter.get_next_state())
+
+ # Model manipulation
+ # These functions are used to simplify the creation of states
+ def add_action(self, new_action):
+ """
+ Adds an action to the state (only if it wasn't added before)
+
+ @param new_action The new action to execute when in this state
+ @return True if added, False otherwise
+ """
+ if new_action not in self.action_list:
+ self.action_list.append(new_action)
+ return True
+ return False
+
+ # remove_action - We did not define names for the action, hence they're
+ # pretty hard to remove on a precise basis
+
+ def get_action_list(self):
+ """
+ @return A list of actions that the state will execute
+ """
+ return self.action_list
+
+ def clear_actions(self):
+ """
+ Removes all the action associated with this state. A cleared state will
+ not do anything when entered or exited.
+ """
+ self.action_list.clear()
+
+ def add_event_filter(self, event_filter):
+ """
+ Adds an event filter that will cause a transition from this state.
+
+ The same event filter may not be added twice.
+
+ @param event_filter The new event filter that will trigger a transition
+ @return True if added, False otherwise
+ """
+ if event_filter not in self.event_filter_list:
+ self.event_filter_list.append(event_filter)
+ return True
+ return False
- # Unused for now
-## def verify(self):
-## """Run the internal tests to see if one of them passes. If it does,
-## then do the associated processing to go in the next state."""
-## for test in self.tests:
-## if test.verify() == True:
-## actions = test.get_actions()
-## for act in actions:
-## act.do()
-## # Now that we execute the actions related to a test, we might
-## # want to undo them right after --- should we use a callback or
-## # a timer?
+ def get_event_filter_list(self):
+ """
+ @return The list of event filters associated with this state.
+ """
+ return self.event_filter_list
+
+ def clear_event_filters(self):
+ """
+ Removes all the event filters associated with this state. A state that
+ was just cleared will become a sink and will be the end of the
+ tutorial.
+ """
+ self.event_filter_list.clear()
class FiniteStateMachine(State):
"""
@@ -312,6 +359,13 @@ class FiniteStateMachine(State):
# Call the initial actions in the new state
self.setup()
+ def get_current_state_name(self):
+ """
+ Returns the name of the current state.
+
+ @return A string representing the name of the current state
+ """
+ return self.current_state.name
def teardown(self):
"""
@@ -332,7 +386,87 @@ class FiniteStateMachine(State):
# TODO : It might be nice to have a start() and stop() method for the
# FSM.
- #Unused for now
-## def verify(self):
-## """Verify if the current state passes its tests"""
-## return self.current_state.verify()
+ # Data manipulation section
+ # These functions are dedicated to the building and editing of a graph.
+ def add_state(self, new_state):
+ """
+ Inserts a new state in the FSM.
+
+ @param new_state The State object that will now be part of the FSM
+ @raise KeyError In the case where a state with this name already exists
+ """
+ if self.state_dict.has_key(new_state.name):
+ raise KeyError("There is already a state by this name in the FSM")
+
+ self.state_dict[new_state.name] = new_state
+
+ def remove_state(self, state_name):
+ """
+ Removes a state from the FSM. Raises a KeyError when the state is
+ not existent.
+
+ Warning : removing a state will also remove all the event filters that
+ point to this given name, to preserve the FSM's integrity. If you only
+ want to edit a state, you would be better off fetching this state with
+ get_state_by_name().
+
+ @param state_name A string being the name of the state to remove
+ @raise KeyError When the state_name does not a represent a real state
+ stored in the dictionary
+ """
+
+ state_to_remove = self.state_dict[state_name]
+
+ # Remove the state from the states' dictionnary
+ for st in self.state_dict.itervalues():
+ # Iterate through the list of event filters and remove those
+ # that point to the state that will be removed
+ for event_filter in st.event_filter_list:
+ if event_filter.get_next_state() == state_name:
+ st.event_filter_list.remove(event_filter)
+
+ # Remove the state from the dictionary
+ del self.state_dict[state_name]
+
+ # Exploration methods - used to know more about a given state
+ def get_following_states(self, state_name):
+ """
+ Returns a tuple of the names of the states that point to the given
+ state. If there is no such state, the function raises a KeyError.
+
+ @param state_name The name of the state to analyse
+ @raise KeyError When there is no state by this name in the FSM
+ """
+ state = self.state_dict[state_name]
+
+ next_states = Set()
+
+ for event_filter in state.event_filter_list:
+ next_states.insert(event_filter.get_next_state())
+
+ return tuple(next_states)
+
+ def get_previous_states(self, state_name):
+ """
+ Returns a tuple of the names of the state that can transition to
+ the given state. If there is no such state, the function raises a
+ KeyError.
+
+ @param state_name The name of the state that the returned states might
+ transition to.
+ """
+ # This might seem a bit funny, but we don't verify if the given
+ # state is present or not in the dictionary.
+ # This is due to the fact that when building a graph, we might have a
+ # prototypal state that has not been inserted yet. We could not know
+ # which states are pointing to it until we insert it in the graph.
+
+ states = []
+ # Walk through the list of states
+ for st in self.state_dict.itervalues():
+ for event_filter in st.event_filter_list:
+ if event_filter.get_next_state() == state_name:
+ states.append(event_filter.get_next_state())
+ continue
+
+ return tuple(states) \ No newline at end of file