concept relations stuff basically OK

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1094 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-02-22 14:54:18 +00:00
parent 09b3bf29e5
commit e86c3e331a
7 changed files with 180 additions and 58 deletions

View file

@ -49,7 +49,7 @@ default predicate concept; the default name for this is 'standard'.
>>> from cybertools.relation.registry import DummyRelationRegistry >>> from cybertools.relation.registry import DummyRelationRegistry
>>> from zope.app.testing import ztapi >>> from zope.app.testing import ztapi
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry()) >>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
>>> concepts['standard'] = Concept('parent') >>> concepts['standard'] = Concept(u'subconcept')
Now we can assign the concept c2 as a child to c1 (using the standard Now we can assign the concept c2 as a child to c1 (using the standard
ConceptRelation): ConceptRelation):
@ -104,6 +104,20 @@ We get a list of types using the ConceptTypeSourceList:
>>> sorted(t.title for t in types) >>> sorted(t.title for t in types)
[u'Topic', u'Type', u'Unknown Type'] [u'Topic', u'Type', u'Unknown Type']
Using a PredicateSourceList we can retrieve a list of the available
predicates. In order for this to work we first have to assign our predicates
a special concept type.
>>> concepts['predicate'] = Concept(u'Predicate')
>>> predicate = concepts['predicate']
>>> concepts['hasType'].conceptType = predicate
>>> concepts['standard'].conceptType = predicate
>>> from loops.concept import PredicateSourceList
>>> predicates = PredicateSourceList(cc1)
>>> sorted(t.title for t in predicates)
[u'has type', u'subconcept']
Concept Views Concept Views
------------- -------------
@ -151,6 +165,24 @@ We can also create a new concept and assign it:
>>> sorted(c.title for c in cc1.getChildren()) >>> sorted(c.title for c in cc1.getChildren())
[u'New concept', u'loops for Zope 3'] [u'New concept', u'loops for Zope 3']
The concept view provides methods for displaying concept types and
predicates:
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from loops.browser.common import LoopsTerms
>>> from zope.app.form.browser.interfaces import ITerms
>>> from zope.schema.interfaces import IIterableSource
>>> ztapi.provideAdapter(IIterableSource, ITerms, LoopsTerms,
... with=(IBrowserRequest,))
>>> sorted((t.title, t.token) for t in view.conceptTypes())
[(u'Topic', '.loops/concepts/topic'), (u'Type', '.loops/concepts/type'),
(u'Unknown Type', '.loops/concepts/unknown')]
>>> sorted((t.title, t.token) for t in view.predicates())
[(u'has type', '.loops/concepts/hasType'),
(u'subconcept', '.loops/concepts/standard')]
Searchable Text Adapter Searchable Text Adapter
----------------------- -----------------------
@ -406,7 +438,6 @@ objects.) The source is basically a source list:
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.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
@ -471,7 +502,6 @@ A node's target is rendered using the NodeView's renderTargetBody()
method. This makes use of a browser view registered for the target interface, 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.publisher.interfaces.browser import IBrowserRequest
>>> from zope.app.publisher.interfaces.browser import IBrowserView >>> from zope.app.publisher.interfaces.browser import IBrowserView
>>> from loops.browser.resource import DocumentView >>> from loops.browser.resource import DocumentView
>>> ztapi.provideAdapter(IDocument, Interface, DocumentView, >>> ztapi.provideAdapter(IDocument, Interface, DocumentView,

View file

@ -31,9 +31,11 @@ from zope.cachedescriptors.property import Lazy
from zope.event import notify from zope.event import notify
from zope.interface import implements from zope.interface import implements
from zope.publisher.interfaces import BadRequest from zope.publisher.interfaces import BadRequest
from zope.publisher.interfaces.browser import IBrowserRequest
from zope import schema from zope import schema
from zope.schema.interfaces import IIterableSource
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from loops.concept import Concept from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
from loops.browser.common import BaseView, LoopsTerms from loops.browser.common import BaseView, LoopsTerms
@ -46,30 +48,16 @@ class ConceptView(BaseView):
def parents(self): def parents(self):
for r in self.context.getParentRelations(): for r in self.context.getParentRelations():
yield ConceptRelationView(r, self.request) yield ConceptRelationView(r, self.request)
#rels = self.context.getParentRelations()
#result = []
#for r in rels:
# p = r.first
#if p is None: # this should not be necessary
# print 'Warning: parents() got a None first on', \
# zapi.getName(self.context), zapi.getName(r.predicate)
# continue
# p.predicate = r.predicate
#return result and self.viewIterator(result) or []
def viewIterator(self, objs):
request = self.request
for o in objs:
yield ConceptView(o, request)
def update(self): def update(self):
action = self.request.get('action') request = self.request
action = request.get('action')
if action is None: if action is None:
return True return True
if action == 'create': if action == 'create':
self.createAndAssign() self.createAndAssign()
return True return True
tokens = self.request.get('tokens', []) tokens = request.get('tokens', [])
for token in tokens: for token in tokens:
parts = token.split(':') parts = token.split(':')
token = parts[0] token = parts[0]
@ -77,16 +65,20 @@ class ConceptView(BaseView):
relToken = parts[1] relToken = parts[1]
concept = self.loopsRoot.loopsTraverse(token) concept = self.loopsRoot.loopsTraverse(token)
if action == 'assign': if action == 'assign':
assignAs = self.request.get('assignAs', 'child') assignAs = request.get('assignAs', 'child')
predicate = request.get('predicate') or None
if predicate:
predicate = removeSecurityProxy(
self.loopsRoot.loopsTraverse(predicate))
if assignAs == 'child': if assignAs == 'child':
self.context.assignChild(removeSecurityProxy(concept)) self.context.assignChild(removeSecurityProxy(concept), predicate)
elif assignAs == 'parent': elif assignAs == 'parent':
self.context.assignParent(removeSecurityProxy(concept)) self.context.assignParent(removeSecurityProxy(concept), predicate)
else: else:
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
elif action == 'remove': elif action == 'remove':
predicate = self.loopsRoot.loopsTraverse(relToken) predicate = self.loopsRoot.loopsTraverse(relToken)
qualifier = self.request.get('qualifier') qualifier = request.get('qualifier')
if qualifier == 'parents': if qualifier == 'parents':
self.context.deassignParent(concept, [predicate]) self.context.deassignParent(concept, [predicate])
elif qualifier == 'children': elif qualifier == 'children':
@ -103,17 +95,23 @@ class ConceptView(BaseView):
if not name: if not name:
raise(BadRequest, 'Empty name.') raise(BadRequest, 'Empty name.')
title = request.get('create.title', u'') title = request.get('create.title', u'')
type = request.get('create.type') conceptType = request.get('create.type')
concept = Concept(title) concept = Concept(title)
container = self.loopsRoot.getConceptManager() container = self.loopsRoot.getConceptManager()
container[name] = concept container[name] = concept
# TODO: notify ObjectCreatedEvent() (?) if conceptType:
#notify(ObjectCreatedEvent(removeSecurityProxy(concept))) ctype = self.loopsRoot.loopsTraverse(conceptType)
concept.conceptType = ctype
notify(ObjectCreatedEvent(removeSecurityProxy(concept)))
assignAs = self.request.get('assignAs', 'child') assignAs = self.request.get('assignAs', 'child')
predicate = request.get('create.predicate') or None
if predicate:
predicate = removeSecurityProxy(
self.loopsRoot.loopsTraverse(predicate))
if assignAs == 'child': if assignAs == 'child':
self.context.assignChild(removeSecurityProxy(concept)) self.context.assignChild(removeSecurityProxy(concept), predicate)
elif assignAs == 'parent': elif assignAs == 'parent':
self.context.assignParent(removeSecurityProxy(concept)) self.context.assignParent(removeSecurityProxy(concept), predicate)
else: else:
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
@ -127,8 +125,32 @@ class ConceptView(BaseView):
result = cat.searchResults(loops_searchableText=searchTerm) result = cat.searchResults(loops_searchableText=searchTerm)
else: else:
result = self.loopsRoot.getConceptManager().values() result = self.loopsRoot.getConceptManager().values()
searchType = request.get('searchType', '*')
# TODO: query catalog for type
if not searchType:
result = [r for r in result if r.conceptType is None]
elif searchType != '*':
type = self.loopsRoot.loopsTraverse(searchType)
result = [r for r in result if r.conceptType == type]
return self.viewIterator(result) return self.viewIterator(result)
def viewIterator(self, objs):
request = self.request
for o in objs:
yield ConceptView(o, request)
def conceptTypes(self):
types = ConceptTypeSourceList(self.context)
terms = zapi.getMultiAdapter((types, self.request), ITerms)
for type in types:
yield terms.getTerm(type)
def predicates(self):
preds = PredicateSourceList(self.context)
terms = zapi.getMultiAdapter((preds, self.request), ITerms)
for pred in preds:
yield terms.getTerm(pred)
class ConceptRelationView(object): class ConceptRelationView(object):

View file

@ -12,6 +12,7 @@
qualifier string:parents; qualifier string:parents;
summary string:Currently assigned objects; summary string:Currently assigned objects;
legend string:Parent Concepts; legend string:Parent Concepts;
showPredicate string:yes;
buttonText string:Remove Parents;" buttonText string:Remove Parents;"
style="float:left; padding-right:20px"> style="float:left; padding-right:20px">
<metal:parents use-macro="views/relation_macros/listing" /> <metal:parents use-macro="views/relation_macros/listing" />
@ -21,6 +22,7 @@
qualifier string:children; qualifier string:children;
summary string:Currently assigned objects; summary string:Currently assigned objects;
legend string:Child Concepts; legend string:Child Concepts;
showPredicate string:yes;
buttonText string:Remove Children;" buttonText string:Remove Children;"
style="padding-right:20px"> style="padding-right:20px">
<metal:children use-macro="views/relation_macros/listing" /> <metal:children use-macro="views/relation_macros/listing" />
@ -37,6 +39,7 @@
qualifier nothing; qualifier nothing;
summary string:Assignment candidates; summary string:Assignment candidates;
legend string:Search; legend string:Search;
showPredicate nothing;
buttonText string:Assign;" buttonText string:Assign;"
style="padding-right:20px"> style="padding-right:20px">
<metal:assign use-macro="views/relation_macros/listing"> <metal:assign use-macro="views/relation_macros/listing">
@ -49,7 +52,15 @@
<option value="child" selected i18n:translate="">Child</option> <option value="child" selected i18n:translate="">Child</option>
<option value="parent" i18n:translate="">Parent</option> <option value="parent" i18n:translate="">Parent</option>
</select> </select>
object(s) Object(s) using Predicate
<select name="predicate">
<tal:types repeat="pred view/predicates">
<option value=".loops/concepts/hasType"
i18n:translate=""
tal:attributes="value pred/token"
tal:content="pred/title">Predicate</option>
</tal:types>
</select>
</metal:special> </metal:special>
</metal:assign> </metal:assign>
</div> </div>

View file

@ -418,6 +418,10 @@
for="loops.concept.ConceptTypeSourceList for="loops.concept.ConceptTypeSourceList
zope.publisher.interfaces.browser.IBrowserRequest" /> zope.publisher.interfaces.browser.IBrowserRequest" />
<zope:adapter factory="loops.browser.common.LoopsTerms"
for="loops.concept.PredicateSourceList
zope.publisher.interfaces.browser.IBrowserRequest" />
<zope:adapter factory="loops.browser.common.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" />

View file

@ -22,8 +22,9 @@
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th i18n:translate="label_title">Title</th> <th i18n:translate="label_title">Title</th>
<th i18n:translate="label_predicate">Predicate</th>
<th i18n:translate="label_type">Type</th> <th i18n:translate="label_type">Type</th>
<th i18n:translate="label_predicate"
tal:condition="showPredicate">Predicate</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -39,21 +40,19 @@
Title Title
</a> </a>
</td> </td>
<tal:relation condition="item/predicateTitle|nothing">
<td>
<a tal:content="item/predicateTitle" href="#"
tal:attributes="href
string:${item/predicateUrl}/@@SelectedManagementView.html">
Type
</a>
</td>
</tal:relation>
<td> <td>
<a tal:condition="item/typeTitle | nothing" <a tal:condition="item/typeTitle | nothing"
tal:content="item/typeTitle" href="#" tal:content="item/typeTitle" href="#"
tal:attributes="href tal:attributes="href
string:${item/typeUrl}/@@SelectedManagementView.html"> string:${item/typeUrl}/@@SelectedManagementView.html">
Title Type
</a>
</td>
<td tal:condition="showPredicate">
<a tal:content="item/predicateTitle" href="#"
tal:attributes="href
string:${item/predicateUrl}/@@SelectedManagementView.html">
Predicate
</a> </a>
</td> </td>
</tr> </tr>
@ -87,8 +86,13 @@
tal:attributes="value nothing" />&nbsp; tal:attributes="value nothing" />&nbsp;
<span i18n:translate="">Type</span> <span i18n:translate="">Type</span>
<select name="create.type"> <select name="create.type">
<option value=".loops/concepts/topic" <tal:types repeat="type view/conceptTypes">
i18n:translate="">Topic</option> <option value=".loops/concepts/topic"
i18n:translate=""
tal:attributes="value type/token"
tal:content="type/title">Topic</option>
</tal:types>
<option>None</option>
</select> </select>
</div><br /> </div><br />
<div class="formControls"> <div class="formControls">
@ -96,11 +100,20 @@
value="Create Object" value="Create Object"
i18n:attributes="value" i18n:attributes="value"
tal:attributes="value buttonText" /> tal:attributes="value buttonText" />
and assign as and assign as
<select name="assignAs"> <select name="assignAs">
<option value="child" selected i18n:translate="">Child</option> <option value="child" selected i18n:translate="">Child</option>
<option value="parent" i18n:translate="">Parent</option> <option value="parent" i18n:translate="">Parent</option>
</select> </select>
using Predicate
<select name="create.predicate">
<tal:types repeat="pred view/predicates">
<option value=".loops/concepts/hasType"
i18n:translate=""
tal:attributes="value pred/token"
tal:content="pred/title">Predicate</option>
</tal:types>
</select>
</div> </div>
</form> </form>
</fieldset> </fieldset>
@ -111,15 +124,23 @@
<form method="post" name="listing" action="." <form method="post" name="listing" action="."
tal:attributes="action request/URL"> tal:attributes="action request/URL">
<input type="hidden" name="action" value="search" /> <input type="hidden" name="action" value="search" />
<div class="row"> <div class="row"
tal:define="searchTerm request/searchTerm | nothing;
searchType request/searchType | nothing;">
<span i18n:translate="">Search Term</span> <span i18n:translate="">Search Term</span>
<input name="searchTerm" <input name="searchTerm"
tal:attributes="value request/searchTerm | nothing" /> tal:attributes="value searchTerm" />
<span i18n:translate="">Type</span> <span i18n:translate="">Type</span>
<select name="search.type"> <select name="searchType">
<option value="*">Any</option> <option value="*">Any</option>
<option value=".loops/concepts/topic" <tal:types repeat="type view/conceptTypes">
i18n:translate="">Topic</option> <option value=".loops/concepts/topic"
i18n:translate=""
tal:attributes="value type/token;
selected python: type.token == searchType"
tal:content="type/title">Topic</option>
</tal:types>
<option>None</option>
</select> </select>
</div> </div>
<div class="formControls"> <div class="formControls">

View file

@ -252,10 +252,9 @@ class ConceptTypeSourceList(object):
result = [] result = []
cm = self.concepts cm = self.concepts
typeObject = cm.getTypeConcept() typeObject = cm.getTypeConcept()
unknownType = self.concepts.get('unknown') unknownType = cm.get('unknown') # does this make sense?
if typeObject is not None: if typeObject is not None:
typeRelation = ConceptRelation(None, typeObject, cm.getTypePredicate()) types = typeObject.getChildren([cm.getTypePredicate()])
types = typeObject.getChildren((typeRelation,))
if typeObject not in types: if typeObject not in types:
result.append(typeObject) result.append(typeObject)
if unknownType is not None and unknownType not in types: if unknownType is not None and unknownType not in types:
@ -267,6 +266,36 @@ class ConceptTypeSourceList(object):
return len(self.conceptTypes) return len(self.conceptTypes)
class PredicateSourceList(object):
implements(schema.interfaces.IIterableSource)
def __init__(self, context):
self.context = context
self.concepts = self.context.getLoopsRoot().getConceptManager()
def __iter__(self):
return iter(self.predicates)
@Lazy
def predicates(self):
result = []
cm = self.concepts
defPred = cm.getDefaultPredicate()
typePred = cm.getTypePredicate()
if defPred is not None and typePred is not None:
result.append(defPred)
result.append(typePred)
predType = defPred.conceptType
if predType is not None and predType != cm.getTypeConcept():
result.extend(p for p in predType.getChildren([typePred])
if p not in result)
return result
def __len__(self):
return len(self.conceptTypes)
class SearchableText(object): class SearchableText(object):
implements(ISearchableText) implements(ISearchableText)

View file

@ -252,6 +252,11 @@
name="loops.conceptTypeSource" name="loops.conceptTypeSource"
/> />
<vocabulary
factory="loops.concept.PredicateSourceList"
name="loops.PredicateSource"
/>
<vocabulary <vocabulary
factory="loops.target.TargetSourceList" factory="loops.target.TargetSourceList"
name="loops.targetSource" name="loops.targetSource"