def dispatchToSublocations(object, event): """Dispatches an event to sublocations of a given object. This handler is used to dispatch copy events to sublocations. To illustrate, we'll first create a hierarchy of objects: >>> class L(object): ... def __init__(self, name): ... self.__name__ = name ... self.__parent__ = None ... def __repr__(self): ... return '%s(%s)' % (self.__class__.__name__, self.__name__) >>> class C(L): ... implements(ISublocations) ... def __init__(self, name, *subs): ... L.__init__(self, name) ... self.subs = subs ... for sub in subs: ... sub.__parent__ = self ... def sublocations(self): ... return self.subs >>> c = C(1, ... C(11, ... L(111), ... L(112), ... ), ... C(12, ... L(121), ... L(122), ... L(123), ... L(124), ... ), ... L(13), ... ) and a handler for copy events that records the objects it's seen: >>> seen = [] >>> def handler(ob, event): ... seen.append((ob, event.object)) Finally, we need to register our handler for copy events: >>> from zope.app.tests import ztapi >>> from zope.app.event.interfaces import IObjectCopiedEvent >>> ztapi.subscribe([None, IObjectCopiedEvent], None, handler) and this function as a dispatcher: >>> ztapi.subscribe([None, IObjectCopiedEvent], None, ... dispatchToSublocations) When we notify that our root object has been copied: >>> notify(ObjectCopiedEvent(c, L(''))) we see that our handler has seen all of the subobjects: >>> seenreprs = map(repr, seen) >>> seenreprs.sort() >>> seenreprs #doctest: +NORMALIZE_WHITESPACE ['(C(1), C(1))', '(C(11), C(1))', '(C(12), C(1))', '(L(111), C(1))', '(L(112), C(1))', '(L(121), C(1))', '(L(122), C(1))', '(L(123), C(1))', '(L(124), C(1))', '(L(13), C(1))'] """ subs = ISublocations(object, None) if subs is not None: for sub in subs.sublocations(): for ignored in zapi.subscribers((sub, event), None): pass # They do work in the adapter fetch
def dispatchToSublocations(object, event): """Dispatch an event to sublocations of a given object When a move event happens for an object, it's important to notify subobjects as well. We do this based on locations. Suppose, for example, that we define some location objects. >>> class L(object): ... zope.interface.implements(ILocation) ... def __init__(self, name): ... self.__name__ = name ... self.__parent__ = None ... def __repr__(self): ... return '%s(%s)' % ( ... self.__class__.__name__, str(self.__name__)) >>> class C(L): ... zope.interface.implements(ISublocations) ... def __init__(self, name, *subs): ... L.__init__(self, name) ... self.subs = subs ... for sub in subs: ... sub.__parent__ = self ... def sublocations(self): ... return self.subs >>> c = C(1, ... C(11, ... L(111), ... L(112), ... ), ... C(12, ... L(121), ... L(122), ... L(123), ... L(124), ... ), ... L(13), ... ) Now, if we call the dispatcher, it should call event handlers for all of the objects. Lets create an event handler that records the objects it sees: >>> seen = [] >>> def handler(ob, event): ... seen.append((ob, event.object)) Note that we record the the object the handler is called on as well as the event object: Now we'll register it: >>> from zope.app.testing import ztapi >>> ztapi.subscribe([None, IObjectMovedEvent], None, handler) We also register our dispatcher: >>> ztapi.subscribe([None, IObjectMovedEvent], None, ... dispatchToSublocations) We can then call the dispatcher for the root object: >>> event = ObjectRemovedEvent(c) >>> dispatchToSublocations(c, event) Now, we should have seen all of the subobjects: >>> seenreprs = map(repr, seen) >>> seenreprs.sort() >>> seenreprs ['(C(11), C(1))', '(C(12), C(1))', '(L(111), C(1))',""" \ """ '(L(112), C(1))', '(L(121), C(1))', '(L(122), C(1))',""" \ """ '(L(123), C(1))', '(L(124), C(1))', '(L(13), C(1))'] We see that we get entries for each of the subobjects and that,for each entry, the event object is top object. This suggests that location event handlers need to be aware that the objects they are called on and the event objects could be different. """ subs = ISublocations(object, None) if subs is not None: for sub in subs.sublocations(): for ignored in zapi.subscribers((sub, event), None): pass # They do work in the adapter fetch