home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / cgkit / eventmanager.py < prev    next >
Encoding:
Python Source  |  2007-01-11  |  8.8 KB  |  270 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python Computer Graphics Kit.
  15. #
  16. # The Initial Developer of the Original Code is Matthias Baas.
  17. # Portions created by the Initial Developer are Copyright (C) 2004
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the GPL or the LGPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK *****
  35. # $Id: eventmanager.py,v 1.4 2005/03/08 16:13:42 mbaas Exp $
  36.  
  37. ## \file eventmanager.py
  38. ## Contains the EventManager class.
  39.  
  40. import sys, types, bisect
  41.  
  42. # Receiver
  43. class _Receiver:
  44.     """Stores a receiver (=callable) and a priority.
  45.  
  46.     This class defines a comparison operator (that's why this class is
  47.     used instead of a tuple (priority, receiver)).
  48.     """
  49.     def __init__(self, receiver, priority=1):
  50.         self.receiver = receiver
  51.         self.priority = priority
  52.  
  53.  
  54.     def __str__(self):
  55.         # If the receiver is an instance method, then obtain the corresponding
  56.         # class name
  57.         cls = getattr(self.receiver, "im_class", None)
  58.         if cls!=None:
  59.             s = getattr(cls, "__name__", "?")+"."
  60.         else:
  61.             s = ""
  62.         s += getattr(self.receiver, "__name__", "<unnamed>")
  63.         return "(%d, %s)"%(self.priority, s)
  64.  
  65.     __repr__ = __str__
  66.  
  67.     def __cmp__(self, other):
  68.         return self.priority-other.priority
  69.     
  70.  
  71. # EventManager
  72. class EventManager:
  73.     """Manages any kind of events.
  74.  
  75.     System wide event receivers must indicate if the event should
  76.     be consumed (return value = True) or passed to the scene wide
  77.     receivers.
  78.     """
  79.  
  80.     def __init__(self):
  81.         """Constructor."""
  82.  
  83.         # System wide connections.
  84.         # Key: Event name - Value: Sorted list of _Receivers
  85.         self.system_connections = {}
  86.         # Scene wide connections.
  87.         # Key: Event name - Value: Sorted list of _Receivers
  88.         self.scene_connections = {}
  89.  
  90.     def __str__(self):
  91.         s = 70*"-"+"\n"
  92.         s += "System events\n"
  93.         s += 70*"-"+"\n"
  94.         for event in self.system_connections:
  95.             s+='Event: "%s"\n'%event
  96.             for rec in self.system_connections[event]:
  97.                 s+="  %s\n"%rec
  98.         s+="\n"
  99.                 
  100.         s += 70*"-"+"\n"
  101.         s += "Scene events\n"
  102.         s += 70*"-"+"\n"
  103.         for event in self.scene_connections:
  104.             s+='Event: "%s"\n'%event
  105.             for rec in self.scene_connections[event]:
  106.                 s+="  %s\n"%rec
  107.         return s
  108.         
  109.  
  110.     # event
  111.     def event(self, name, *params, **keyargs):
  112.         """Signal an event.
  113.  
  114.         When an event handler returns True the notification is interrupted
  115.         (i.e. the event is consumed and not available anymore for other
  116.         handlers).
  117.  
  118.         \param name (\c str) Name of the event.
  119.         \return True, if any event handler returned True.
  120.  
  121.         \todo Aufruf der Empfaenger-Methode kann Exception verursachen.
  122.         """
  123.  
  124.         # Process system wide connections
  125.         receivers = self.system_connections.get(name, [])
  126.         for rec in receivers:
  127.             if rec.receiver(*params, **keyargs):
  128.                 return True
  129.  
  130.         # Process scene wide connections
  131.         receivers = self.scene_connections.get(name, [])
  132.         for rec in receivers:
  133.             if rec.receiver(*params, **keyargs):
  134.                 return True
  135.  
  136.         return False
  137.  
  138.     # connect
  139.     def connect(self, name, receiver, priority=10, system=False):
  140.         """Connect a function or method to an event.
  141.  
  142.         The priority determines the calling order when the corresponding
  143.         event is emitted. Receivers with a smaller priority are invoked first.
  144.  
  145.         \param name (\c str) Name of the event.
  146.         \param receiver The receiving function or method, or an instance
  147.                         of a class that must implement an on<Event>() method.
  148.         \param priority (\c int) Priority of the receiver
  149.         \param system (\c bool) Specifies if the connection is system wide or
  150.                       not (default: \c False).
  151.         """
  152.  
  153.         receiver = self._determine_receiver(name, receiver)
  154.  
  155.         # Disconnect the receiver if it was already connected
  156.         try:
  157.             self.disconnect(name,receiver,system)
  158.         except KeyError:
  159.             pass
  160.  
  161.         if system:
  162.             connections = self.system_connections
  163.         else:
  164.             connections = self.scene_connections
  165.  
  166.         rec = _Receiver(receiver, priority)
  167.         # Has the event already any connections? then add the new receiver
  168.         if connections.has_key(name):
  169.             bisect.insort(connections[name], rec)
  170. #            connections[name].append(receiver)
  171.         # otherwise create a new list
  172.         else:
  173.             connections[name] = [rec]
  174.  
  175.         return (name,receiver)
  176.  
  177.     # disconnect
  178.     def disconnect(self, name, receiver=None, system=False):
  179.         """Disconnect a function or method from an event.
  180.  
  181.         \param name (\c str) Name of the event.
  182.         \param receiver The receiving function or method, or an instance
  183.                         of a class that must implement an on<Event>() method.
  184.         \param system (\c bool) Specifies if the connection is system wide or
  185.                       not (default: \c False).
  186.         """
  187.  
  188.         if isinstance(name,tuple):
  189.             name,receiver = name
  190.  
  191.         if system:
  192.             connections = self.system_connections
  193.         else:
  194.             connections = self.scene_connections
  195.  
  196.         # Are all connections to be removed?
  197.         if receiver==None:
  198.             if connections.has_key(name):
  199.                 del connections[name]
  200.                 return
  201.  
  202.         receiver = self._determine_receiver(name, receiver)
  203.  
  204.         # Has the event any connections at all?
  205.         if not connections.has_key(name):
  206.             raise KeyError, 'Receiver is not connected to event "%s"'%name
  207.  
  208.         # Try to remove the connection
  209. #        try:
  210. #            connections[name].remove(receiver)
  211. #        except ValueError:
  212. #            raise KeyError, 'Receiver is not connected to event "%s"'%name
  213.         
  214.         for i,rec in enumerate(connections[name]):
  215.             if rec.receiver==receiver:
  216.                 break
  217.         else:
  218.             raise KeyError, 'Receiver is not connected to event "%s"'%name
  219.  
  220.         del connections[name][i]
  221.  
  222.     # disconnectAll
  223.     def disconnectAll(self, system=False):
  224.         """Remove all connections.
  225.  
  226.         \param system (\c bool) Specifies if the system wide connections or
  227.                       the scene wide connections shall be removed
  228.                       (default: \c False).
  229.         """
  230.         if system:
  231.             self.system_connections = {}
  232.         else:
  233.             self.scene_connections = {}
  234.  
  235.  
  236.     ## private:
  237.     def _determine_receiver(self, name, receiver):
  238.         """Returns the receiver object.
  239.  
  240.         The receiver is the callable that gets called when an event
  241.         occurs.
  242.  
  243.         \param name (\c str) Name of the event.
  244.         \param receiver The receiving function or method, or an instance
  245.                         of a class that must implement an on<Event>() method.
  246.         \return Callable object.
  247.         """
  248.  
  249.         methodname = "on"+name
  250.         if hasattr(receiver, methodname):
  251.             return getattr(receiver, methodname)
  252.         
  253.         if callable(receiver):
  254.             return receiver
  255.             
  256.         raise ValueError, "Receiver argument must be a callable or an object with an %s() method"%methodname
  257.         
  258. ######################################################################
  259.  
  260. _global_event_manager = EventManager()
  261.  
  262. # eventManager
  263. def eventManager():
  264.     """Returns the global event manager.
  265.  
  266.     \return Event manager (EventManager)
  267.     """
  268.     global _global_event_manager
  269.     return _global_event_manager
  270.