diff --git a/README.txt b/README.txt index f85d921..6ec4233 100755 --- a/README.txt +++ b/README.txt @@ -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'] diff --git a/__init__.py b/__init__.py index 6c9ffbb..17abd30 100644 --- a/__init__.py +++ b/__init__.py @@ -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)):]) + diff --git a/browser/configure.zcml b/browser/configure.zcml index 0e5e472..5db0a57 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -247,7 +247,6 @@ @@ -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"> @@ -304,6 +304,12 @@ + + + + + + - - diff --git a/browser/node.py b/browser/node.py index c7c5656..0988888 100644 --- a/browser/node.py +++ b/browser/node.py @@ -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 diff --git a/concept.py b/concept.py index a56f4b2..1bbd42d 100644 --- a/concept.py +++ b/concept.py @@ -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() + + + diff --git a/configure.zcml b/configure.zcml index 4bb0309..4e69e35 100644 --- a/configure.zcml +++ b/configure.zcml @@ -218,8 +218,10 @@ - - + + 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