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:
parent
e95943cbf3
commit
1ded8434db
9 changed files with 159 additions and 127 deletions
38
README.txt
38
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,))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -8,39 +8,34 @@
|
|||
<h1 tal:content="context/title">Concept Title</h1><br />
|
||||
|
||||
<tal:block define="items view/parents;
|
||||
action string:remove;
|
||||
qualifier string:parents;
|
||||
legend string:Parent Concepts">
|
||||
<metal:parents use-macro="views/relation_macros/assignments" />
|
||||
summary string:Currently assigned objects;
|
||||
legend string:Parent Concepts;
|
||||
buttonText string:Remove Assignment(s);
|
||||
">
|
||||
<metal:parents use-macro="views/relation_macros/listing" />
|
||||
</tal:block>
|
||||
<tal:block define="items view/children;
|
||||
action string:remove;
|
||||
qualifier string:children;
|
||||
legend string:Child Concepts">
|
||||
<metal:children use-macro="views/relation_macros/assignments" />
|
||||
summary string:Currently assigned objects;
|
||||
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>
|
||||
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -414,12 +414,12 @@
|
|||
|
||||
<!-- vocabulary, traversing, and other stuff -->
|
||||
|
||||
<zope:adapter factory="loops.browser.terms.LoopsTerms"
|
||||
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
||||
for="loops.target.TargetSourceList
|
||||
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||
|
||||
<zope:adapter factory="loops.browser.terms.LoopsTerms"
|
||||
for="loops.browser.concept.ConceptSourceList
|
||||
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
||||
for="loops.concept.ConceptSourceList
|
||||
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||
|
||||
<zope:view factory="loops.view.NodeTraverser"
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
<html i18n:domain="loops">
|
||||
|
||||
|
||||
<metal:assignments define-macro="assignments">
|
||||
<form method="post" name="remove" action="."
|
||||
<metal:assignments define-macro="listing">
|
||||
<form method="post" name="listing" action="."
|
||||
tal:attributes="action request/URL"
|
||||
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"
|
||||
tal:condition="qualifier"
|
||||
tal:attributes="value qualifier" />
|
||||
<fieldset>
|
||||
<legend tal:content="legend">Parent Concepts</legend>
|
||||
<table class="listing" summary="Currently assigned objects">
|
||||
<legend tal:content="legend"
|
||||
i18n:translate="">Parent Concepts</legend>
|
||||
<table class="listing" summary="Currently assigned objects"
|
||||
i18n:attributes="summary"
|
||||
tal:attributes="summary summary">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
|
@ -32,9 +37,10 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<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)"
|
||||
i18n:attributes="value" />
|
||||
i18n:attributes="value"
|
||||
tal:attributes="value buttonText" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
|
|
@ -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)
|
||||
|
31
concept.py
31
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)
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
<require
|
||||
permission="zope.View"
|
||||
attributes="getLoopsUri" />
|
||||
attributes="getLoopsUri loopsTraverse" />
|
||||
|
||||
</content>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue