diff --git a/README.txt b/README.txt index 459c930..bcd3868 100755 --- a/README.txt +++ b/README.txt @@ -81,12 +81,39 @@ Concept Views >>> sorted([c.title for c in view.children()]) [u'Zope 3'] +The concept view allows to get a list of terms (sort of vocabulary) that +can be used to show the objects in a listing: + + >>> from zope.publisher.interfaces.browser import IBrowserRequest + >>> from zope.app.form.browser.interfaces import ITerms + >>> from loops.concept import ConceptSourceList + >>> from loops.browser.common import LoopsTerms + >>> ztapi.provideAdapter(ConceptSourceList, ITerms, LoopsTerms, + ... with=(IBrowserRequest,)) >>> voc = view.getVocabularyForRelated() >>> for term in voc: ... print term.token, term.title - .loops/concepts/cc1 + .loops/concepts/cc1 cc1 .loops/concepts/cc2 Zope 3 - + +The concept view allows updating the underlying context object: + + >>> cc3 = Concept(u'loops for Zope 3') + >>> concepts['cc3'] = cc3 + >>> view = ConceptView(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, + ... TestRequest(action='remove', qualifier='children', + ... tokens=['.loops/concepts/cc2'])) + >>> view.update() + True + >>> sorted(c.title for c in cc1.getChildren()) + [u'loops for Zope 3'] Resources and what they have to do with Concepts ================================================ @@ -329,14 +356,14 @@ objects.) The source is basically a source list: >>> from loops.target import TargetSourceList >>> source = TargetSourceList(m111) >>> len(source) - 3 + 4 >>> sorted([zapi.getName(s) for s in source]) - [u'cc1', u'cc2', u'doc1'] + [u'cc1', u'cc2', u'cc3', u'doc1'] The form then uses a sort of browser view providing the ITerms interface based on this source list: - >>> from loops.browser.terms import LoopsTerms + >>> from loops.browser.common import LoopsTerms >>> terms = LoopsTerms(source, TestRequest()) >>> term = terms.getTerm(doc1) >>> term.token, term.title, term.value @@ -402,7 +429,6 @@ method. This makes use of a browser view registered for the target interface, and of a lot of other stuff needed for the rendering machine. >>> from zope.app.publisher.interfaces.browser import IBrowserView - >>> from zope.publisher.interfaces.browser import IBrowserRequest >>> from loops.browser.resource import DocumentView >>> ztapi.provideAdapter(IDocument, Interface, DocumentView, ... with=(IBrowserRequest,)) diff --git a/browser/common.py b/browser/common.py index 8b3c84a..91a8858 100644 --- a/browser/common.py +++ b/browser/common.py @@ -24,7 +24,10 @@ $Id$ from zope.app import zapi from zope.app.dublincore.interfaces import ICMFDublinCore +from zope.app.form.browser.interfaces import ITerms from zope.cachedescriptors.property import Lazy +from zope.interface import implements +#from zope.schema.vocabulary import SimpleTerm from zope.security.proxy import removeSecurityProxy class BaseView(object): @@ -56,5 +59,37 @@ class BaseView(object): @Lazy def title(self): - return self.context.title + return self.context.title or zapi.getName(self.context) + + @Lazy + def value(self): + return self.context + + +class LoopsTerms(object): + """ Provide the ITerms interface, e.g. for usage in selection + lists. + """ + + implements(ITerms) + + def __init__(self, source, request): + # the source parameter is a view or adapter of a real context object: + self.source = source + self.context = source.context + self.request = request + + @Lazy + def loopsRoot(self): + return self.context.getLoopsRoot() + + def getTerm(self, value): + return BaseView(value, self.request) + #token = self.loopsRoot.getLoopsUri(value) + #title = value.title or zapi.getName(value) + #return SimpleTerm(value, token, title) + + def getValue(self, token): + return self.loopsRoot.loopsTraverse(token) + diff --git a/browser/concept.py b/browser/concept.py index a06b171..3c0112c 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -24,12 +24,14 @@ $Id$ from zope.app import zapi from zope.app.dublincore.interfaces import ICMFDublinCore +from zope.app.form.browser.interfaces import ITerms from zope.cachedescriptors.property import Lazy from zope.interface import implements +from zope.publisher.interfaces import BadRequest from zope import schema from zope.security.proxy import removeSecurityProxy -from loops.browser.common import BaseView -from loops.browser.terms import LoopsTerms +from loops.concept import ConceptSourceList +from loops.browser.common import BaseView, LoopsTerms class ConceptView(BaseView): @@ -45,32 +47,29 @@ class ConceptView(BaseView): yield ConceptView(c, request) def update(self): - concept_name = self.request.get('concept_name', None) - if concept_name: - concept = zapi.getParent(self.context)[concept_name] - self.context.assignChild(removeSecurityProxy(concept)) + action = self.request.get('action', None) + if action is None: + return True + tokens = self.request.get('tokens', []) + for token in tokens: + concept = self.loopsRoot.loopsTraverse(token) + if action == 'assign': + self.context.assignChild(removeSecurityProxy(concept)) + elif action == 'remove': + qualifier = self.request.get('qualifier', None) + if qualifier == 'parents': + self.context.deassignParents(concept) + elif qualifier == 'children': + self.context.deassignChildren(concept) + else: + raise(BadRequest, 'Illegal qualifier: %s.' % qualifier) + else: + raise(BadRequest, 'Illegal action: %s.' % action) return True def getVocabularyForRelated(self): source = ConceptSourceList(self.context) + terms = zapi.getMultiAdapter((source, self.request), ITerms) for candidate in source: - yield LoopsTerms(ConceptView(candidate, self.request), self.request) - - -class ConceptSourceList(object): - - implements(schema.interfaces.IIterableSource) - - def __init__(self, context): - #self.context = context - self.context = removeSecurityProxy(context) - root = self.context.getLoopsRoot() - self.concepts = root.getConceptManager() - - def __iter__(self): - for obj in self.concepts.values(): - yield obj - - def __len__(self): - return len(self.concepts) + yield terms.getTerm(candidate) diff --git a/browser/concept_related.pt b/browser/concept_related.pt index c43defe..8569e9f 100644 --- a/browser/concept_related.pt +++ b/browser/concept_related.pt @@ -8,39 +8,34 @@

