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:
parent
3cbba1d593
commit
b02329358a
10 changed files with 144 additions and 36 deletions
33
README.txt
33
README.txt
|
@ -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']
|
||||||
|
|
||||||
|
|
|
@ -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)):])
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
38
view.py
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue