diff options
Diffstat (limited to 'sugar-toolkit/src/sugar/tutorius/core.py')
-rw-r--r-- | sugar-toolkit/src/sugar/tutorius/core.py | 334 |
1 files changed, 0 insertions, 334 deletions
diff --git a/sugar-toolkit/src/sugar/tutorius/core.py b/sugar-toolkit/src/sugar/tutorius/core.py deleted file mode 100644 index f817ba9..0000000 --- a/sugar-toolkit/src/sugar/tutorius/core.py +++ /dev/null @@ -1,334 +0,0 @@ -# Copyright (C) 2009, Tutorius.org -# Copyright (C) 2009, Vincent Vinet <vince.vinet@gmail.com> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -""" -Core - -This module contains the core classes for tutorius - -""" - -import gtk -import logging - -from sugar.tutorius.dialog import TutoriusDialog -from sugar.tutorius.gtkutils import find_widget - -logger = logging.getLogger("tutorius") - -class Tutorial (object): - """ - Tutorial Class, used to run through the FSM. - """ - - def __init__(self, name, fsm): - """ - Creates an unattached tutorial. - """ - object.__init__(self) - self.name = name - - self.state_machine = fsm - self.state_machine.set_tutorial(self) - - self.state = None - - self.handlers = [] - self.activity = None - #Rest of initialisation happens when attached - - def attach(self, activity): - """ - Attach to a running activity - - @param activity the activity to attach to - """ - #For now, absolutely detach if a previous one! - if self.activity: - self.detach() - self.activity = activity - self.state_machine.set_state("INIT") - - def detach(self): - """ - Detach from the current activity - """ - - # Uninstall the whole FSM - self.state_machine.teardown() - - #FIXME There should be some amount of resetting done here... - self.activity = None - - - def set_state(self, name): - """ - Switch to a new state - """ - logger.debug("====NEW STATE: %s====" % name) - - self.state_machine.set_state(name) - - - # Currently unused -- equivalent function is in each state - def _eventfilter_state_done(self, eventfilter): - """ - Callback handler for eventfilter to notify - when we must go to the next state. - """ - #XXX Tests should be run here normally - - #Swith to the next state pointed by the eventfilter - self.set_state(eventfilter.get_next_state()) - -class State: - """ - 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 - with associated actions that point to a possible next state. - """ - - def __init__(self, name, action_list=[], event_filter_list=[], tutorial=None): - """ - Initializes the content of the state, like loading the actions - that are required and building the correct tests. - - @param action_list The list of actions to execute when entering this - state - @param event_filter_list A list of tuples of the form - (event_filter, next_state_name), that explains the outgoing links for - this state - @param tutorial The higher level container of the state - """ - self._actions = action_list - - # Unused for now - #self.tests = [] - - self._event_filters = event_filter_list - - self.tutorial = tutorial - - def set_tutorial(self, tutorial): - """ - Associates this state with a tutorial. A tutorial must be set prior - to executing anything in the state. The reason for this is that the - states need to have access to the activity (via the tutorial) in order - to properly register their callbacks on the activities' widgets. - - @param tutorial The tutorial that this state runs under. - """ - if self.tutorial == None : - self.tutorial = tutorial - else: - raise RuntimeWarning(\ - "The state %s was already associated with a tutorial." % self.name) - - def setup(self): - """ - Install the state itself, by first registering the event filters - and then triggering the actions. - """ - for eventfilter in self._event_filters: - eventfilter.install_handlers(self._event_filter_state_done_cb, - activity=self.tutorial.activity) - - for action in self._actions: - action.do() - - def teardown(self): - """ - Uninstall all the event filters that were active in this state. - Also undo every action that was installed for this state. This means - removing dialogs that were displayed, removing highlights, etc... - """ - # Remove the handlers for the all of the state's event filters - for event_filter in self._event_filters: - event_filter.remove_handlers() - - # Undo all the actions related to this state - for action in self._actions: - action.undo() - - def _event_filter_state_done_cb(self, event_filter): - """ - Callback for event filters. This function needs to inform the - tutorial that the state is over and tell it what is the next state. - - @param event_filter The event filter that was called - """ - # Run the tests here, if need be - - # Warn the higher level that we wish to change state - self.tutorial.set_state(event_filter.get_next_state()) - - # 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? - -class FiniteStateMachine(State): - """ - This is a collection of states, with a start state and an end callback. - It is used to simplify the development of the various tutorials by - encapsulating a collection of states that represent a given learning - process. - - For now, we will consider that there can only be states - inserted in the FSM, and that there are no nested FSM inside. - """ - - def __init__(self, name, tutorial=None, state_dict={}, start_state_name="INIT", action_list=[]): - """ - The constructor for a FSM. Pass in the start state and the setup - actions that need to be taken when the FSM itself start (which may be - different from what is done in the first state of the machine). - - @param name A short descriptive name for this FSM - @param tutorial The tutorial that will execute this FSM. If None is - attached on creation, then one must absolutely be attached before - executing the FSM with set_tutorial(). - @param state_dict A dictionary containing the state names as keys and - the state themselves as entries. - @param start_state_name The name of the starting state, if different - from "INIT" - @param action_list The actions to undertake when initializing the FSM - """ - State.__init__(self, name) - - self.name = name - self.tutorial = tutorial - - # Dictionnary of states contained in the FSM - self._states = state_dict - - # Remember the initial state - we might want to reset - # or rewind the FSM at a later moment - self.start_state = state_dict[start_state_name] - self.current_state = self.start_state - - # Register the actions for the FSM - They will be processed at the - # FSM level, meaning that when the FSM will start, it will first - # execute those actions. When the FSM closes, it will tear down the - # inner actions of the state, then close its own actions - self.actions = action_list - - # Flag to mention that the FSM was initialized - self._fsm_setup_done = False - # Flag that must be raised when the FSM is to be teared down - self._fsm_teardown_done = False - # Flag used to declare that the FSM has reached an end state - self._fsm_has_finished = False - - def set_tutorial(self, tutorial): - """ - This associates the FSM to the given tutorial. It MUST be associated - either in the constructor or with this function prior to executing the - FSM. - - @param tutorial The tutorial that will execute this FSM. - """ - # If there was no tutorial associated - if self.tutorial == None: - # Associate it with this FSM and all the underlying states - self.tutorial = tutorial - for state in self._states.itervalues(): - state.set_tutorial(tutorial) - else: - raise RuntimeWarning(\ - "The FSM %s is already associated with a tutorial."%self.name\ - ) - - def setup(self): - """ - This function initializes the FSM the first time it is called. - Then, every time it is called, it initializes the current state. - """ - # Are we associated with a tutorial? - if self.tutorial == None: - raise UnboundLocalError("No tutorial was associated with FSM %s" % self.name) - - # If we never initialized the FSM itself, then we need to run all the - # actions associated with the FSM. - if self._fsm_setup_done == False: - # Flag the FSM level setup as done - self._fsm_setup_done = True - # Execute all the FSM level actions - for action in self.actions: - action.do() - - # Then, we need to run the setup of the current state - self.current_state.setup() - - def set_state(self, new_state_name): - """ - This functions changes the current state of the finite state machine. - - @param new_state The identifier of the state we need to go to - """ - # TODO : Since we assume no nested FSMs, we don't set state on the - # inner States / FSMs -## # Pass in the name to the internal state - it might be a FSM and -## # this name will apply to it -## self.current_state.set_state(new_state_name) - - # Make sure the given state is owned by the FSM - if not self._states.has_key(new_state_name): - # If we did not recognize the name, then we do not possess any - # state by that name - we must ignore this state change request as - # it will be done elsewhere in the hierarchy (or it's just bogus). - return - - new_state = self._states[new_state_name] - - # Undo the actions of the old state - self.teardown() - - # Insert the new state - self.current_state = new_state - - # Call the initial actions in the new state - self.setup() - - - def teardown(self): - """ - Revert any changes done by setup() - """ - # Teardown the current state - self.current_state.teardown() - - # If we just finished the whole FSM, we need to also call the teardown - # on the FSM level actions - if self._fsm_has_finished == True: - # Flag the FSM teardown as not needed anymore - self._fsm_teardown_done = True - # Undo all the FSM level actions here - for action in self.actions: - action.undo() - - #Unused for now -## def verify(self): -## """Verify if the current state passes its tests""" -## return self.current_state.verify() |