Concept Title


- + summary string:Currently assigned objects; + legend string:Parent Concepts; + buttonText string:Remove Assignment(s); + "> + - + summary string:Currently assigned objects; + legend string:Child Concepts; + buttonText string:Remove Assignment(s); + "> + + + + + -
-
- Concept Name: - - - -
-
- -
-
- -
-
- diff --git a/browser/configure.zcml b/browser/configure.zcml index 58dcd26..b2bba13 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -414,12 +414,12 @@ - - - -
+ - +
- Parent Concepts - + Parent Concepts +
@@ -32,9 +37,10 @@
 
- + i18n:attributes="value" + tal:attributes="value buttonText" />
diff --git a/browser/terms.py b/browser/terms.py deleted file mode 100644 index bc55683..0000000 --- a/browser/terms.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2006 Helmut Merz helmutm@cy55.de -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -""" -Class(es) for representing a related object , to be used e.g. for -vocabularies and widgets. - -$Id$ -""" - -from zope.app import zapi -from zope.app.form.browser.interfaces import ITerms -from zope.schema.vocabulary import SimpleTerm -from zope.cachedescriptors.property import Lazy -from zope.interface import implements -from zope.security.proxy import removeSecurityProxy -from loops.browser.common import BaseView - - -class LoopsTerms(BaseView): - - implements(ITerms) - - def __init__(self, context, request): - self.context = context.context # the context parameter is the source object - self.request = request - - @Lazy - def loopsRoot(self): - return self.context.getLoopsRoot() - - def getTerm(self, value): - token = self.loopsRoot.getLoopsUri(value) - 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 396366e..8de4619 100644 --- a/concept.py +++ b/concept.py @@ -26,6 +26,8 @@ from zope.app import zapi from zope.app.container.btree import BTreeContainer from zope.app.container.contained import Contained from zope.interface import implements +from zope import schema +from zope.security.proxy import removeSecurityProxy from persistent import Persistent from cybertools.relation import DyadicRelation @@ -96,10 +98,12 @@ class Concept(Contained, Persistent): if relationships is None: relationships = [ConceptRelation] registry = zapi.getUtility(IRelationRegistry) - relations = registry.query(first=self, second=concept, - relationships=relationships) + relations = [] + for rs in relationships: + relations.extend(registry.query(first=self, second=concept, + relationship=rs)) for rel in relations: - registry.unregister(relation) + registry.unregister(rel) def deassignParents(self, concept, relationships=None): concept.deassignChildren(self, relationships) @@ -140,3 +144,24 @@ class ConceptManager(BTreeContainer): def getViewManager(self): return self.getLoopsRoot().getViewManager() + +# adapters and similar components + +class ConceptSourceList(object): + + implements(schema.interfaces.IIterableSource) + + def __init__(self, context): + #self.context = context + self.context = removeSecurityProxy(context) + root = self.context.getLoopsRoot() + self.concepts = root.getConceptManager() + + def __iter__(self): + for obj in self.concepts.values(): + yield obj + + def __len__(self): + return len(self.concepts) + + diff --git a/configure.zcml b/configure.zcml index 5d001bc..dfb686d 100644 --- a/configure.zcml +++ b/configure.zcml @@ -49,7 +49,7 @@ + attributes="getLoopsUri loopsTraverse" />