home *** CD-ROM | disk | FTP | other *** search
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the Python Computer Graphics Kit.
- #
- # The Initial Developer of the Original Code is Matthias Baas.
- # Portions created by the Initial Developer are Copyright (C) 2004
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
- # $Id: eventmanager.py,v 1.4 2005/03/08 16:13:42 mbaas Exp $
-
- ## \file eventmanager.py
- ## Contains the EventManager class.
-
- import sys, types, bisect
-
- # Receiver
- class _Receiver:
- """Stores a receiver (=callable) and a priority.
-
- This class defines a comparison operator (that's why this class is
- used instead of a tuple (priority, receiver)).
- """
- def __init__(self, receiver, priority=1):
- self.receiver = receiver
- self.priority = priority
-
-
- def __str__(self):
- # If the receiver is an instance method, then obtain the corresponding
- # class name
- cls = getattr(self.receiver, "im_class", None)
- if cls!=None:
- s = getattr(cls, "__name__", "?")+"."
- else:
- s = ""
- s += getattr(self.receiver, "__name__", "<unnamed>")
- return "(%d, %s)"%(self.priority, s)
-
- __repr__ = __str__
-
- def __cmp__(self, other):
- return self.priority-other.priority
-
-
- # EventManager
- class EventManager:
- """Manages any kind of events.
-
- System wide event receivers must indicate if the event should
- be consumed (return value = True) or passed to the scene wide
- receivers.
- """
-
- def __init__(self):
- """Constructor."""
-
- # System wide connections.
- # Key: Event name - Value: Sorted list of _Receivers
- self.system_connections = {}
- # Scene wide connections.
- # Key: Event name - Value: Sorted list of _Receivers
- self.scene_connections = {}
-
- def __str__(self):
- s = 70*"-"+"\n"
- s += "System events\n"
- s += 70*"-"+"\n"
- for event in self.system_connections:
- s+='Event: "%s"\n'%event
- for rec in self.system_connections[event]:
- s+=" %s\n"%rec
- s+="\n"
-
- s += 70*"-"+"\n"
- s += "Scene events\n"
- s += 70*"-"+"\n"
- for event in self.scene_connections:
- s+='Event: "%s"\n'%event
- for rec in self.scene_connections[event]:
- s+=" %s\n"%rec
- return s
-
-
- # event
- def event(self, name, *params, **keyargs):
- """Signal an event.
-
- When an event handler returns True the notification is interrupted
- (i.e. the event is consumed and not available anymore for other
- handlers).
-
- \param name (\c str) Name of the event.
- \return True, if any event handler returned True.
-
- \todo Aufruf der Empfaenger-Methode kann Exception verursachen.
- """
-
- # Process system wide connections
- receivers = self.system_connections.get(name, [])
- for rec in receivers:
- if rec.receiver(*params, **keyargs):
- return True
-
- # Process scene wide connections
- receivers = self.scene_connections.get(name, [])
- for rec in receivers:
- if rec.receiver(*params, **keyargs):
- return True
-
- return False
-
- # connect
- def connect(self, name, receiver, priority=10, system=False):
- """Connect a function or method to an event.
-
- The priority determines the calling order when the corresponding
- event is emitted. Receivers with a smaller priority are invoked first.
-
- \param name (\c str) Name of the event.
- \param receiver The receiving function or method, or an instance
- of a class that must implement an on<Event>() method.
- \param priority (\c int) Priority of the receiver
- \param system (\c bool) Specifies if the connection is system wide or
- not (default: \c False).
- """
-
- receiver = self._determine_receiver(name, receiver)
-
- # Disconnect the receiver if it was already connected
- try:
- self.disconnect(name,receiver,system)
- except KeyError:
- pass
-
- if system:
- connections = self.system_connections
- else:
- connections = self.scene_connections
-
- rec = _Receiver(receiver, priority)
- # Has the event already any connections? then add the new receiver
- if connections.has_key(name):
- bisect.insort(connections[name], rec)
- # connections[name].append(receiver)
- # otherwise create a new list
- else:
- connections[name] = [rec]
-
- return (name,receiver)
-
- # disconnect
- def disconnect(self, name, receiver=None, system=False):
- """Disconnect a function or method from an event.
-
- \param name (\c str) Name of the event.
- \param receiver The receiving function or method, or an instance
- of a class that must implement an on<Event>() method.
- \param system (\c bool) Specifies if the connection is system wide or
- not (default: \c False).
- """
-
- if isinstance(name,tuple):
- name,receiver = name
-
- if system:
- connections = self.system_connections
- else:
- connections = self.scene_connections
-
- # Are all connections to be removed?
- if receiver==None:
- if connections.has_key(name):
- del connections[name]
- return
-
- receiver = self._determine_receiver(name, receiver)
-
- # Has the event any connections at all?
- if not connections.has_key(name):
- raise KeyError, 'Receiver is not connected to event "%s"'%name
-
- # Try to remove the connection
- # try:
- # connections[name].remove(receiver)
- # except ValueError:
- # raise KeyError, 'Receiver is not connected to event "%s"'%name
-
- for i,rec in enumerate(connections[name]):
- if rec.receiver==receiver:
- break
- else:
- raise KeyError, 'Receiver is not connected to event "%s"'%name
-
- del connections[name][i]
-
- # disconnectAll
- def disconnectAll(self, system=False):
- """Remove all connections.
-
- \param system (\c bool) Specifies if the system wide connections or
- the scene wide connections shall be removed
- (default: \c False).
- """
- if system:
- self.system_connections = {}
- else:
- self.scene_connections = {}
-
-
- ## private:
- def _determine_receiver(self, name, receiver):
- """Returns the receiver object.
-
- The receiver is the callable that gets called when an event
- occurs.
-
- \param name (\c str) Name of the event.
- \param receiver The receiving function or method, or an instance
- of a class that must implement an on<Event>() method.
- \return Callable object.
- """
-
- methodname = "on"+name
- if hasattr(receiver, methodname):
- return getattr(receiver, methodname)
-
- if callable(receiver):
- return receiver
-
- raise ValueError, "Receiver argument must be a callable or an object with an %s() method"%methodname
-
- ######################################################################
-
- _global_event_manager = EventManager()
-
- # eventManager
- def eventManager():
- """Returns the global event manager.
-
- \return Event manager (EventManager)
- """
- global _global_event_manager
- return _global_event_manager
-