Work in progress: working with target objects

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1041 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-01-28 08:24:49 +00:00
parent 3cbba1d593
commit b02329358a
10 changed files with 144 additions and 36 deletions

View file

@ -30,6 +30,8 @@ top-level loops container and a concept manager:
>>> concepts['cc1'] = cc1 >>> concepts['cc1'] = cc1
>>> cc1.title >>> cc1.title
u'' u''
>>> loopsRoot.getLoopsUri(cc1)
'.loops/concepts/cc1'
>>> cc2 = Concept(u'Zope 3') >>> cc2 = Concept(u'Zope 3')
>>> concepts['cc2'] = cc2 >>> concepts['cc2'] = cc2
@ -277,13 +279,17 @@ target may be moved or renamed without any problems.)
>>> nodeConfig = INodeConfigSchema(m111) >>> nodeConfig = INodeConfigSchema(m111)
>>> nodeConfig.targetUri >>> nodeConfig.targetUri
u'.loops/concepts/cc2' '.loops/concepts/cc2'
>>> nodeConfig.title = u'New title for m111' >>> nodeConfig.title = u'New title for m111'
>>> nodeConfig.title >>> nodeConfig.title
u'New title for m111' u'New title for m111'
>>> 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' >>> nodeConfig.title = 'New title for m111'
>>> m111.target is doc1 >>> m111.target is doc1
True True
@ -305,12 +311,22 @@ application uses a subclass that does all the other stuff for form handling.)
>>> form = {'field.createTarget': True, >>> form = {'field.createTarget': True,
... 'field.targetUri': '.loops/resources/ma07', ... 'field.targetUri': '.loops/resources/ma07',
... 'field.targetType': 'loops.resource.MediaAsset'} ... 'field.targetType': 'loops.resource.MediaAsset'}
>>> view = ConfigureBaseView(INodeConfigSchema(m111), TestRequest(form=form))
>>> view = ConfigureBaseView(m111, TestRequest(form=form)) >>> view = ConfigureBaseView(m111, TestRequest(form=form))
>>> view.checkCreateTarget() >>> m111.target = view.checkCreateTarget()
>>> sorted(resources.keys()) >>> sorted(resources.keys())
[u'doc1', u'ma07'] [u'doc1', u'ma07']
>>> isinstance(resources['ma07'], MediaAsset)
True
>>> form = {'field.createTarget': True,
... 'field.targetType': 'loops.resource.Document'}
>>> view = ConfigureBaseView(m111, TestRequest(form=form))
>>> m111.target = view.checkCreateTarget()
>>> sorted(resources.keys())
[u'doc1', u'm1.m11.m111', u'ma07']
>>> isinstance(resources['m1.m11.m111'], Document)
True
It is also possible to edit a target's attributes directly in an It is also possible to edit a target's attributes directly in an
edit form provided by the node: edit form provided by the node:
@ -318,6 +334,11 @@ edit form provided by the node:
>>> ztapi.provideAdapter(INode, IDocument, DocumentProxy) >>> ztapi.provideAdapter(INode, IDocument, DocumentProxy)
>>> ztapi.provideAdapter(INode, IMediaAsset, MediaAssetProxy) >>> ztapi.provideAdapter(INode, IMediaAsset, MediaAssetProxy)
>>> proxy = zapi.getAdapter(m111, IDocument)
>>> proxy.title = u'Set via proxy'
>>> resources['m1.m11.m111'].title
u'Set via proxy'
Ordering Nodes Ordering Nodes
-------------- --------------
@ -335,10 +356,10 @@ to the bottom, and to the top
>>> from cybertools.container.ordered import OrderedContainerView >>> from cybertools.container.ordered import OrderedContainerView
>>> view = OrderedContainerView(m11, TestRequest()) >>> view = OrderedContainerView(m11, TestRequest())
>>> view.moveToBottom(('m113',)) >>> view.move_bottom(('m113',))
>>> m11.keys() >>> m11.keys()
['m111', 'm112', 'm114', 'm113'] ['m111', 'm112', 'm114', 'm113']
>>> view.moveUp(('m114',), 1) >>> view.move_up(('m114',), 1)
>>> m11.keys() >>> m11.keys()
['m111', 'm114', 'm112', 'm113'] ['m111', 'm114', 'm112', 'm113']

View file

@ -23,8 +23,9 @@
$Id$ $Id$
""" """
from zope.interface import implements from zope.app import zapi
from zope.app.folder.folder import Folder from zope.app.folder.folder import Folder
from zope.interface import implements
from interfaces import ILoops from interfaces import ILoops
class Loops(Folder): class Loops(Folder):
@ -34,3 +35,9 @@ class Loops(Folder):
def getLoopsRoot(self): def getLoopsRoot(self):
return self return self
def getViewManager(self):
return self['views']
def getLoopsUri(self, obj):
return str('.loops' + zapi.getPath(obj)[len(zapi.getPath(self)):])

View file

@ -247,7 +247,6 @@
<containerViews <containerViews
for="loops.interfaces.IViewManager" for="loops.interfaces.IViewManager"
index="zope.ManageContent" index="zope.ManageContent"
contents="zope.ManageContent"
add="zope.ManageContent" add="zope.ManageContent"
/> />
@ -274,6 +273,7 @@
content_factory="loops.view.Node" content_factory="loops.view.Node"
schema="loops.interfaces.INodeConfigSchema" schema="loops.interfaces.INodeConfigSchema"
fields="title description nodeType targetType targetUri createTarget" fields="title description nodeType targetType targetUri createTarget"
class="loops.browser.node.ConfigureView"
permission="zope.ManageContent"> permission="zope.ManageContent">
<widget field="description" height="2" /> <widget field="description" height="2" />
@ -304,6 +304,12 @@
</editform> </editform>
<containerViews
for="loops.interfaces.INode"
index="zope.ManageContent"
add="zope.ManageContent"
/>
<editform <editform
label="Configure Node" label="Configure Node"
name="configure.html" name="configure.html"
@ -320,6 +326,21 @@
</editform> </editform>
<editform
label="Edit Target"
name="edit_target.html"
schema="loops.interfaces.IMediaAsset"
fields="title data contentType"
for="loops.interfaces.INode"
permission="zope.ManageContent"
/>
<menuItem
for="loops.interfaces.INode"
menu="zmi_views" action="edit_target.html" title="Edit Target"
filter="context/target"
/>
<page <page
name="node.html" name="node.html"
for="loops.interfaces.INode" for="loops.interfaces.INode"
@ -333,10 +354,4 @@
name="node.html" name="node.html"
/> />
<containerViews
for="loops.interfaces.IBaseNode"
index="zope.ManageContent"
add="zope.ManageContent"
/>
</configure> </configure>

View file

@ -26,6 +26,7 @@ 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
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
@ -104,18 +105,41 @@ class ConfigureBaseView(object):
self.context = removeSecurityProxy(context) self.context = removeSecurityProxy(context)
self.request = request self.request = request
@Lazy
def loopsRoot(self):
return self.context.getLoopsRoot()
def checkCreateTarget(self): def checkCreateTarget(self):
form = self.request.form form = self.request.form
if 'field.createTarget' in form: 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')
# TODO: find class (better: factory) from type name factory = ConfigurationContext().resolve(type)
uri = self.request.form.get('field.targetUri', None) uri = self.request.form.get('field.targetUri', None)
# TODO: generate uri/__name__ if not given
if uri: if uri:
# TODO: find container path = uri.split('/')
self.context.getLoopsRoot()['resources']['ma07'] = MediaAsset() containerName = path[-2]
#self.context.loopsRoot['resources']['ma07'] = MediaAsset() name = path[-1]
else:
containerName = 'resource' in type and 'resources' or 'concepts'
viewManagerPath = zapi.getPath(self.context.getViewManager())
name = zapi.getPath(self.context)[len(viewManagerPath)+1:]
name = name.replace('/', '.')
container = self.loopsRoot[containerName]
# check for duplicates:
num = 1
basename = name
while name in container:
name = '%s-%d' % (basename, num)
num += 1
# create target:
container[name] = factory()
target = container[name]
# set possibly new targetUri in request for further processing:
targetUri = self.loopsRoot.getLoopsUri(target)
form['field.targetUri'] = targetUri
return target
class ConfigureView(object): class ConfigureView(object):
""" An editing view for configuring a node, optionally creating """ An editing view for configuring a node, optionally creating

View file

@ -65,6 +65,9 @@ class Concept(Contained, Persistent):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
# concept relations # concept relations
def getSubConcepts(self, relationships=None): def getSubConcepts(self, relationships=None):
@ -128,3 +131,8 @@ class ConceptManager(BTreeContainer):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self) return zapi.getParent(self)
def getViewManager(self):
return self.getLoopsRoot().getViewManager()

View file

@ -218,8 +218,10 @@
<adapter factory=".view.NodeConfigAdapter" <adapter factory=".view.NodeConfigAdapter"
permission="zope.ManageContent" /> permission="zope.ManageContent" />
<adapter factory="loops.target.DocumentProxy" /> <adapter factory="loops.target.DocumentProxy"
<adapter factory="loops.target.MediaAssetProxy" /> permission="zope.ManageContent" />
<adapter factory="loops.target.MediaAssetProxy"
permission="zope.ManageContent" />
<view factory="loops.view.NodeTraverser" <view factory="loops.view.NodeTraverser"
for="loops.interfaces.INode" for="loops.interfaces.INode"

View file

@ -43,6 +43,10 @@ class ILoopsObject(Interface):
""" Return the loops root object. """ Return the loops root object.
""" """
def getViewManager():
""" Return the (default) view manager.
"""
# concept interfaces # concept interfaces
class IConcept(ILoopsObject): class IConcept(ILoopsObject):
@ -310,6 +314,10 @@ class ILoops(ILoopsObject, IFolder):
""" The top-level object of a loops site. """ The top-level object of a loops site.
""" """
contains(IConceptManager, IResourceManager, IViewManager) contains(IConceptManager, IResourceManager, IViewManager)
def getLoopsUri(obj):
""" Return the relativ path to obj, starting with '.loops/...'.
"""
class ILoopsContained(Interface): class ILoopsContained(Interface):

View file

@ -55,6 +55,9 @@ class Resource(Contained, Persistent):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
def getClients(self, relationships=None): def getClients(self, relationships=None):
rels = getRelations(second=self, relationships=relationships) rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels] return [r.first for r in rels]
@ -105,4 +108,8 @@ class ResourceManager(BTreeContainer):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self) return zapi.getParent(self)
def getViewManager(self):
return self.getLoopsRoot().getViewManager()

View file

@ -27,6 +27,7 @@ from zope.app import zapi
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.component import adapts from zope.component import adapts
from zope.interface import implements from zope.interface import implements
from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IResource, IDocument, IMediaAsset from loops.interfaces import IResource, IDocument, IMediaAsset
from loops.interfaces import IView from loops.interfaces import IView
@ -37,16 +38,17 @@ class ResourceProxy(object):
adapts(IView) adapts(IView)
def getTitle(self): return self.target.title def getTitle(self): return self.target.title
def setTitle(self, title): self.title = title def setTitle(self, title): self.target.title = title
title = property(getTitle, setTitle) title = property(getTitle, setTitle)
def setContentType(self, contentType): def setContentType(self, contentType):
self.target._contentType = contentType self.target.contentType = contentType
def getContentType(self): return self.target.contentType def getContentType(self): return self.target.contentType
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)
@Lazy @Lazy
def target(self): def target(self):

38
view.py
View file

@ -60,7 +60,8 @@ class View(object):
if len(rels) == 0: if len(rels) == 0:
return None return None
if len(rels) > 1: if len(rels) > 1:
raise ValueError, 'There may be only one target for a View object.' raise ValueError('There may be only one target for a View object: %s - %s'
% (zapi.getName(self), `[zapi.getName(r.second) for r in rels]`))
return list(rels)[0].second return list(rels)[0].second
def setTarget(self, target): def setTarget(self, target):
@ -72,8 +73,9 @@ class View(object):
return return
else: else:
registry.unregister(oldRel) registry.unregister(oldRel)
rel = TargetRelation(self, target) if target:
registry.register(rel) rel = TargetRelation(self, target)
registry.register(rel)
target = property(getTarget, setTarget) target = property(getTarget, setTarget)
@ -85,6 +87,9 @@ class View(object):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return zapi.getParent(self).getViewManager()
class Node(View, OrderedContainer): class Node(View, OrderedContainer):
@ -141,6 +146,9 @@ class ViewManager(OrderedContainer):
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self) return zapi.getParent(self)
def getViewManager(self):
return self
class TargetRelation(DyadicRelation): class TargetRelation(DyadicRelation):
""" A relation between a view and another object. """ A relation between a view and another object.
@ -186,24 +194,30 @@ class NodeConfigAdapter(object):
@Lazy @Lazy
def loopsRoot(self): return self.context.getLoopsRoot() def loopsRoot(self): return self.context.getLoopsRoot()
@Lazy
def target(self):
return self.context.target
def getTargetUri(self): def getTargetUri(self):
rootPath = zapi.getPath(self.loopsRoot) target = self.target
if self.context.target is not None: if target is not None:
path = zapi.getPath(self.context.target)[len(rootPath):] return self.loopsRoot.getLoopsUri(target)
return '.loops' + path
else: else:
return '' return ''
def setTargetUri(self, uri): def setTargetUri(self, uri):
names = uri.split('/') if uri:
if names[0] == '.loops': names = uri.split('/')
path = '/'.join(names[1:]) if names[0] == '.loops':
self.context.target = zapi.traverse(self.loopsRoot, path) path = '/'.join(names[1:])
self.context.target = zapi.traverse(self.loopsRoot, path)
else:
self.context.target = None
targetUri = property(getTargetUri, setTargetUri) targetUri = property(getTargetUri, setTargetUri)
def getTargetType(self): def getTargetType(self):
target = self.context.target target = self.target
if target: if target:
return '%s.%s' % (target.__module__, target.__class__.__name__) return '%s.%s' % (target.__module__, target.__class__.__name__)
return None return None