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

View file

@ -23,8 +23,9 @@
$Id$
"""
from zope.interface import implements
from zope.app import zapi
from zope.app.folder.folder import Folder
from zope.interface import implements
from interfaces import ILoops
class Loops(Folder):
@ -34,3 +35,9 @@ class Loops(Folder):
def getLoopsRoot(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
for="loops.interfaces.IViewManager"
index="zope.ManageContent"
contents="zope.ManageContent"
add="zope.ManageContent"
/>
@ -274,6 +273,7 @@
content_factory="loops.view.Node"
schema="loops.interfaces.INodeConfigSchema"
fields="title description nodeType targetType targetUri createTarget"
class="loops.browser.node.ConfigureView"
permission="zope.ManageContent">
<widget field="description" height="2" />
@ -304,6 +304,12 @@
</editform>
<containerViews
for="loops.interfaces.INode"
index="zope.ManageContent"
add="zope.ManageContent"
/>
<editform
label="Configure Node"
name="configure.html"
@ -320,6 +326,21 @@
</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
name="node.html"
for="loops.interfaces.INode"
@ -333,10 +354,4 @@
name="node.html"
/>
<containerViews
for="loops.interfaces.IBaseNode"
index="zope.ManageContent"
add="zope.ManageContent"
/>
</configure>

View file

@ -26,6 +26,7 @@ from zope.cachedescriptors.property import Lazy
from zope.app import zapi
from zope.app.container.browser.contents import JustContents
from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.configuration.config import ConfigurationContext
from zope.proxy import removeAllProxies
from zope.security import canAccess, canWrite
from zope.security.proxy import removeSecurityProxy
@ -104,18 +105,41 @@ class ConfigureBaseView(object):
self.context = removeSecurityProxy(context)
self.request = request
@Lazy
def loopsRoot(self):
return self.context.getLoopsRoot()
def checkCreateTarget(self):
form = self.request.form
if 'field.createTarget' in form:
if form.get('field.createTarget', False):
type = self.request.form.get('field.targetType',
'loops.resource.MediaAsset')
# TODO: find class (better: factory) from type name
factory = ConfigurationContext().resolve(type)
uri = self.request.form.get('field.targetUri', None)
# TODO: generate uri/__name__ if not given
if uri:
# TODO: find container
self.context.getLoopsRoot()['resources']['ma07'] = MediaAsset()
#self.context.loopsRoot['resources']['ma07'] = MediaAsset()
path = uri.split('/')
containerName = path[-2]
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):
""" An editing view for configuring a node, optionally creating

View file

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

View file

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

View file

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

View file

@ -55,6 +55,9 @@ class Resource(Contained, Persistent):
def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot()
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
def getClients(self, relationships=None):
rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels]
@ -105,4 +108,8 @@ class ResourceManager(BTreeContainer):
def getLoopsRoot(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.component import adapts
from zope.interface import implements
from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IResource, IDocument, IMediaAsset
from loops.interfaces import IView
@ -37,16 +38,17 @@ class ResourceProxy(object):
adapts(IView)
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)
def setContentType(self, contentType):
self.target._contentType = contentType
self.target.contentType = contentType
def getContentType(self): return self.target.contentType
contentType = property(getContentType, setContentType)
def __init__(self, context):
self.context = context
#self.context = removeSecurityProxy(context)
@Lazy
def target(self):

38
view.py
View file

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