Media assets and documents as target objects for nodes: basically OK

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1043 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-01-28 13:09:39 +00:00
parent b02329358a
commit 21b6af48b9
8 changed files with 117 additions and 52 deletions

View file

@ -286,11 +286,6 @@ target may be moved or renamed without any problems.)
>>> m111.title >>> m111.title
u'New title for m111' u'New title for m111'
>>> nodeConfig.targetUri = '.loops/resources/doc1' >>> nodeConfig.targetUri = '.loops/resources/doc1'
We have to get a new adapter to avoid problems with lazy variables:
>>> nodeConfig = INodeConfigSchema(m111)
>>> nodeConfig.title = 'New title for m111'
>>> m111.target is doc1 >>> m111.target is doc1
True True
>>> nodeConfig.targetType >>> nodeConfig.targetType
@ -327,16 +322,33 @@ application uses a subclass that does all the other stuff for form handling.)
>>> isinstance(resources['m1.m11.m111'], Document) >>> isinstance(resources['m1.m11.m111'], Document)
True True
It is also possible to edit a target's attributes directly in an A node object provides the targetSchema of its target:
>>> from loops.interfaces import IDocumentView
>>> from loops.interfaces import IMediaAssetView
>>> IDocumentView.providedBy(m111)
True
>>> IMediaAssetView.providedBy(m111)
False
>>> m111.target = None
>>> IDocumentView.providedBy(m111)
False
>>> m111.target = resources['ma07']
>>> IDocumentView.providedBy(m111)
False
>>> IMediaAssetView.providedBy(m111)
True
It is possible to edit a target's attributes directly in an
edit form provided by the node: edit form provided by the node:
>>> from loops.target import DocumentProxy, MediaAssetProxy >>> from loops.target import DocumentProxy, MediaAssetProxy
>>> ztapi.provideAdapter(INode, IDocument, DocumentProxy) >>> ztapi.provideAdapter(INode, IDocumentView, DocumentProxy)
>>> ztapi.provideAdapter(INode, IMediaAsset, MediaAssetProxy) >>> ztapi.provideAdapter(INode, IMediaAssetView, MediaAssetProxy)
>>> proxy = zapi.getAdapter(m111, IDocument) >>> proxy = zapi.getAdapter(m111, IDocumentView)
>>> proxy.title = u'Set via proxy' >>> proxy.title = u'Set via proxy'
>>> resources['m1.m11.m111'].title >>> resources['ma07'].title
u'Set via proxy' u'Set via proxy'
Ordering Nodes Ordering Nodes

View file

