import logging import dbus.mainloop.glib from jarabe.model import shell from sugar.bundle.activitybundle import ActivityBundle from .vault import Vault from .TProbe import ProbeManager from .dbustools import save_args class TutorialRunner(object): """ Driver for the execution of one tutorial """ def __init__(self, tutorial, probeManager): """Constructor @param tutorial Tutorial to execute @param probeManager probeManager to use """ self._tutorial = tutorial self._pM = probeManager #State self._state = None self._sEvents = set() #Subscribed Events #Cached objects self._actions = {} #Temp FIX until event/actions have an activity id self._activity_id = None #Temp FIX until event, actions have an activity id def setCurrentActivity(self): self._pM.currentActivity = self._activity_id def start(self): self.setCurrentActivity() #Temp Hack until activity in events/actions self.setState(self._tutorial.INIT) def stop(self): self.setCurrentActivity() #Temp Hack until activity in events/actions self.setState(self._tutorial.END) self._teardownState() self._state = None def _handleEvent(self, next_state, event): #FIXME sanity check self.setState(next_state) def _teardownState(self): if self._state is None: #No state, no teardown return #Clear the current actions for action in self._actions.values(): self._pM.uninstall(action) self._actions = {} #Clear the EventFilters for event in self._sEvents: self._pM.unsubscribe(event) self._sEvents.clear() def _setupState(self): if self._state is None: raise RuntimeError("Attempting to setupState without a state") self._actions = self._tutorial.get_action_dict(self._state) transitions = self._tutorial.get_transition_dict(self._state) for (event, next_state) in transitions.values(): self._sEvents.add(self._pM.subscribe(event, save_args(self._handleEvent, next_state))) for action in self._actions.values(): self._pM.install(action) def setState(self, state_name): self.setCurrentActivity() #Temp Hack until activity in events/actions if state_name == self._state: #Nothing to do return self._teardownState() self._state = state_name self._setupState() class Engine: """ Driver for the execution of tutorials """ def __init__(self, probeManager=None): """Constructor @param probeManager (optional) ProbeManager instance to use """ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) #FIXME shell.get_model() will only be useful in the shell process self._shell = shell.get_model() self._probeManager = probeManager or ProbeManager() self._tutorial = None def launch(self, tutorialID): """ Launch a tutorial @param tutorialID unique tutorial identifier used to retrieve it from the disk """ if self._tutorial: self.stop() self._tutorial = TutorialRunner(Vault.loadTutorial(tutorialID), self._probeManager) #Get the active activity from the shell activity = self._shell.get_active_activity() #TProbes automatically use the bundle id, available from the ActivityBundle bundle = ActivityBundle(activity.get_bundle_path()) self._tutorial._activity_id = bundle.get_bundle_id() #HACK until we have activity id's in action/events self._tutorial.start() def stop(self, tutorialID=None): """ Stop the current tutorial """ if tutorialID is None: logging.warning( "stop() without a tutorialID will become deprecated") self._tutorial.stop() self._tutorial = None def pause(self, tutorialID=None): """ Interrupt the current tutorial and save its state in the journal """ if tutorialID is None: logging.warning( \ "pause() without a tutorialID will become deprecated") raise NotImplementedError("Unable to store tutorial state")