messenger now remembers obj->event dict

This commit is contained in:
Joe Shochet 2005-02-14 21:36:56 +00:00
parent 9fcb8cf159
commit 949f57e477
2 changed files with 96 additions and 88 deletions

View File

@ -10,56 +10,28 @@ class DirectObject:
def __init__(self):
pass
# This destructor is useful for debugging leaks
#def __del__(self):
# print "Destructing: ", self.__class__.__name__
# Event Handling
def __initEvents(self):
# this function exists because:
# - DirectObject does not have a constructor, and adding one
# would involve touching many, many files
# - a constructor that creates self.events would cause every
# DirectObject to incur the cost of an additional function
# call and dictionary creation
# - DirectObjects that do not use the messenger should not have
# an unused dictionary taking up space
# - the speed hit of calling this function on calls to accept,
# ignore, etc. is negligible, since they are not called often
if not hasattr(self, "events"):
# list of events that this object is accepting
# we use a dictionary to avoid linear searches
self.events = {}
# Wrapper functions to have a cleaner, more object oriented approach to
# the messenger functionality.
def accept(self, event, method, extraArgs=[]):
self.__initEvents()
self.events.setdefault(event, None)
messenger.accept(event, self, method, extraArgs, 1)
return messenger.accept(event, self, method, extraArgs, 1)
def acceptOnce(self, event, method, extraArgs=[]):
self.__initEvents()
self.events.setdefault(event, None)
messenger.accept(event, self, method, extraArgs, 0)
def _INTERNAL_acceptOnceExpired(self, event):
""" this should only be called by the messenger """
if self.events.has_key(event):
del self.events[event]
return messenger.accept(event, self, method, extraArgs, 0)
def ignore(self, event):
self.__initEvents()
if self.events.has_key(event):
del self.events[event]
messenger.ignore(event, self)
return messenger.ignore(event, self)
def ignoreAll(self):
self.__initEvents()
for event in self.events.keys():
messenger.ignore(event, self)
self.events.clear()
return messenger.ignoreAll(self)
def isAccepting(self, event):
self.__initEvents()
return self.events.has_key(event)
return messenger.isAccepting(event, self)
def isIgnoring(self, event):
return not self.isAccepting(event)
return messenger.isIgnoring(event, self)

View File