@ -167,7 +167,7 @@
<addform <addform
label="Add Document" label="Add Document"
name="AddLoopsDocument.html" name="AddLoopsDocument.html"
schema="loops.interfaces.IDocument" schema="loops.interfaces.IDocumentSchema"
fields="title data contentType" fields="title data contentType"
content_factory="loops.resource.Document" content_factory="loops.resource.Document"
permission="zope.ManageContent" /> permission="zope.ManageContent" />
@ -184,7 +184,7 @@
<editform <editform
label="Edit Document" label="Edit Document"
name="edit.html" name="edit.html"
schema="loops.interfaces.IDocument" schema="loops.interfaces.IDocumentSchema"
fields="title data contentType" fields="title data contentType"
for="loops.interfaces.IDocument" for="loops.interfaces.IDocument"
permission="zope.ManageContent" permission="zope.ManageContent"
@ -195,7 +195,7 @@
<addform <addform
label="Add Media Asset" label="Add Media Asset"
name="AddLoopsMediaAsset.html" name="AddLoopsMediaAsset.html"
schema="loops.interfaces.IMediaAsset" schema="loops.interfaces.IMediaAssetSchema"
fields="title data contentType" fields="title data contentType"
content_factory="loops.resource.MediaAsset" content_factory="loops.resource.MediaAsset"
permission="zope.ManageContent" permission="zope.ManageContent"
@ -212,11 +212,11 @@
<editform <editform
label="Edit Media Asset" label="Edit Media Asset"
name="edit.html" name="edit.html"
schema="loops.interfaces.IMediaAsset" schema="loops.interfaces.IMediaAssetSchema"
fields="title data contentType" fields="title data contentType"
for="loops.interfaces.IMediaAsset" for="loops.interfaces.IMediaAsset"
permission="zope.ManageContent" permission="zope.ManageContent"
menu="zmi_views" title="Edit" menu="zmi_views" title="Edit Media Asset"
/> />
<!-- suppress the upload menu item: --> <!-- suppress the upload menu item: -->
@ -271,8 +271,8 @@
label="Add Node" label="Add Node"
name="AddLoopsNode.html" name="AddLoopsNode.html"
content_factory="loops.view.Node" content_factory="loops.view.Node"
schema="loops.interfaces.INodeConfigSchema" schema="loops.interfaces.INode"
fields="title description nodeType targetType targetUri createTarget" fields="title description nodeType body"
class="loops.browser.node.ConfigureView" class="loops.browser.node.ConfigureView"
permission="zope.ManageContent"> permission="zope.ManageContent">
@ -327,18 +327,23 @@
</editform> </editform>
<editform <editform
label="Edit Target" label="Edit Media Asset"
name="edit_target.html" name="edit_target.html"
schema="loops.interfaces.IMediaAsset" schema="loops.interfaces.IMediaAsset"
fields="title data contentType" fields="title data contentType"
for="loops.interfaces.INode" for="loops.interfaces.IMediaAssetView"
permission="zope.ManageContent" permission="zope.ManageContent"
menu="zmi_views" title="Edit Media Asset"
/> />
<menuItem <editform
for="loops.interfaces.INode" label="Edit Document"
menu="zmi_views" action="edit_target.html" title="Edit Target" name="edit_target.html"
filter="context/target" schema="loops.interfaces.IDocument"
fields="title data contentType"
for="loops.interfaces.IDocumentView"
permission="zope.ManageContent"
menu="zmi_views" title="Edit Document"
/> />
<page <page

View file

@ -26,7 +26,8 @@ from zope.cachedescriptors.property import Lazy
from zope.app import zapi from zope.app import zapi
from zope.app.container.browser.contents import JustContents from zope.app.container.browser.contents import JustContents
from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.configuration.config import ConfigurationContext #import zope.configuration.name
from zope.dottedname.resolve import resolve
from zope.proxy import removeAllProxies from zope.proxy import removeAllProxies
from zope.security import canAccess, canWrite from zope.security import canAccess, canWrite
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
@ -114,7 +115,7 @@ class ConfigureBaseView(object):
if form.get('field.createTarget', False): if form.get('field.createTarget', False):
type = self.request.form.get('field.targetType', type = self.request.form.get('field.targetType',
'loops.resource.MediaAsset') 'loops.resource.MediaAsset')
factory = ConfigurationContext().resolve(type) factory = resolve(type)
uri = self.request.form.get('field.targetUri', None) uri = self.request.form.get('field.targetUri', None)
if uri: if uri:
path = uri.split('/') path = uri.split('/')

View file

@ -54,6 +54,8 @@ class Concept(Contained, Persistent):
implements(IConcept, IConceptManagerContained) implements(IConcept, IConceptManagerContained)
proxyInterface = IConcept
_title = u'' _title = u''
def getTitle(self): return self._title def getTitle(self): return self._title
def setTitle(self, title): self._title = title def setTitle(self, title): self._title = title

View file

