From 48f580ca314b98849362f55ba0165dab60d6b615 Mon Sep 17 00:00:00 2001 From: helmutm Date: Mon, 6 Feb 2006 15:14:04 +0000 Subject: [PATCH] More on assigning targets to views/nodes via a vocabulary, including doc tests git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1055 fd906abe-77d9-0310-91a1-e0d9ade77398 --- README.txt | 52 ++++++++++++++++++++++++++++++++++-------- __init__.py | 6 +++++ browser/node.py | 18 +++++++++------ browser/node_macros.pt | 4 ++-- browser/target.py | 3 ++- concept.py | 3 --- interfaces.py | 21 ++++++++++++----- resource.py | 3 --- target.py | 11 +++++---- view.py | 25 +++----------------- 10 files changed, 89 insertions(+), 57 deletions(-) diff --git a/README.txt b/README.txt index af08259..0b578be 100755 --- a/README.txt +++ b/README.txt @@ -271,20 +271,20 @@ Node Views ... print item.url, view.selected(item) http://127.0.0.1/loops/views/m1/m11 True -Node Schema Adapters --------------------- - -When configuring a node you may -specify what you want to do with respect to the node's target: associate -an existing one or create a new one. +Node Configuration +------------------ +When configuring a node you may specify what you want to do with respect +to the node's target: associate an existing one or create a new one. +These options are provided via the INodeConfigSchema that is provided +by a NodeConfigAdapter; in addition the attributes of the node (like the +title) may be changed via the NodeConfigAdapter. + >>> from loops.interfaces import INodeConfigSchema >>> from loops.view import NodeConfigAdapter >>> ztapi.provideAdapter(INode, INodeConfigSchema, NodeConfigAdapter) >>> nodeConfig = INodeConfigSchema(m111) - >>> nodeConfig.targetUri - '.loops/concepts/cc2' >>> nodeConfig.title = u'New title for m111' >>> nodeConfig.title u'New title for m111' @@ -293,9 +293,43 @@ an existing one or create a new one. >>> nodeConfig.target = doc1 >>> m111.target is doc1 True + >>> m111 in doc1.getClients() + True + +The targetUri and targetType fields are only relevant when creating +a new target object: + + >>> nodeConfig.targetUri + '' >>> nodeConfig.targetType 'loops.resource.Document' - >>> m111 in doc1.getClients() + +The node configuration form provides a target assignment field using +a vocabulary (source) for selecting the target. (In a future version this form +will be extended by a widget that lets you search for potential target +objects.) The source is basically a source list: + + >>> from loops.target import TargetSourceList + >>> source = TargetSourceList(m111) + >>> len(source) + 3 + >>> sorted([zapi.getName(s) for s in source]) + [u'cc1', u'cc2', u'doc1'] + +The form then uses a sort of browser view providing the ITerms interface +based on this source list: + + >>> from loops.browser.target import TargetTerms + >>> terms = TargetTerms(source, TestRequest()) + >>> term = terms.getTerm(doc1) + >>> term.token, term.title, term.value + ('.loops/resources/doc1', u'Zope Info', ) + + >>> term = terms.getTerm(cc1) + >>> term.token, term.title, term.value + ('.loops/concepts/cc1', u'cc1', ) + + >>> terms.getValue('.loops/concepts/cc1') is cc1 True There is a special edit view class that can be used to configure a node diff --git a/__init__.py b/__init__.py index d137a4a..80d3f5d 100644 --- a/__init__.py +++ b/__init__.py @@ -37,6 +37,12 @@ class Loops(Folder): def getLoopsRoot(self): return self + def getConceptManager(self): + return self['concepts'] + + def getResourceManager(self): + return self['resources'] + def getViewManager(self): return self['views'] diff --git a/browser/node.py b/browser/node.py index af49dc7..e226d68 100644 --- a/browser/node.py +++ b/browser/node.py @@ -32,7 +32,7 @@ from zope.proxy import removeAllProxies from zope.security import canAccess, canWrite from zope.security.proxy import removeSecurityProxy -from loops.interfaces import IDocument, IMediaAsset +from loops.interfaces import IConcept, IDocument, IMediaAsset from loops.resource import MediaAsset class NodeView(object): @@ -97,7 +97,9 @@ class NodeView(object): target = self.target if target is None or IDocument.providedBy(target): return 'textbody' - if target.contentType.startswith('image/'): + if IConcept.providedBy(target): # TODO... + return 'filebody' + if IMediaAsset.providedBy(target) and target.contentType.startswith('image/'): return 'imagebody' return 'filebody' @@ -138,20 +140,23 @@ class ConfigureBaseView(object): def checkCreateTarget(self): form = self.request.form if form.get('field.createTarget', False): + root = self.loopsRoot type = self.request.form.get('field.targetType', 'loops.resource.MediaAsset') factory = resolve(type) uri = self.request.form.get('field.targetUri', None) if uri: path = uri.split('/') + # TODO: check for .loops prefix containerName = path[-2] name = path[-1] + container = root[containerName] else: - containerName = 'resource' in type and 'resources' or 'concepts' - viewManagerPath = zapi.getPath(self.context.getViewManager()) + container = ('.resource.' in type and root.getResourceManager() + or root.getConceptManager()) + viewManagerPath = zapi.getPath(root.getViewManager()) name = zapi.getPath(self.context)[len(viewManagerPath)+1:] name = name.replace('/', '.') - container = self.loopsRoot[containerName] # check for duplicates: num = 1 basename = name @@ -161,9 +166,8 @@ class ConfigureBaseView(object): # create target: container[name] = factory() target = container[name] - # set possibly new targetUri in request for further processing: + # set possibly new target uri in request for further processing: targetUri = self.loopsRoot.getLoopsUri(target) - #form['field.targetUri'] = targetUri form['field.target'] = targetUri return target diff --git a/browser/node_macros.pt b/browser/node_macros.pt index bb84902..783a1e0 100644 --- a/browser/node_macros.pt +++ b/browser/node_macros.pt @@ -22,12 +22,12 @@ The body
+ tal:content="structure item/renderTargetBody"> The body
diff --git a/browser/target.py b/browser/target.py index f4d79e7..b1fdb6a 100644 --- a/browser/target.py +++ b/browser/target.py @@ -45,7 +45,8 @@ class TargetTerms(object): def getTerm(self, value): token = self.loopsRoot.getLoopsUri(value) - return SimpleTerm(value, token, value.title) + title = value.title or zapi.getName(value) + return SimpleTerm(value, token, title) def getValue(self, token): return self.loopsRoot.loopsTraverse(token) diff --git a/concept.py b/concept.py index 5dc421b..9f52087 100644 --- a/concept.py +++ b/concept.py @@ -67,9 +67,6 @@ 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): diff --git a/interfaces.py b/interfaces.py index 2b974bc..caaec81 100644 --- a/interfaces.py +++ b/interfaces.py @@ -46,13 +46,9 @@ class ILoopsObject(Interface): """ Return the loops root object. """ - def getViewManager(): - """ Return the (default) view manager. - """ - class IPotentialTarget(Interface): - """ For objects that may be used as target objects for view objects. + """ For objects that may be used as target objects for views/nodes. """ proxyInterface = Attribute('An interface allowing an object to be ' @@ -381,9 +377,22 @@ class ILoops(ILoopsObject, IFolder): """ def loopsTraverse(uri): - """ Retrieve object specified by the loops uri given. + """ Retrieve object specified by the loops uri (starting with + '.loops/') given. """ + def getConceptManager(): + """ Return the (default) concept manager. + """ + + def getResourceManager(): + """ Return the (default) resource manager. + """ + + def getViewManager(): + """ Return the (default) view manager. + """ + class ILoopsContained(Interface): containers(ILoops) diff --git a/resource.py b/resource.py index 246504b..3cfe9ff 100644 --- a/resource.py +++ b/resource.py @@ -57,9 +57,6 @@ 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] diff --git a/target.py b/target.py index f186d91..be8b36a 100644 --- a/target.py +++ b/target.py @@ -109,12 +109,15 @@ class TargetSourceList(object): def __init__(self, context): self.context = removeSecurityProxy(context) - self.resources = self.context.getLoopsRoot()['resources'] + root = self.context.getLoopsRoot() + self.resources = root.getResourceManager() + self.concepts = root.getConceptManager() def __iter__(self): - return iter(self.resources.values()) + return iter(list(self.resources.values()) + list(self.concepts.values())) - def __len__(): - return len(self.resources) + def __len__(self): + return len(self.resources) + len(self.concepts) + \ No newline at end of file diff --git a/view.py b/view.py index 7f482d9..31f0867 100644 --- a/view.py +++ b/view.py @@ -91,9 +91,6 @@ class View(object): def getLoopsRoot(self): return zapi.getParent(self).getLoopsRoot() - def getViewManager(self): - return zapi.getParent(self).getViewManager() - class Node(View, OrderedContainer): @@ -204,23 +201,8 @@ class NodeConfigAdapter(object): @Lazy def loopsRoot(self): return self.context.getLoopsRoot() - def getTargetUri(self): - target = self.target - if target is not None: - return self.loopsRoot.getLoopsUri(target) - else: - return '' - - def setTargetUri(self, uri): - return # ignore - only relevant for target creation - 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 - + def getTargetUri(self):return '' + def setTargetUri(self, uri): pass targetUri = property(getTargetUri, setTargetUri) def getTargetType(self): @@ -228,8 +210,7 @@ class NodeConfigAdapter(object): if target: return '%s.%s' % (target.__module__, target.__class__.__name__) return None - def setTargetType(self, tt): - pass # only used whe a new target object is created + def setTargetType(self, tt): pass targetType = property(getTargetType, setTargetType) def getCreateTarget(self): return False