Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'tutorius/core.py')
-rw-r--r--tutorius/core.py104
1 files changed, 56 insertions, 48 deletions
diff --git a/tutorius/core.py b/tutorius/core.py
index 4376315..6030457 100644
--- a/tutorius/core.py
+++ b/tutorius/core.py
@@ -21,14 +21,12 @@ This module contains the core classes for tutorius
"""
-import gtk
import logging
-import copy
import os
-from sugar.tutorius.dialog import TutoriusDialog
-from sugar.tutorius.gtkutils import find_widget
-from sugar.tutorius.services import ObjectStore
+from sugar.tutorius.TProbe import ProbeManager
+from sugar.tutorius.dbustools import save_args
+from sugar.tutorius import addon
logger = logging.getLogger("tutorius")
@@ -36,8 +34,11 @@ class Tutorial (object):
"""
Tutorial Class, used to run through the FSM.
"""
+ #Properties
+ probeManager = property(lambda self: self._probeMgr)
+ activityId = property(lambda self: self._activity_id)
- def __init__(self, name, fsm,filename= None):
+ def __init__(self, name, fsm, filename=None):
"""
Creates an unattached tutorial.
"""
@@ -51,21 +52,22 @@ class Tutorial (object):
self.state = None
self.handlers = []
- self.activity = None
+ self._probeMgr = ProbeManager()
+ self._activity_id = None
#Rest of initialisation happens when attached
- def attach(self, activity):
+ def attach(self, activity_id):
"""
Attach to a running activity
- @param activity the activity to attach to
+ @param activity_id the id of the activity to attach to
"""
#For now, absolutely detach if a previous one!
- if self.activity:
+ if self._activity_id:
self.detach()
- self.activity = activity
- ObjectStore().activity = activity
- ObjectStore().tutorial = self
+ self._activity_id = activity_id
+ self._probeMgr.attach(activity_id)
+ self._probeMgr.currentActivity = activity_id
self._prepare_activity()
self.state_machine.set_state("INIT")
@@ -77,9 +79,9 @@ class Tutorial (object):
# Uninstall the whole FSM
self.state_machine.teardown()
- #FIXME There should be some amount of resetting done here...
- self.activity = None
-
+ if not self._activity_id is None:
+ self._probeMgr.detach(self._activity_id)
+ self._activity_id = None
def set_state(self, name):
"""
@@ -100,9 +102,11 @@ class Tutorial (object):
#of the activity root directory
filename = os.getenv("SUGAR_ACTIVITY_ROOT") + "/data/" +\
self.activity_init_state_filename
- if os.path.exists(filename):
- self.activity.read_file(filename)
-
+ readfile = addon.create("ReadFile", filename=filename)
+ if readfile:
+ self._probeMgr.install(readfile)
+ #Uninstall now while we have the reference handy
+ self._probeMgr.uninstall(readfile)
class State(object):
"""
@@ -129,7 +133,9 @@ class State(object):
self._actions = action_list or []
- self._event_filters = event_filter_list or []
+ self._transitions= dict(event_filter_list or [])
+
+ self._installedEvents = set()
self.tutorial = tutorial
@@ -153,12 +159,11 @@ class State(object):
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 (event, next_state) in self._transitions.items():
+ self._installedEvents.add(self.tutorial.probeManager.subscribe(event, save_args(self._event_filter_state_done_cb, next_state )))
for action in self._actions:
- action.do()
+ self.tutorial.probeManager.install(action)
def teardown(self):
"""
@@ -167,24 +172,25 @@ class State(object):
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()
+ while len(self._installedEvents) > 0:
+ self.tutorial.probeManager.unsubscribe(self._installedEvents.pop())
# Undo all the actions related to this state
for action in self._actions:
- action.undo()
+ self.tutorial.probeManager.uninstall(action)
- def _event_filter_state_done_cb(self, event_filter):
+ def _event_filter_state_done_cb(self, next_state, event):
"""
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
+ @param next_state The next state for the transition
+ @param event The event that occured
"""
# 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())
+ self.tutorial.set_state(next_state)
# Model manipulation
# These functions are used to simplify the creation of states
@@ -212,19 +218,21 @@ class State(object):
Removes all the action associated with this state. A cleared state will
not do anything when entered or exited.
"""
+ #FIXME What if the action is currently installed?
self._actions = []
- def add_event_filter(self, event_filter):
+ def add_event_filter(self, event, next_state):
"""
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
+ @param event The event that will trigger a transition
+ @param next_state The state to which the transition will lead
@return True if added, False otherwise
"""
- if event_filter not in self._event_filters:
- self._event_filters.append(event_filter)
+ if event not in self._transitions.keys():
+ self._transitions[event]=next_state
return True
return False
@@ -232,7 +240,7 @@ class State(object):
"""
@return The list of event filters associated with this state.
"""
- return self._event_filters
+ return self._transitions.items()
def clear_event_filters(self):
"""
@@ -240,7 +248,7 @@ class State(object):
was just cleared will become a sink and will be the end of the
tutorial.
"""
- self._event_filters = []
+ self._transitions = {}
def __eq__(self, otherState):
"""
@@ -385,8 +393,8 @@ class FiniteStateMachine(State):
# 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()
+ for action in self.actions:
+ self.tutorial.probeManager.install(action)
# Then, we need to run the setup of the current state
self.current_state.setup()
@@ -450,8 +458,8 @@ class FiniteStateMachine(State):
# 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()
+ for action in self.actions:
+ self.tutorial.probeManager.uninstall(action)
# TODO : It might be nice to have a start() and stop() method for the
# FSM.
@@ -507,9 +515,9 @@ class FiniteStateMachine(State):
#TODO : Move this code inside the State itself - we're breaking
# encap :P
- for event_filter in st._event_filters:
- if event_filter.get_next_state() == state_name:
- st._event_filters.remove(event_filter)
+ for event, state in st._transitions:
+ if state == state_name:
+ del st._transitions[event]
# Remove the state from the dictionary
del self._states[state_name]
@@ -527,8 +535,8 @@ class FiniteStateMachine(State):
next_states = set()
- for event_filter in state._event_filters:
- next_states.add(event_filter.get_next_state())
+ for event, state in state._transitions:
+ next_states.add(state)
return tuple(next_states)
@@ -550,9 +558,9 @@ class FiniteStateMachine(State):
states = []
# Walk through the list of states
for st in self._states.itervalues():
- for event_filter in st._event_filters:
- if event_filter.get_next_state() == state_name:
- states.append(event_filter.get_next_state())
+ for event, state in st._transitions:
+ if state == state_name:
+ states.append(state)
continue
return tuple(states)