@ -47,9 +47,18 @@ class ILoopsObject(Interface):
""" Return the (default) view manager. """ Return the (default) view manager.
""" """
class IPotentialTarget(Interface):
""" For objects that may be used as target objects for view objects.
"""
proxyInterface = Attribute('An interface allowing an object to be '
'used as a target for a view/node (and '
'typically specifying the corresponding schema')
# concept interfaces # concept interfaces
class IConcept(ILoopsObject): class IConcept(ILoopsObject, IPotentialTarget):
""" The concept is the central element of the loops framework. """ The concept is the central element of the loops framework.
A concept is related to other concepts, may have resources A concept is related to other concepts, may have resources
@ -115,10 +124,7 @@ class IConceptManagerContained(Interface):
# resource interfaces # resource interfaces
class IResource(ILoopsObject): class IResourceSchema(Interface):
""" A resource is an atomic information element that is made
available via a view or a concept.
"""
title = schema.TextLine( title = schema.TextLine(
title=_(u'Title'), title=_(u'Title'),
@ -127,13 +133,6 @@ class IResource(ILoopsObject):
missing_value=u'', missing_value=u'',
required=False) required=False)
contentType = schema.BytesLine(
title=_(u'Content Type'),
description=_(u'Content type (format) of the data field'),
default='',
missing_value='',
required=False)
data = schema.Bytes( data = schema.Bytes(
title=_(u'Data'), title=_(u'Data'),
description=_(u'Resource raw data'), description=_(u'Resource raw data'),
@ -141,15 +140,26 @@ class IResource(ILoopsObject):
missing_value='', missing_value='',
required=False) required=False)
contentType = schema.BytesLine(
title=_(u'Content Type'),
description=_(u'Content type (format) of the data field'),
default='',
missing_value='',
required=False)
class IResource(ILoopsObject, IPotentialTarget):
""" A resource is an atomic information element that is made
available via a view or a concept.
"""
def getClients(relationships=None): def getClients(relationships=None):
""" Return a sequence of objects that are clients of the resource, """ Return a sequence of objects that are clients of the resource,
i.e. that have some relation with it. i.e. that have some relation with it.
""" """
class IDocument(IResource): class IDocumentSchema(IResourceSchema):
""" A resource containing an editable body.
"""
data = schema.Text( data = schema.Text(
title=_(u'Data'), title=_(u'Data'),
@ -159,11 +169,17 @@ class IDocument(IResource):
required=False) required=False)
class IMediaAsset(IResource, IBaseAsset): class IDocumentView(IDocumentSchema):
""" A resource containing a (typically binary) file-like content """ Used for accessing a document via a node's target attribute"""
or an image.
class IDocument(IDocumentSchema, IResource):
""" A resource containing an editable body.
""" """
class IMediaAssetSchema(IResourceSchema):
data = schema.Bytes( data = schema.Bytes(
title=_(u'Data'), title=_(u'Data'),
description=_(u'Media asset file'), description=_(u'Media asset file'),
@ -172,6 +188,16 @@ class IMediaAsset(IResource, IBaseAsset):
required=False) required=False)
class IMediaAssetView(IMediaAssetSchema):
""" Used for accessing a media asset via a node's target attribute"""
class IMediaAsset(IMediaAssetSchema, IResource, IBaseAsset):
""" A resource containing a (typically binary) file-like content
or an image.
"""
class IResourceManager(ILoopsObject, IContainer): class IResourceManager(ILoopsObject, IContainer):
""" A manager/container for resources. """ A manager/container for resources.
""" """
@ -203,6 +229,7 @@ class IView(ILoopsObject):
target = Attribute('Target object that is referenced by this view') target = Attribute('Target object that is referenced by this view')
class IBaseNode(IOrderedContainer): class IBaseNode(IOrderedContainer):
""" Common abstract base class for different types of nodes """ Common abstract base class for different types of nodes
""" """

View file

@ -31,7 +31,9 @@ from persistent import Persistent
from cStringIO import StringIO from cStringIO import StringIO
from cybertools.relation.registry import getRelations from cybertools.relation.registry import getRelations
from interfaces import IResource, IDocument, IMediaAsset from interfaces import IResource
from interfaces import IDocument, IDocumentSchema, IDocumentView
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
from interfaces import IResourceManager, IResourceManagerContained from interfaces import IResourceManager, IResourceManagerContained
from interfaces import ILoopsContained from interfaces import ILoopsContained
@ -72,6 +74,8 @@ class Document(Resource):
implements(IDocument) implements(IDocument)
proxyInterface = IDocumentView
_data = u'' _data = u''
def setData(self, data): self._data = data def setData(self, data): self._data = data
def getData(self): return self._data def getData(self): return self._data
@ -82,6 +86,8 @@ class MediaAsset(Resource, BaseMediaAsset):
implements(IMediaAsset) implements(IMediaAsset)
proxyInterface = IMediaAssetView
def __init__(self, title=u''): def __init__(self, title=u''):
super(MediaAsset, self).__init__() super(MediaAsset, self).__init__()
self.title = title self.title = title

