Work in progress: concept assignments

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1078 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-02-14 12:05:04 +00:00
parent e95943cbf3
commit 1ded8434db
9 changed files with 159 additions and 127 deletions

View file

@ -81,12 +81,39 @@ Concept Views
>>> sorted([c.title for c in view.children()]) >>> sorted([c.title for c in view.children()])
[u'Zope 3'] [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() >>> voc = view.getVocabularyForRelated()
>>> for term in voc: >>> for term in voc:
... print term.token, term.title ... print term.token, term.title
.loops/concepts/cc1 .loops/concepts/cc1 cc1
.loops/concepts/cc2 Zope 3 .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 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 >>> from loops.target import TargetSourceList
>>> source = TargetSourceList(m111) >>> source = TargetSourceList(m111)
>>> len(source) >>> len(source)
3 4
>>> sorted([zapi.getName(s) for s in source]) >>> 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 The form then uses a sort of browser view providing the ITerms interface
based on this source list: based on this source list:
>>> from loops.browser.terms import LoopsTerms >>> from loops.browser.common import LoopsTerms
>>> terms = LoopsTerms(source, TestRequest()) >>> terms = LoopsTerms(source, TestRequest())
>>> term = terms.getTerm(doc1) >>> term = terms.getTerm(doc1)
>>> term.token, term.title, term.value >>> 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. and of a lot of other stuff needed for the rendering machine.
>>> from zope.app.publisher.interfaces.browser import IBrowserView >>> from zope.app.publisher.interfaces.browser import IBrowserView
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from loops.browser.resource import DocumentView >>> from loops.browser.resource import DocumentView
>>> ztapi.provideAdapter(IDocument, Interface, DocumentView, >>> ztapi.provideAdapter(IDocument, Interface, DocumentView,
... with=(IBrowserRequest,)) ... with=(IBrowserRequest,))

View file

@ -24,7 +24,10 @@ $Id$
from zope.app import zapi from zope.app import zapi
from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.app.form.browser.interfaces import ITerms
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.interface import implements
#from zope.schema.vocabulary import SimpleTerm
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
class BaseView(object): class BaseView(object):
@ -56,5 +59,37 @@ class BaseView(object):
@Lazy @Lazy
def title(self): 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)

View file

@ -24,12 +24,14 @@ $Id$
from zope.app import zapi from zope.app import zapi
from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.app.form.browser.interfaces import ITerms
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.interface import implements from zope.interface import implements
from zope.publisher.interfaces import BadRequest
from zope import schema from zope import schema
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from loops.browser.common import BaseView from loops.concept import ConceptSourceList
from loops.browser.terms import LoopsTerms from loops.browser.common import BaseView, LoopsTerms
class ConceptView(BaseView): class ConceptView(BaseView):
@ -45,32 +47,29 @@ class ConceptView(BaseView):
yield ConceptView(c, request) yield ConceptView(c, request)
def update(self): def update(self):
concept_name = self.request.get('concept_name', None) action = self.request.get('action', None)
if concept_name: if action is None:
concept = zapi.getParent(self.context)[concept_name] return True
self.context.assignChild(removeSecurityProxy(concept)) 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 return True
def getVocabularyForRelated(self): def getVocabularyForRelated(self):
source = ConceptSourceList(self.context) source = ConceptSourceList(self.context)
terms = zapi.getMultiAdapter((source, self.request), ITerms)
for candidate in source: for candidate in source:
yield LoopsTerms(ConceptView(candidate, self.request), self.request) yield terms.getTerm(candidate)
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)

View file

@ -8,39 +8,34 @@
<h1 tal:content="context/title">Concept Title</h1><br /> <h1 tal:content="context/title">Concept Title</h1><br />
<tal:block define="items view/parents; <tal:block define="items view/parents;
action string:remove;
qualifier string:parents; qualifier string:parents;
legend string:Parent Concepts"> summary string:Currently assigned objects;
<metal:parents use-macro="views/relation_macros/assignments" /> legend string:Parent Concepts;
buttonText string:Remove Assignment(s);
">
<metal:parents use-macro="views/relation_macros/listing" />
</tal:block> </tal:block>
<tal:block define="items view/children; <tal:block define="items view/children;
action string:remove;
qualifier string:children; qualifier string:children;
legend string:Child Concepts"> summary string:Currently assigned objects;
<metal:children use-macro="views/relation_macros/assignments" /> legend string:Child Concepts;
buttonText string:Remove Assignment(s);
">
<metal:children use-macro="views/relation_macros/listing" />
</tal:block>
<tal:block define="items view/getVocabularyForRelated;
action string:assign;
qualifier nothing;
summary string:Assignment candidates;
legend string:Assign as Children;
buttonText string:Assign Object(s);
">
<metal:assign use-macro="views/relation_macros/listing" />
</tal:block> </tal:block>
<form action="." method="post"
tal:attributes="action request/URL">
<div class="row">
<span class="label">Concept Name</span>:
<span class="field">
<input type="test" name="concept_name" />
</span>
</div>
<div class="row">
<select name="concept">
<tal:option repeat="term view/getVocabularyForRelated">
<option tal:content="term/title"
tal:attributes="value term/token">
Concept Abc
</option>
</tal:option>
</select>
</div>
<div class="row">
<input type="submit" name="concept_assign" value="Assign Concept" />
</div>
</form>
</div> </div>
</body> </body>
</html> </html>

