# 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 gobject import gtk import logging logger = logging.getLogger("filters") from sugar.tutorius.gtkutils import find_widget from sugar.tutorius.services import ObjectStore from sugar.tutorius import properties class EventFilter(properties.TPropContainer): """ Base class for an event filter """ next_state = properties.TStringProperty("None") def __init__(self, next_state=None): """ Constructor. @param next_state name of the next state """ super(EventFilter, self).__init__() if next_state: self.next_state = next_state self._callback = None def get_next_state(self): """ Getter for the next state """ return self.next_state def set_next_state(self, new_next_name): """ Setter for the next state. Should only be used during construction of the event_fitler, not while the tutorial is running. """ self.next_state = new_next_name def install_handlers(self, callback, **kwargs): """ install_handlers is called for eventfilters to setup all necessary event handlers to be able to catch the desired event. @param callback the callback function that will be called with the event filter as an argument when the event is catched and validated. @param **kwargs unused by this handler for now, allows subclasses to receive information about the context when installing Subclasses must call this super method to setup the callback if they feel like cooperating """ self._callback = callback def remove_handlers(self): """ remove_handlers is called when a state is done so that all event filters can cleanup any handlers they have installed This function will also clear the callback function so that any leftover handler that is triggered will not be able to change the application state. subclasses must call this super method to cleanup the callback if they collaborate and use this classe's do_callback() """ self._callback = None def do_callback(self, *args, **kwargs): """ Default callback function that calls the event filter callback with the event filter as only argument. """ if self._callback: self._callback(self) ##class TimerEvent(EventFilter): ## """ ## TimerEvent is a special EventFilter that uses gobject ## timeouts to trigger a state change after a specified amount ## of time. It must be used inside a gobject main loop to work. ## """ ## def __init__(self,next_state,timeout_s): ## """Constructor. ## ## @param next_state default EventFilter param, passed on to EventFilter ## @param timeout_s timeout in seconds ## """ ## super(TimerEvent,self).__init__(next_state) ## self._timeout = timeout_s ## self._handler_id = None ## ## def install_handlers(self, callback, **kwargs): ## """install_handlers creates the timer and starts it""" ## super(TimerEvent,self).install_handlers(callback, **kwargs) ## #Create the timer ## self._handler_id = gobject.timeout_add_seconds(self._timeout, self._timeout_cb) ## ## def remove_handlers(self): ## """remove handler removes the timer""" ## super(TimerEvent,self).remove_handlers() ## if self._handler_id: ## try: ## #XXX What happens if this was already triggered? ## #remove the timer ## gobject.source_remove(self._handler_id) ## except: ## pass ## ## def _timeout_cb(self): ## """ ## _timeout_cb triggers the eventfilter callback. ## ## It is necessary because gobject timers only stop if the callback they ## trigger returns False ## """ ## self.do_callback() ## return False #Stops timeout ## ##class GtkWidgetTypeFilter(EventFilter): ## """ ## Event Filter that listens for keystrokes on a widget ## """ ## def __init__(self, next_state, object_id, text=None, strokes=None): ## """Constructor ## @param next_state default EventFilter param, passed on to EventFilter ## @param object_id object tree-ish identifier ## @param text resulting text expected ## @param strokes list of strokes expected ## ## At least one of text or strokes must be supplied ## """ ## super(GtkWidgetTypeFilter, self).__init__(next_state) ## self._object_id = object_id ## self._text = text ## self._captext = "" ## self._strokes = strokes ## self._capstrokes = [] ## self._widget = None ## self._handler_id = None ## ## def install_handlers(self, callback, **kwargs): ## """install handlers ## @param callback default EventFilter callback arg ## """ ## super(GtkWidgetTypeFilter, self).install_handlers(callback, **kwargs) ## logger.debug("~~~GtkWidgetTypeFilter install") ## activity = ObjectStore().activity ## if activity is None: ## logger.error("No activity") ## raise RuntimeWarning("no activity in the objectstore") ## ## self._widget = find_widget(activity, self._object_id) ## if self._widget: ## self._handler_id= self._widget.connect("key-press-event",self.__keypress_cb) ## logger.debug("~~~Connected handler %d on %s" % (self._handler_id,self._object_id) ) ## ## def remove_handlers(self): ## """remove handlers""" ## super(GtkWidgetTypeFilter, self).remove_handlers() ## #if an event was connected, disconnect it ## if self._handler_id: ## self._widget.handler_disconnect(self._handler_id) ## self._handler_id=None ## ## def __keypress_cb(self, widget, event, *args): ## """keypress callback""" ## logger.debug("~~~keypressed!") ## key = event.keyval ## keystr = event.string ## logger.debug("~~~Got key: " + str(key) + ":"+ keystr) ## self._capstrokes += [key] ## #TODO Treat other stuff, such as arrows ## if key == gtk.keysyms.BackSpace: ## self._captext = self._captext[:-1] ## else: ## self._captext = self._captext + keystr ## ## logger.debug("~~~Current state: " + str(self._capstrokes) + ":" + str(self._captext)) ## if not self._strokes is None and self._strokes in self._capstrokes: ## self.do_callback() ## if not self._text is None and self._text in self._captext: ## self.do_callback()