@ -1,24 +1,32 @@
from PythonUtil import *
from direct.directnotify.DirectNotifyGlobal import *
from direct.directnotify import DirectNotifyGlobal
import types
class Messenger:
notify = None
notify = DirectNotifyGlobal.directNotify.newCategory("Messenger")
def __init__(self):
"""
One dictionary does it all. It has the following structure:
One is keyed off the event name. It has the following structure:
{event1 : {object1: [method, extraArgs, persistent],
object2: [method, extraArgs, persistent]},
event2 : {object1: [method, extraArgs, persistent],
object2: [method, extraArgs, persistent]}}
This dictionary allow for efficient callbacks when the messenger
hears an event.
A second dictionary remembers which objects are accepting which
events. This allows for efficient ignoreAll commands.
Or, for an example with more real data:
{'mouseDown' : {avatar : [avatar.jump, [2.0], 1]}}
"""
self.dict = {}
self.__callbacks = {}
self.__objectEvents = {}
if __debug__:
self.isWatching=0
@ -29,11 +37,6 @@ class Messenger:
# under __debug__.
self.quieting={"NewFrame":1, "avatarMoving":1} # see def quiet()
if (Messenger.notify == None):
Messenger.notify = directNotify.newCategory("Messenger")
# Messenger.notify.setDebug(1)
def accept(self, event, object, method, extraArgs=[], persistent=1):
""" accept(self, string, DirectObject, Function, List, Boolean)
@ -52,9 +55,13 @@ class Messenger:
+ '\n extraArgs: ' + `extraArgs`
+ '\n persistent: ' + `persistent`)
acceptorDict = self.dict.setdefault(event, {})
acceptorDict = self.__callbacks.setdefault(event, {})
acceptorDict[object] = [method, extraArgs, persistent]
# Remember that this object is listening for this event
eventDict = self.__objectEvents.setdefault(object, {})
eventDict.setdefault(event, None)
def ignore(self, event, object):
""" ignore(self, string, DirectObject)
Make this object no longer respond to this event.
@ -64,41 +71,52 @@ class Messenger:
Messenger.notify.debug(`object` + '\n now ignoring: ' + `event`)
# Find the dictionary of all the objects accepting this event
acceptorDict = self.dict.get(event)
acceptorDict = self.__callbacks.get(event)
# If this object is there, delete it from the dictionary
if acceptorDict and acceptorDict.has_key(object):
del acceptorDict[object]
# If this dictionary is now empty, remove the event
# entry from the Messenger alltogether
if (len(acceptorDict) == 0):
del self.dict[event]
## ### moved into DirectObject for speed
## ###
## def ignoreAll(self, object):
## """ ignoreAll(self, DirectObject)
## Make this object no longer respond to any events it was accepting
## Useful for cleanup
## """
## if Messenger.notify.getDebug():
## Messenger.notify.debug(`object` + '\n now ignoring all events')
## for event, acceptorDict in self.dict.items():
## # If this object is there, delete it from the dictionary
## if acceptorDict.has_key(object):
## del acceptorDict[object]
## # If this dictionary is now empty, remove the event
## # entry from the Messenger alltogether
## if (len(acceptorDict) == 0):
## del self.dict[event]
del self.__callbacks[event]
# This object is no longer listening for this event
eventDict = self.__objectEvents.get(object)
if eventDict and eventDict.has_key(event):
del eventDict[event]
if (len(eventDict) == 0):
del self.__objectEvents[object]
def ignoreAll(self, object):
""" ignoreAll(self, DirectObject)
Make this object no longer respond to any events it was accepting
Useful for cleanup
"""
if Messenger.notify.getDebug():
Messenger.notify.debug(`object` + '\n now ignoring all events')
# Get the list of events this object is listening to
eventDict = self.__objectEvents.get(object)
if eventDict:
for event in eventDict.keys():
# Find the dictionary of all the objects accepting this event
acceptorDict = self.__callbacks.get(event)
# If this object is there, delete it from the dictionary
if acceptorDict and acceptorDict.has_key(object):
del acceptorDict[object]
# If this dictionary is now empty, remove the event
# entry from the Messenger alltogether
if (len(acceptorDict) == 0):
del self.__callbacks[event]
del self.__objectEvents[object]
def isAccepting(self, event, object):
""" isAccepting(self, string, DirectOject)
Is this object accepting this event?
"""
if self.dict.has_key(event):
if self.dict[event].has_key(object):
# Found it, return true
return 1
acceptorDict = self.__callbacks.get(event)
if acceptorDict and acceptorDict.has_key(object):
# Found it, return true
return 1
# If we looked in both dictionaries and made it here
# that object must not be accepting that event.
return 0
@ -107,7 +125,7 @@ class Messenger:
"""
Return objects accepting the given event
"""
return self.dict.get(event, None)
return self.__callbacks.get(event)
def isIgnoring(self, event, object):
""" isIgnorning(self, string, DirectObject)
@ -132,7 +150,7 @@ class Messenger:
if str(event).find(i) >= 0:
foundWatch=1
break
acceptorDict = self.dict.get(event)
acceptorDict = self.__callbacks.get(event)
if not acceptorDict:
if __debug__:
if foundWatch:
@ -153,13 +171,18 @@ class Messenger:
# If this object was only accepting this event once,
# remove it from the dictionary
if not persistent:
# notify the object that the event has been triggered
object._INTERNAL_acceptOnceExpired(event)
# This object is no longer listening for this event
eventDict = self.__objectEvents.get(object)
if eventDict and eventDict.has_key(event):
del eventDict[event]
if (len(eventDict) == 0):
del self.__objectEvents[object]
del acceptorDict[object]
# If the dictionary at this event is now empty, remove
# the event entry from the Messenger altogether
if (self.dict.has_key(event) and (len(self.dict[event]) == 0)):
del self.dict[event]
if (self.__callbacks.has_key(event) and (len(self.__callbacks[event]) == 0)):
del self.__callbacks[event]
if __debug__:
if foundWatch:
@ -178,8 +201,14 @@ class Messenger:
"""
Start fresh with a clear dict
"""
self.dict.clear()
self.__callbacks.clear()
self.__objectEvents.clear()
def isEmpty(self):
return (len(self.__callbacks) == 0)
def getEvents(self):
return self.__callbacks.keys()
def replaceMethod(self, oldMethod, newFunction):
"""
@ -188,7 +217,7 @@ class Messenger:
"""
import new
retFlag = 0
for entry in self.dict.items():
for entry in self.__callbacks.items():
event, objectDict = entry
for objectEntry in objectDict.items():
object, params = objectEntry
@ -263,12 +292,12 @@ class Messenger:
return a matching event (needle) if found (in haystack).
This is primarily a debugging tool.
"""
keys = self.dict.keys()
keys = self.__callbacks.keys()
keys.sort()
for event in keys:
if `event`.find(needle) >= 0:
print self.__eventRepr(event),
return {event: self.dict[event]}
return {event: self.__callbacks[event]}
def findAll(self, needle, limit=None):
"""
@ -277,12 +306,12 @@ class Messenger:
This is primarily a debugging tool.
"""
matches = {}
keys = self.dict.keys()
keys = self.__callbacks.keys()
keys.sort()
for event in keys:
if `event`.find(needle) >= 0:
print self.__eventRepr(event),
matches[event] = self.dict[event]
matches[event] = self.__callbacks[event]
# if the limit is not None, decrement and
# check for break:
if limit > 0:
@ -306,7 +335,7 @@ class Messenger:
Compact version of event, acceptor pairs
"""
str = event.ljust(32) + '\t'
acceptorDict = self.dict[event]
acceptorDict = self.__callbacks[event]
for object, (method, extraArgs, persistent) in acceptorDict.items():
str = str + self.__methodRepr(method) + ' '
str = str + '\n'
@ -317,10 +346,17 @@ class Messenger:
Compact version of event, acceptor pairs
"""
str = "The messenger is currently handling:\n" + "="*64 + "\n"
keys = self.dict.keys()
keys = self.__callbacks.keys()
keys.sort()
for event in keys:
str += self.__eventRepr(event)
# Print out the object : event dictionary too
str += "="*64 + "\n"
for object, eventDict in self.__objectEvents.items():
str += "%s:\n" % object
for event in eventDict.keys():
str += " %s\n" % event
str += "="*64 + "\n" + "End of messenger info.\n"
return str
@ -331,10 +367,10 @@ class Messenger:
import types
str = 'Messenger\n'
str = str + '='*50 + '\n'
keys = self.dict.keys()
keys = self.__callbacks.keys()
keys.sort()
for event in keys:
acceptorDict = self.dict[event]
acceptorDict = self.__callbacks[event]
str = str + 'Event: ' + event + '\n'
for object in acceptorDict.keys():
function, extraArgs, persistent = acceptorDict[object]