From d6b7f5bc1f2cff4f0dba01a775849514586b5f51 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sat, 4 Mar 2006 14:50:16 +0000 Subject: [PATCH] Assignment of resources to concepts and vice versa git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1108 fd906abe-77d9-0310-91a1-e0d9ade77398 --- README.txt | 53 +++++++++++++++++----- browser/concept.py | 63 ++++++++++++++++++++++++-- browser/concept_resources.pt | 87 ++++++++++++++++++++++++++++++++++++ browser/configure.zcml | 23 +++++++++- browser/relation_macros.pt | 43 +++++++++--------- browser/resource.py | 69 ++++++++++++++++++++++++++-- browser/resource_concepts.pt | 49 ++++++++++++++++++++ concept.py | 2 +- interfaces.py | 27 ++++++++++- resource.py | 41 +++++++++++++++-- 10 files changed, 410 insertions(+), 47 deletions(-) create mode 100644 browser/concept_resources.pt create mode 100644 browser/resource_concepts.pt diff --git a/README.txt b/README.txt index 4d64333..defb60b 100755 --- a/README.txt +++ b/README.txt @@ -121,7 +121,7 @@ a special concept type. Concept Views ------------- - >>> from loops.browser.concept import ConceptView + >>> from loops.browser.concept import ConceptView, ConceptConfigureView >>> view = ConceptView(cc1, TestRequest()) >>> children = list(view.children()) @@ -136,18 +136,19 @@ of URIs to item and the predicate of the relationship: >>> [c.token for c in children] ['.loops/concepts/cc2:.loops/concepts/standard'] -The concept view allows updating the underlying context object: +There is also a concept configuration view that allows updating the +underlying context object: >>> cc3 = Concept(u'loops for Zope 3') >>> concepts['cc3'] = cc3 - >>> view = ConceptView(cc1, + >>> view = ConceptConfigureView(cc1, ... TestRequest(action='assign', tokens=['.loops/concepts/cc3'])) >>> view.update() True >>> sorted(c.title for c in cc1.getChildren()) [u'Zope 3', u'loops for Zope 3'] - >>> view = ConceptView(cc1, + >>> view = ConceptConfigureView(cc1, ... TestRequest(action='remove', qualifier='children', ... tokens=['.loops/concepts/cc2:.loops/concepts/standard'])) >>> view.update() @@ -159,14 +160,14 @@ We can also create a new concept and assign it: >>> params = {'action': 'create', 'create.name': 'cc4', ... 'create.title': u'New concept'} - >>> view = ConceptView(cc1, TestRequest(**params)) + >>> view = ConceptConfigureView(cc1, TestRequest(**params)) >>> view.update() True >>> sorted(c.title for c in cc1.getChildren()) [u'New concept', u'loops for Zope 3'] -The concept view provides methods for displaying concept types and -predicates: +The concept configuration view provides methods for displaying concept +types and predicates: >>> from zope.publisher.interfaces.browser import IBrowserRequest >>> from loops.browser.common import LoopsTerms @@ -257,15 +258,33 @@ We can associate a resource with a concept by assigning it to the concept: >>> list(res) [] -The resource also provides access to the associated concepts (or views, see -below) via the getClients() method: +The concept configuration view discussed above also manages the relations +from concepts to resources: - >>> conc = doc1.getClients() - >>> len(conc) + >>> len(cc1.getResources()) 1 - >>> conc[0] is cc1 + >>> form = dict(action='remove', qualifier='resources', + ... tokens=['.loops/resources/doc1:.loops/concepts/standard']) + >>> view = ConceptConfigureView(cc1, TestRequest(form=form)) + >>> [zapi.getName(r.context) for r in view.resources()] + [u'doc1'] + >>> view.update() True + >>> len(cc1.getResources()) + 0 + >>> form = dict(action='assign', assignAs='resource', + ... tokens=['.loops/resources/doc1']) + >>> view = ConceptConfigureView(cc1, TestRequest(form=form)) + >>> view.update() + True + >>> len(cc1.getResources()) + 1 +These relations may also be managed starting from a resource using +the resource configuration view: + + >>> from loops.browser.resource import ResourceConfigureView + Index attributes adapter ------------------------ @@ -393,6 +412,16 @@ out - this is usually done through ZCML.) >>> m111.target is cc2 True +A resource provides access to the associated views/nodes via the +getClients() method: + + >>> len(doc1.getClients()) + 0 + >>> m112.target = doc1 + >>> nodes = doc1.getClients() + >>> nodes[0] is m112 + True + Node Views ---------- diff --git a/browser/concept.py b/browser/concept.py index 69eeb8e..00627d6 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -28,6 +28,7 @@ from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.event.objectevent import ObjectCreatedEvent from zope.app.form.browser.interfaces import ITerms from zope.cachedescriptors.property import Lazy +from zope.dottedname.resolve import resolve from zope.event import notify from zope.interface import implements from zope.publisher.interfaces import BadRequest @@ -35,7 +36,10 @@ from zope.publisher.interfaces.browser import IBrowserRequest from zope import schema from zope.schema.interfaces import IIterableSource from zope.security.proxy import removeSecurityProxy +from loops.interfaces import IConcept from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList +from loops.resource import getResourceTypes, getResourceTypesForSearch +from loops.target import getTargetTypes from loops.browser.common import BaseView, LoopsTerms from loops import util @@ -50,6 +54,13 @@ class ConceptView(BaseView): for r in self.context.getParentRelations(): yield ConceptRelationView(r, self.request) + def resources(self): + for r in self.context.getResourceRelations(): + yield ConceptResourceRelationView(r, self.request, contextIsSecond=True) + + +class ConceptConfigureView(ConceptView): + def update(self): request = self.request action = request.get('action') @@ -75,6 +86,8 @@ class ConceptView(BaseView): self.context.assignChild(removeSecurityProxy(concept), predicate) elif assignAs == 'parent': self.context.assignParent(removeSecurityProxy(concept), predicate) + elif assignAs == 'resource': + self.context.assignResource(removeSecurityProxy(concept), predicate) else: raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) elif action == 'remove': @@ -84,6 +97,8 @@ class ConceptView(BaseView): self.context.deassignParent(concept, [predicate]) elif qualifier == 'children': self.context.deassignChild(concept, [predicate]) + elif qualifier == 'resources': + self.context.deassignResource(concept, [predicate]) else: raise(BadRequest, 'Illegal qualifier: %s.' % qualifier) else: @@ -97,8 +112,13 @@ class ConceptView(BaseView): raise(BadRequest, 'Empty name.') title = request.get('create.title', u'') conceptType = request.get('create.type') - concept = Concept(title) - container = self.loopsRoot.getConceptManager() + if conceptType and conceptType.startswith('loops.resource.'): + factory = resolve(conceptType) + concept = factory(title) + container = self.loopsRoot.getResourceManager() + else: + concept = Concept(title) + container = self.loopsRoot.getConceptManager() container[name] = concept if conceptType: ctype = self.loopsRoot.loopsTraverse(conceptType) @@ -113,6 +133,8 @@ class ConceptView(BaseView): self.context.assignChild(removeSecurityProxy(concept), predicate) elif assignAs == 'parent': self.context.assignParent(removeSecurityProxy(concept), predicate) + elif assignAs == 'resource': + self.context.assignResource(removeSecurityProxy(concept), predicate) else: raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) @@ -153,7 +175,10 @@ class ConceptView(BaseView): def viewIterator(self, objs): request = self.request for o in objs: - yield ConceptView(o, request) + if IConcept.providedBy(o): + yield ConceptConfigureView(o, request) + else: + yield BaseView(o, request) def conceptTypes(self): types = ConceptTypeSourceList(self.context) @@ -171,6 +196,13 @@ class ConceptView(BaseView): def getConceptTypeTokenForSearch(self, ct): return ct is None and 'unknown' or zapi.getName(ct) + def resourceTypes(self): + return util.KeywordVocabulary(getResourceTypes()) + + def resourceTypesForSearch(self): + return util.KeywordVocabulary(getResourceTypesForSearch()) + + def predicates(self): preds = PredicateSourceList(self.context) terms = zapi.getMultiAdapter((preds, self.request), ITerms) @@ -188,7 +220,6 @@ class ConceptRelationView(object): self.context = relation.first self.other = relation.second self.predicate = relation.predicate - self.conceptType = self.context.conceptType self.request = request @Lazy @@ -208,6 +239,10 @@ class ConceptRelationView(object): return ':'.join((self.loopsRoot.getLoopsUri(self.context), self.loopsRoot.getLoopsUri(self.predicate))) + @Lazy + def conceptType(self): + return self.context.conceptType + @Lazy def typeTitle(self): return self.conceptType.title @@ -224,3 +259,23 @@ class ConceptRelationView(object): def predicateUrl(self): return zapi.absoluteURL(self.predicate, self.request) + +class ConceptResourceRelationView(ConceptRelationView): + + @Lazy + def conceptType(self): + return None + + @Lazy + def typeTitle(self): + voc = util.KeywordVocabulary(getTargetTypes()) + token = '.'.join((self.context.__module__, + self.context.__class__.__name__)) + term = voc.getTermByToken(token) + return term.title + + + @Lazy + def typeUrl(self): + return '' + diff --git a/browser/concept_resources.pt b/browser/concept_resources.pt new file mode 100644 index 0000000..9b50807 --- /dev/null +++ b/browser/concept_resources.pt @@ -0,0 +1,87 @@ + + + + +
+ +

Concept Title


+ +
+ +
+ +
+ + + + + + and assign using Predicate + + + + + + + + + + + Object(s) using Predicate + + + +
+ +
+ + diff --git a/browser/configure.zcml b/browser/configure.zcml index 2528b24..49b10a3 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -105,7 +105,7 @@ + + + + + + + + + +