diff --git a/README.txt b/README.txt index 3b5eee2..a269591 100755 --- a/README.txt +++ b/README.txt @@ -26,14 +26,14 @@ top-level loops container and a concept manager: >>> from loops.concept import ConceptManager, Concept >>> loops['concepts'] = ConceptManager() >>> concepts = loops['concepts'] - >>> zope = Concept() - >>> concepts['zope'] = zope - >>> zope.title + >>> cc1 = Concept() + >>> concepts['cc1'] = cc1 + >>> cc1.title u'' - >>> zope3 = Concept(u'Zope 3') - >>> concepts['zope3'] = zope3 - >>> zope3.title + >>> cc2 = Concept(u'Zope 3') + >>> concepts['cc2'] = cc2 + >>> cc2.title u'Zope 3' Now we want to relate the second concept to the first one. @@ -48,25 +48,25 @@ testing we use a simple dummy implementation. Now we can assign the concept c2 to c1 (using the standard ConceptRelation): - >>> zope.assignConcept(zope3) + >>> cc1.assignConcept(cc2) We can now ask our concepts for their related concepts: - >>> sc1 = zope.getSubConcepts() + >>> sc1 = cc1.getSubConcepts() >>> len(sc1) 1 - >>> zope3 in sc1 + >>> cc2 in sc1 True - >>> len(zope.getParentConcepts()) + >>> len(cc1.getParentConcepts()) 0 - >>> pc2 = zope3.getParentConcepts() + >>> pc2 = cc2.getParentConcepts() >>> len(pc2) 1 - >>> zope in pc2 + >>> cc1 in pc2 True - >>> len(zope3.getSubConcepts()) + >>> len(cc2.getSubConcepts()) 0 TODO: Work with views... @@ -81,31 +81,33 @@ We first need a resource manager: >>> loops['resources'] = ResourceManager() >>> resources = loops['resources'] -A common type of resource is a Document: +A common type of resource is a document: - >>> zope_info = Document(u'Zope Info') - >>> resources['zope_info'] = zope_info - >>> zope_info.title + >>> doc1 = Document(u'Zope Info') + >>> resources['doc1'] = doc1 + >>> doc1.title u'Zope Info' - >>> zope_info.body + >>> doc1.data u'' - >>> zope_info.format + >>> doc1.contentType u'text/xml' +Another one is a media asset: + We can associate a resource with a concept by assigning it to the concept: - >>> zope.assignResource(zope_info) - >>> res = zope.getResources() + >>> cc1.assignResource(doc1) + >>> res = cc1.getResources() >>> list(res) [] The resource also provides access to the associated concepts (or views, see below) via the getClients() method: - >>> conc = zope_info.getClients() + >>> conc = doc1.getClients() >>> len(conc) 1 - >>> conc[0] is zope + >>> conc[0] is cc1 True @@ -200,14 +202,14 @@ Targets We can associate a node with a concept or directly with a resource via the view class's target attribute: - >>> m111.target = zope_info - >>> m111.target is zope_info + >>> m111.target = cc1 + >>> m111.target is cc1 True - >>> m111.target = zope_info - >>> m111.target is zope_info + >>> m111.target = cc1 + >>> m111.target is cc1 True - >>> m111.target = zope3 - >>> m111.target is zope3 + >>> m111.target = cc2 + >>> m111.target is cc2 True Node views diff --git a/browser/configure.zcml b/browser/configure.zcml index d4f29d5..07d4d9b 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -159,7 +159,7 @@ label="Add Document" name="AddLoopsDocument.html" schema="loops.interfaces.IDocument" - fields="title body format" + fields="title data contentType" content_factory="loops.resource.Document" permission="zope.ManageContent" /> @@ -176,12 +176,41 @@ label="Edit Document" name="edit.html" schema="loops.interfaces.IDocument" - fields="title body format" + fields="title data contentType" for="loops.interfaces.IDocument" permission="zope.ManageContent" menu="zmi_views" title="Edit" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interfaces.py b/interfaces.py index c376ad9..60e8a13 100644 --- a/interfaces.py +++ b/interfaces.py @@ -27,7 +27,7 @@ from zope.i18nmessageid import MessageFactory from zope import schema from zope.app.container.constraints import contains, containers from zope.app.container.interfaces import IContainer, IOrderedContainer -from zope.app.file.interfaces import IFile as IBaseFile +from zope.app.file.interfaces import IImage as IBaseAsset from zope.app.folder.interfaces import IFolder _ = MessageFactory('loops') @@ -102,8 +102,8 @@ class IConceptManagerContained(Interface): # resource interfaces class IResource(Interface): - """ A resource is an atomic information element that is usually - available via a concept. + """ A resource is an atomic information element that is made + available via a view or a concept. """ title = schema.TextLine( @@ -111,6 +111,13 @@ class IResource(Interface): description=_(u'Title of the document'), required=False) + contentType = schema.TextLine( + title=_(u'Content Type'), + description=_(u'Content type (format) of the body field, ' + 'default is "text/xml"'), + default=_(u'text/xml'), + required=False) + def getClients(relationships=None): """ Return a sequence of objects that are clients of the resource, i.e. that have some relation with it. @@ -121,23 +128,22 @@ class IDocument(IResource): """ A resource containing an editable body. """ - body = schema.Text( - title=_(u'Body'), - description=_(u'Body of the document'), - required=False) - - format = schema.TextLine( - title=_(u'Format'), - description=_(u'Format of the body field, default is "text/xml"'), - default=_(u'text/xml'), + data = schema.Text( + title=_(u'Data'), + description=_(u'Raw body data of the document'), required=False) -class IFile(IResource, IBaseFile): +class IMediaAsset(IResource, IBaseAsset): """ A resource containing a (typically binary) file-like content - or an image. + or an image. """ + data = schema.Bytes( + title=_(u'Data'), + description=_(u'Media asset raw data'), + required=False) + class IResourceManager(IContainer): """ A manager/container for resources. @@ -173,6 +179,10 @@ class IView(Interface): class IBaseNode(IOrderedContainer): """ Common abstract base class for different types of nodes """ + + def getLoopsRoot(): + """ Return the loops root object. + """ class INode(IView, IBaseNode): diff --git a/resource.py b/resource.py index 43a86c4..72ddede 100644 --- a/resource.py +++ b/resource.py @@ -25,11 +25,12 @@ $Id$ from zope.app import zapi from zope.app.container.btree import BTreeContainer from zope.app.container.contained import Contained +from zope.app.file.image import Image as BaseMediaAsset from zope.interface import implements from persistent import Persistent from cybertools.relation.registry import getRelations -from interfaces import IResource, IDocument +from interfaces import IResource, IDocument, IMediaAsset from interfaces import IResourceManager, IResourceManagerContained from interfaces import ILoopsContained @@ -43,27 +44,36 @@ class Resource(Contained, Persistent): def setTitle(self, title): self._title = title title = property(getTitle, setTitle) - def __init__(self, title=u''): - self.title = title + _contentType = u'text/xml' + def setContentType(self, contentType): self._contentType = contentType + def getContentType(self): return self._contentType + contentType = property(getContentType, setContentType) + + _data = u'' + def setData(self, data): self._data = data + def getData(self): return self._data + data = property(getData, setData) def getClients(self, relationships=None): rels = getRelations(second=self, relationships=relationships) return [r.first for r in rels] + def __init__(self, title=u''): + self.title = title + class Document(Resource): implements(IDocument) - - _body = u'' - def setBody(self, body): self._body = body - def getBody(self): return self._body - body = property(getBody, setBody) - _format = u'text/xml' - def setFormat(self, format): self._format = format - def getFormat(self): return self._format - format = property(getFormat, setFormat) + +class MediaAsset(Resource, BaseMediaAsset): + + implements(IMediaAsset) + + def __init__(self, title=u''): + super(MediaAsset, self).__init__() + self.title = title class ResourceManager(BTreeContainer): diff --git a/tests.py b/tests.py index dd0baa8..784165b 100755 --- a/tests.py +++ b/tests.py @@ -10,10 +10,11 @@ from zope.app.intid.interfaces import IIntIds from interfaces import ILoops from loops import Loops -from interfaces import IConcept, IConceptManager, IDocument, IResourceManager +from interfaces import IConcept, IConceptManager +from interfaces import IDocument, IMediaAsset, IResourceManager from interfaces import INode, IViewManager from loops.concept import Concept, ConceptManager -from loops.resource import Document, ResourceManager +from loops.resource import Document, MediaAsset, ResourceManager from loops.view import Node, ViewManager class Test(unittest.TestCase): @@ -28,6 +29,8 @@ class Test(unittest.TestCase): self.assert_(IConceptManager.providedBy(ConceptManager())) verifyClass(IDocument, Document) self.assert_(IDocument.providedBy(Document())) + verifyClass(IMediaAsset, MediaAsset) + self.assert_(IMediaAsset.providedBy(MediaAsset())) verifyClass(IResourceManager, ResourceManager) self.assert_(IResourceManager.providedBy(ResourceManager())) verifyClass(INode, Node) diff --git a/view.py b/view.py index ca137b2..3551dde 100644 --- a/view.py +++ b/view.py @@ -26,6 +26,9 @@ from zope.app import zapi from zope.app.container.btree import BTreeContainer from zope.app.container.contained import Contained from zope.app.container.ordered import OrderedContainer +from zope.app.container.traversal import ContainerTraverser, ItemTraverser +from zope.app.container.traversal import ContainerTraversable +from zope.component import adapts from zope.interface import implements from persistent import Persistent from cybertools.relation import DyadicRelation @@ -95,6 +98,9 @@ class Node(View, OrderedContainer): contentType = u'zope.source.rest' + def getLoopsRoot(self): + return zapi.getParent(self).getLoopsRoot() + def getParentNode(self, nodeTypes=None): parent = zapi.getParent(self) while INode.providedBy(parent): @@ -134,8 +140,34 @@ class ViewManager(OrderedContainer): implements(IViewManager, ILoopsContained) + def getLoopsRoot(self): + return zapi.getParent(self) + class TargetRelation(DyadicRelation): """ A relation between a view and another object. """ + +class NodeTraverser(ItemTraverser): + + adapts(INode) + + def publishTraverse(self, request, name): + print name + if name == '.loops': + return self.context.getLoopsRoot() + return super(NodeTraverser, self).publishTraverse(request, name) + + +# class NodeTraversable(ContainerTraversable): +# +# adapts(INode) +# +# def traverse(self, name, furtherPath): +# print name +# if str(name) == '.loops': +# print self._container.getLoopsRoot() +# return self._container.getLoopsRoot() +# return super(NodeTraversable, self).traverse(name, furtherPath) +