From d3ce17cfffae2db3ddc3b94ea8b6c7e4ee733255 Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 27 Feb 2009 18:16:08 +0000 Subject: Merge branch 'tutorial_toolkit' of ssh://mike@bobthebuilder.mine.nu:8080/home/git into tutorial_toolkit --- diff --git a/src/sugar/tutorius/Makefile.am b/src/sugar/tutorius/Makefile.am index 9be1284..8389349 100644 --- a/src/sugar/tutorius/Makefile.am +++ b/src/sugar/tutorius/Makefile.am @@ -1,5 +1,6 @@ sugardir = $(pythondir)/sugar/tutorius sugar_PYTHON = \ - __init__.py \ - core.py \ - dialog.py + __init__.py \ + core.py \ + dialog.py \ + actions.py diff --git a/src/sugar/tutorius/actions.py b/src/sugar/tutorius/actions.py new file mode 100644 index 0000000..b48cb8b --- /dev/null +++ b/src/sugar/tutorius/actions.py @@ -0,0 +1,135 @@ +# Copyright (C) 2009, Tutorius.org +# +# 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 +""" +This module defines Actions that can be done and undone on a state +""" + +from dialog import TutoriusDialog + + +class Action(object): + """Base class for Actions""" + def __init__(self): + object.__init__(self) + + def do(self): + """ + Perform the action + """ + raise NotImplementedError("Not implemented") + + def undo(self): + """ + Revert anything the action has changed + """ + pass #Should raise NotImplemented? + + +class DoOnceMixin(object): + """Mixin class used to have an action be called only on the first do(). + + To use this mixin, create a new class that derives from this and from + the action you want executed only once. + + class ConcreteOnceAction(DoOnceMixin, ConcreteAction): + pass + + This ConcreteActions's do() method will only be called on the first do() + and the undo() will be callable after do() has been called + + Maybe it would be better off just using a wrapper class instead of this. + + But it was fun to play with. + + Did I mention the wrapper is 25 lines "south" of here? Besides, this mixin + class fails at __init__ ..... mixins... right....narwhals! + """ + def __init__(self ): + super(DoOnceMixin, self).__init + self._called = False + self._need_undo = False + + def do(self): + """ + Do the action only on the first time + """ + if not self._called: + self._called = True + super(DoOnceMixin, self).do() + self._need_undo = True + + def undo(self): + """ + Undo the action if it's been done + """ + if self._need_undo: + super(DoOnceMixin, self).undo() + self._need_undo = False + +class OnceWrapper(object): + """Wraps a class to perform an action once only + """ + def __init__(self, action): + self._action = action + self._called = False + self._need_undo = False + + def do(self): + """ + Do the action only on the first time + """ + if not self._called: + self._called = True + self._action.do() + self._need_undo = True + + def undo(self): + """ + Undo the action if it's been done + """ + if self._need_undo: + self._action.undo() + self._need_undo = False + +class DialogMessage(Action): + """Show a dialog!""" + def __init__(self, message): + super(DialogMessage, self).__init__(self) + self._message = message + self._dialog = None + + def do(self): + """ + Show the dialog + """ + self._dialog = TutoriusDialog(self._message) + self._dialog.set_button_clicked_cb(self._dialog.close_self) + self._dialog.set_modal(False) + self._dialog.show() + + def undo(self): + """ + Destroy the dialog + """ + if self._dialog: + self._dialog.destroy() + self._dialog = None + + + +class OnceDialogMessage(DoOnceMixin, DialogMessage): + """Broken!""" + pass diff --git a/src/sugar/tutorius/core.py b/src/sugar/tutorius/core.py index 8919057..62caee0 100644 --- a/src/sugar/tutorius/core.py +++ b/src/sugar/tutorius/core.py @@ -15,9 +15,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ -Module Tutorial +Core -This is the main module for Tutorius. +This module contains the core classes for tutorius """ @@ -57,6 +57,8 @@ class Event: return False + + class Tutorial (object): """ Tutorial Class, used to run through the FSM. @@ -139,18 +141,24 @@ class Tutorial (object): if not self.state_machine.has_key(name): return logger.debug("====NEW STATE: %s====" % name) + + #Remove handlers (TODO replace by EventFilter unregister) self.disconnect_handlers() + #Undo actions + for act in self.state_machine.get(self.state,{}).get("Actions",()): + act.undo() + + #Switch to new state self.state = name newstate = self.state_machine.get(name) + #Add handlers (TODO replace by EventFilter register) for event, unused in newstate["Events"]: self.register_signal(self.handle_event, \ event.object_name, event.event_name) - if newstate.has_key("Message"): - dlg = TutoriusDialog(newstate["Message"]) - dlg.set_button_clicked_cb(dlg.close_self) - dlg.run() - + #Do actions + for act in newstate.get("Actions",()): + act.do() def register_signals(self, target, handler, prefix=None, max_depth=None): """ @@ -322,7 +330,6 @@ class FiniteStateMachine(State): self.actions = setup_actions self.current_state = self.start_state - #TODO Setup current state now? def setup(self): """ -- cgit v0.9.1