View file

@ -29,7 +29,9 @@ from zope.component import adapts
from zope.interface import implements from zope.interface import implements
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IResource, IDocument, IMediaAsset from loops.interfaces import IResource
from loops.interfaces import IDocument, IMediaAsset
from loops.interfaces import IDocumentView, IMediaAssetView
from loops.interfaces import IView from loops.interfaces import IView
@ -47,8 +49,8 @@ class ResourceProxy(object):
contentType = property(getContentType, setContentType) contentType = property(getContentType, setContentType)
def __init__(self, context): def __init__(self, context):
self.context = context #self.context = context
#self.context = removeSecurityProxy(context) self.context = removeSecurityProxy(context)
@Lazy @Lazy
def target(self): def target(self):
@ -58,6 +60,7 @@ class ResourceProxy(object):
class DocumentProxy(ResourceProxy): class DocumentProxy(ResourceProxy):
implements(IDocument) implements(IDocument)
adapts(IDocumentView)
def setData(self, data): self.target.data = data def setData(self, data): self.target.data = data
def getData(self): return self.target.data def getData(self): return self.target.data
@ -67,6 +70,7 @@ class DocumentProxy(ResourceProxy):
class MediaAssetProxy(ResourceProxy): class MediaAssetProxy(ResourceProxy):
implements(IMediaAsset) implements(IMediaAsset)
adapts(IMediaAssetView)
def setData(self, data): self.target.data = data def setData(self, data): self.target.data = data
def getData(self): return self.target.data def getData(self): return self.target.data

14
view.py
View file

@ -28,9 +28,10 @@ from zope.app.container.contained import Contained
from zope.app.container.ordered import OrderedContainer from zope.app.container.ordered import OrderedContainer
from zope.app.container.traversal import ContainerTraverser, ItemTraverser from zope.app.container.traversal import ContainerTraverser, ItemTraverser
from zope.app.container.traversal import ContainerTraversable from zope.app.container.traversal import ContainerTraversable
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy, readproperty
from zope.component import adapts from zope.component import adapts
from zope.interface import implements from zope.interface import implements
from zope.interface import alsoProvides, directlyProvides, directlyProvidedBy
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from persistent import Persistent from persistent import Persistent
from cybertools.relation import DyadicRelation from cybertools.relation import DyadicRelation
@ -73,9 +74,14 @@ class View(object):
return return
else: else:
registry.unregister(oldRel) registry.unregister(oldRel)
oldTargetSchema = oldRel.second.proxyInterface
directlyProvides(self, directlyProvidedBy(self) - oldTargetSchema)
if target: if target:
targetSchema = target.proxyInterface
rel = TargetRelation(self, target) rel = TargetRelation(self, target)
registry.register(rel) registry.register(rel)
alsoProvides(self, targetSchema)
target = property(getTarget, setTarget) target = property(getTarget, setTarget)
@ -194,7 +200,7 @@ class NodeConfigAdapter(object):
@Lazy @Lazy
def loopsRoot(self): return self.context.getLoopsRoot() def loopsRoot(self): return self.context.getLoopsRoot()
@Lazy @readproperty
def target(self): def target(self):
return self.context.target return self.context.target
@ -225,5 +231,7 @@ class NodeConfigAdapter(object):
pass # only used whe a new target object is created pass # only used whe a new target object is created
targetType = property(getTargetType, setTargetType) targetType = property(getTargetType, setTargetType)
createTarget = False # not used def getCreateTarget(self): return False
def setCreateTarget(self, value): pass
createTarget = property(getCreateTarget, setCreateTarget)