diff --git a/README.txt b/README.txt index 7323476..c869943 100755 --- a/README.txt +++ b/README.txt @@ -232,8 +232,16 @@ Targets ------- We can associate a node with a concept or directly with a resource via the -view class's target attribute: +view class's target attribute. (We also have to supply a subscriber to +IRelationInvalidatedEvent to make sure associated actions will be carried +out - this is usually done through ZCML.) + >>> from loops.util import removeTargetRelation + >>> from loops.interfaces import ITargetRelation + >>> from cybertools.relation.interfaces import IRelationInvalidatedEvent + >>> ztapi.subscribe([ITargetRelation, IRelationInvalidatedEvent], None, + ... removeTargetRelation) + >>> m111.target = cc1 >>> m111.target is cc1 True @@ -351,6 +359,22 @@ edit form provided by the node: >>> resources['ma07'].title u'Set via proxy' +If the target object is removed from its container all references +to it are removed as well. (To make this work we have to handle +the IObjectRemovedEvent; this is usually done via ZCML in the +cybertools.relation package.) + + >>> from zope.app.container.interfaces import IObjectRemovedEvent + >>> from zope.interface import Interface + >>> from cybertools.relation.registry import invalidateRelations + >>> ztapi.subscribe([Interface, IObjectRemovedEvent], None, + ... invalidateRelations) + + >>> del resources['ma07'] + >>> m111.target + >>> IMediaAssetView.providedBy(m111) + False + Ordering Nodes -------------- diff --git a/browser/configure.zcml b/browser/configure.zcml index b91c17c..7e4a2f6 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -251,6 +251,13 @@ add="zope.ManageContent" /> + + + menu="zmi_views" title="Edit Node"> diff --git a/configure.zcml b/configure.zcml index 4e69e35..e20a883 100644 --- a/configure.zcml +++ b/configure.zcml @@ -5,7 +5,15 @@ i18n_domain="zope" > - + + + + + diff --git a/interfaces.py b/interfaces.py index 8fb8075..5f99c7c 100644 --- a/interfaces.py +++ b/interfaces.py @@ -29,11 +29,12 @@ from zope.app.container.constraints import contains, containers from zope.app.container.interfaces import IContainer, IOrderedContainer from zope.app.file.interfaces import IImage as IBaseAsset from zope.app.folder.interfaces import IFolder +from cybertools.relation.interfaces import IRelation _ = MessageFactory('loops') -# common top-level +# common interfaces class ILoopsObject(Interface): """ Common top-level interface. @@ -56,6 +57,7 @@ class IPotentialTarget(Interface): 'used as a target for a view/node (and ' 'typically specifying the corresponding schema') + # concept interfaces class IConcept(ILoopsObject, IPotentialTarget): @@ -335,6 +337,12 @@ class INodeConfigSchema(INode, ITargetProperties): required=False) +class ITargetRelation(IRelation): + """ (Marker) interfaces for relations pointing to a target + of a view or node. + """ + + # the loops top-level container class ILoops(ILoopsObject, IFolder): @@ -350,4 +358,3 @@ class ILoops(ILoopsObject, IFolder): class ILoopsContained(Interface): containers(ILoops) - \ No newline at end of file diff --git a/util.py b/util.py index 8ea2d27..a72ed06 100644 --- a/util.py +++ b/util.py @@ -22,9 +22,21 @@ Utility functions. $Id$ """ +from zope.interface import directlyProvides, directlyProvidedBy +from view import TargetRelation + + +def removeTargetRelation(context, event): + """ Handles IRelationInvalidatedEvent by doing some cleanup work. + """ + targetIfc = context.second.proxyInterface + if targetIfc: + directlyProvides(context.first, directlyProvidedBy(context) - targetIfc) + + def nl2br(text): if not text: return text if '\n' in text: # Unix or DOS line endings return '
\n'.join(x.replace('\r', '') for x in text.split('\n')) - else: # gracefully handle Mac line endigns + else: # gracefully handle Mac line endings return '
\n'.join(text.split('\r')) diff --git a/view.py b/view.py index d6b23bc..5c4714c 100644 --- a/view.py +++ b/view.py @@ -40,6 +40,7 @@ from cybertools.relation.registry import IRelationsRegistry, getRelations from interfaces import IView, INode, INodeConfigSchema from interfaces import IViewManager, INodeContained from interfaces import ILoopsContained +from interfaces import ITargetRelation class View(object): @@ -74,8 +75,6 @@ class View(object): return else: registry.unregister(oldRel) - oldTargetSchema = oldRel.second.proxyInterface - directlyProvides(self, directlyProvidedBy(self) - oldTargetSchema) if target: targetSchema = target.proxyInterface @@ -157,8 +156,10 @@ class ViewManager(OrderedContainer): class TargetRelation(DyadicRelation): - """ A relation between a view and another object. + """ A relation between a view and its target. """ + implements(ITargetRelation) + # adapters