View file

@ -414,12 +414,12 @@
<!-- vocabulary, traversing, and other stuff --> <!-- vocabulary, traversing, and other stuff -->
<zope:adapter factory="loops.browser.terms.LoopsTerms" <zope:adapter factory="loops.browser.common.LoopsTerms"
for="loops.target.TargetSourceList for="loops.target.TargetSourceList
zope.publisher.interfaces.browser.IBrowserRequest" /> zope.publisher.interfaces.browser.IBrowserRequest" />
<zope:adapter factory="loops.browser.terms.LoopsTerms" <zope:adapter factory="loops.browser.common.LoopsTerms"
for="loops.browser.concept.ConceptSourceList for="loops.concept.ConceptSourceList
zope.publisher.interfaces.browser.IBrowserRequest" /> zope.publisher.interfaces.browser.IBrowserRequest" />
<zope:view factory="loops.view.NodeTraverser" <zope:view factory="loops.view.NodeTraverser"

View file

@ -1,16 +1,21 @@
<html i18n:domain="loops"> <html i18n:domain="loops">
<metal:assignments define-macro="assignments"> <metal:assignments define-macro="listing">
<form method="post" name="remove" action="." <form method="post" name="listing" action="."
tal:attributes="action request/URL" tal:attributes="action request/URL"
tal:condition="items"> tal:condition="items">
<input type="hidden" name="action" value="remove" /> <input type="hidden" name="action" value="remove"
tal:attributes="value action" />
<input type="hidden" name="qualifier" value="parents" <input type="hidden" name="qualifier" value="parents"
tal:condition="qualifier"
tal:attributes="value qualifier" /> tal:attributes="value qualifier" />
<fieldset> <fieldset>
<legend tal:content="legend">Parent Concepts</legend> <legend tal:content="legend"
<table class="listing" summary="Currently assigned objects"> i18n:translate="">Parent Concepts</legend>
<table class="listing" summary="Currently assigned objects"
i18n:attributes="summary"
tal:attributes="summary summary">
<thead> <thead>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
@ -32,9 +37,10 @@
</tbody> </tbody>
</table> </table>
<div class="formControls"> <div class="formControls">
<input class="context" type="submit" name="form.button.Remove" <input class="context" type="submit" name="form.button.submit"
value="Remove Assignment(s)" value="Remove Assignment(s)"
i18n:attributes="value" /> i18n:attributes="value"
tal:attributes="value buttonText" />
</div> </div>
</fieldset> </fieldset>
</form> </form>

View file

@ -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)

View file

@ -26,6 +26,8 @@ from zope.app import zapi
from zope.app.container.btree import BTreeContainer from zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained from zope.app.container.contained import Contained
from zope.interface import implements from zope.interface import implements
from zope import schema
from zope.security.proxy import removeSecurityProxy
from persistent import Persistent from persistent import Persistent
from cybertools.relation import DyadicRelation from cybertools.relation import DyadicRelation
@ -96,10 +98,12 @@ class Concept(Contained, Persistent):
if relationships is None: if relationships is None:
relationships = [ConceptRelation] relationships = [ConceptRelation]
registry = zapi.getUtility(IRelationRegistry) registry = zapi.getUtility(IRelationRegistry)
relations = registry.query(first=self, second=concept, relations = []
relationships=relationships) for rs in relationships:
relations.extend(registry.query(first=self, second=concept,
relationship=rs))
for rel in relations: for rel in relations:
registry.unregister(relation) registry.unregister(rel)
def deassignParents(self, concept, relationships=None): def deassignParents(self, concept, relationships=None):
concept.deassignChildren(self, relationships) concept.deassignChildren(self, relationships)
@ -140,3 +144,24 @@ class ConceptManager(BTreeContainer):
def getViewManager(self): def getViewManager(self):
return self.getLoopsRoot().getViewManager() 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)

View file

@ -49,7 +49,7 @@
<require <require
permission="zope.View" permission="zope.View"
attributes="getLoopsUri" /> attributes="getLoopsUri loopsTraverse" />
</content> </content>