# Copyright (C) 2009, Tutorius.org # Copyright (C) 2009, Vincent Vinet # # 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 import gtk import logging from sugar.tutorius.dialog import TutoriusDialog logger = logging.getLogger("tutorius") class Event: def __init__(self, object_name, event_name ): self.object_name = object_name self.event_name = event_name def test(self, sig, name): if self.object_name == name and self.event_name == sig: return True return False class Tutorial (object): EVENTS = [ "focus", "button-press-event", "enter-notify-event", "leave-notify-event", "key-press-event", "text-selected", "clicked", ] IGNORED_WIDGETS = [ "GtkVBox", "GtkHBox", "GtkAlignment", "GtkNotebook", "GtkButton", "GtkToolItem", "GtkToolbar", ] def __init__(self, name, fsm): object.__init__(self) self.name = name self.state_machine = fsm self.handlers = [] self.activity = None #self.setState("INIT") #self.state="INIT" #self.register_signals(self.activity, self.handleEvent, max_depth=10) def attach(self, activity): #For now, absolutely detach if a previous one! if self.activity: self.detach() self.activity = activity self.state="INIT" self.register_signals(self.activity,self.handleEvent, max_depth=10) def detach(self): self.disconnectHandlers() self.activity = None def handleEvent(self, *args): sig, objname = args[-1] logger.debug("EVENT %s ON %s" % (sig, objname) ) for transition, next in self.state_machine[self.state]["Events"]: if transition.test(sig,objname): logger.debug("====NEW STATE: %s====" % next) self.state = next dlg = TutoriusDialog(self.state_machine[self.state]["Message"]) dlg.setButtonClickedCallback(dlg.closeSelf) dlg.run() # @staticmethod # def logEvent(obj, *args): # logger.debug("%s" % str(args[-1])) def disconnectHandlers(self): for t, id in self.handlers: t.disconnect_handler(id) # def setState(self,name): # self.disconnectHandlers() # self.state = name # newstate = ABIWORD_MEF.get(name,()) # for event, n in newstate: # target = self.activity # try: # for obj in event.object_name.split("."): # target = getattr(target,obj) # id = target.connect(self.handler,(event.object_name, event.event_name)) # self.handlers.append(target, id) # id = target.connect(Tutorial.logEvent,"EVENT %s ON %s" % (event.object_name, event.event_name)) # self.handlers.append(target, id) # except Exception, e: # logger.debug(str(e)) def register_signals(self,object,handler,prefix=None,max_depth=None): """ Recursive function to register event handlers on an object and it's children. The event handler is called with an extra argument which is a two-tuple containing the signal name and the FQDN-style name of the object that triggered the event. This function registers all of the events listed in Tutorial.EVENTS and omits widgets with a name matching Tutorial.IGNORED_WIDGETS from the name hierarchy. Example arg tuple added: ("focus", "Activity.Toolbox.Bold") Side effects: -Handlers connected on the various objects -Handler ID's stored in self.handlers @param object the object to recurse on @param handler the handler function to connect @param prefix name prepended to the object name to form a chain @param max_depth maximum recursion depth, None for infinity """ #Gtk Containers have a get_children() function if hasattr(object,"get_children") and \ hasattr(object.get_children,"__call__"): for child in object.get_children(): if max_depth is None or max_depth > 0: #Recurse with a prefix on all children pre = ".".join( \ [p for p in (prefix, object.get_name()) \ if not (p is None or p in Tutorial.IGNORED_WIDGETS)] \ ) self.register_signals(child,handler,pre,max_depth-1) name = ".".join( \ [p for p in (prefix, object.get_name()) \ if not (p is None or p in Tutorial.IGNORED_WIDGETS)] \ ) #register events on the object if a widget XXX necessary to check this? if isinstance(object,gtk.Widget): for sig in Tutorial.EVENTS: try: self.handlers.append( (object,object.connect(sig,handler,(sig, name) )) ) except TypeError: continue