Now concepts may have a type, and the types are concepts themselves, with the 'type' concept on top
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1081 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
da52ecc17c
commit
19e4431cfb
8 changed files with 255 additions and 70 deletions
61
README.txt
61
README.txt
|
@ -72,6 +72,33 @@ We can now ask our concepts for their related child and parent concepts:
|
||||||
>>> len(cc2.getChildren())
|
>>> len(cc2.getChildren())
|
||||||
0
|
0
|
||||||
|
|
||||||
|
Each concept should have a concept type; this is in fact provided by a
|
||||||
|
relation to a special kind of concept object with the magic name 'type'.
|
||||||
|
This type object is its own type:
|
||||||
|
|
||||||
|
>>> concepts['type'] = Concept(u'Type')
|
||||||
|
>>> typeObject = concepts['type']
|
||||||
|
>>> typeObject.setConceptType(typeObject)
|
||||||
|
>>> typeObject.getConceptType().title
|
||||||
|
u'Type'
|
||||||
|
|
||||||
|
>>> concepts['unknown'] = Concept(u'Unknown Type')
|
||||||
|
>>> unknown = concepts['unknown']
|
||||||
|
>>> unknown.setConceptType(typeObject)
|
||||||
|
>>> unknown.getConceptType().title
|
||||||
|
u'Type'
|
||||||
|
|
||||||
|
>>> cc1.setConceptType(unknown)
|
||||||
|
>>> cc1.getConceptType().title
|
||||||
|
u'Unknown Type'
|
||||||
|
|
||||||
|
>>> concepts['topic'] = Concept(u'Topic')
|
||||||
|
>>> topic = concepts['topic']
|
||||||
|
>>> topic.setConceptType(typeObject)
|
||||||
|
>>> cc1.setConceptType(topic)
|
||||||
|
>>> cc1.getConceptType().title
|
||||||
|
u'Topic'
|
||||||
|
|
||||||
Concept Views
|
Concept Views
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -84,18 +111,6 @@ Concept Views
|
||||||
The concept view allows to get a list of terms (sort of vocabulary) that
|
The concept view allows to get a list of terms (sort of vocabulary) that
|
||||||
can be used to show the objects in a listing:
|
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 cc1
|
|
||||||
.loops/concepts/cc2 Zope 3
|
|
||||||
|
|
||||||
The concept view allows updating the underlying context object:
|
The concept view allows updating the underlying context object:
|
||||||
|
|
||||||
>>> cc3 = Concept(u'loops for Zope 3')
|
>>> cc3 = Concept(u'loops for Zope 3')
|
||||||
|
@ -115,6 +130,23 @@ The concept view allows updating the underlying context object:
|
||||||
>>> sorted(c.title for c in cc1.getChildren())
|
>>> sorted(c.title for c in cc1.getChildren())
|
||||||
[u'loops for Zope 3']
|
[u'loops for Zope 3']
|
||||||
|
|
||||||
|
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.update()
|
||||||
|
True
|
||||||
|
>>> sorted(c.title for c in cc1.getChildren())
|
||||||
|
[u'New concept', u'loops for Zope 3']
|
||||||
|
|
||||||
|
Searchable Text Adapter
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
>>> from loops.concept import SearchableText
|
||||||
|
>>> SearchableText(cc2).searchableText()
|
||||||
|
u'cc2 Zope 3'
|
||||||
|
|
||||||
Resources and what they have to do with Concepts
|
Resources and what they have to do with Concepts
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
|
@ -356,9 +388,9 @@ 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)
|
||||||
4
|
8
|
||||||
>>> sorted([zapi.getName(s) for s in source])
|
>>> sorted([zapi.getName(s) for s in source])
|
||||||
[u'cc1', u'cc2', u'cc3', u'doc1']
|
[u'cc1', u'cc2', u'cc3', u'cc4', u'doc1', u'topic', u'type', u'unknown']
|
||||||
|
|
||||||
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:
|
||||||
|
@ -428,6 +460,7 @@ 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,
|
||||||
|
|
|
@ -23,6 +23,7 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.app.dublincore.interfaces import ICMFDublinCore
|
from zope.app.dublincore.interfaces import ICMFDublinCore
|
||||||
from zope.app.form.browser.interfaces import ITerms
|
from zope.app.form.browser.interfaces import ITerms
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
@ -30,26 +31,32 @@ from zope.interface import implements
|
||||||
from zope.publisher.interfaces import BadRequest
|
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.concept import ConceptSourceList
|
from loops.concept import Concept
|
||||||
from loops.browser.common import BaseView, LoopsTerms
|
from loops.browser.common import BaseView, LoopsTerms
|
||||||
|
|
||||||
|
|
||||||
class ConceptView(BaseView):
|
class ConceptView(BaseView):
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
request = self.request
|
ch = self.context.getChildren()
|
||||||
for c in self.context.getChildren():
|
return ch and self.viewIterator(ch) or []
|
||||||
yield ConceptView(c, request)
|
|
||||||
|
|
||||||
def parents(self):
|
def parents(self):
|
||||||
|
p = self.context.getParents()
|
||||||
|
return p and self.viewIterator(p) or []
|
||||||
|
|
||||||
|
def viewIterator(self, objs):
|
||||||
request = self.request
|
request = self.request
|
||||||
for c in self.context.getParents():
|
for o in objs:
|
||||||
yield ConceptView(c, request)
|
yield ConceptView(o, request)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
action = self.request.get('action', None)
|
action = self.request.get('action')
|
||||||
if action is None:
|
if action is None:
|
||||||
return True
|
return True
|
||||||
|
if action == 'create':
|
||||||
|
self.createAndAssign()
|
||||||
|
return True
|
||||||
tokens = self.request.get('tokens', [])
|
tokens = self.request.get('tokens', [])
|
||||||
for token in tokens:
|
for token in tokens:
|
||||||
concept = self.loopsRoot.loopsTraverse(token)
|
concept = self.loopsRoot.loopsTraverse(token)
|
||||||
|
@ -62,7 +69,7 @@ class ConceptView(BaseView):
|
||||||
else:
|
else:
|
||||||
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
|
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
|
||||||
elif action == 'remove':
|
elif action == 'remove':
|
||||||
qualifier = self.request.get('qualifier', None)
|
qualifier = self.request.get('qualifier')
|
||||||
if qualifier == 'parents':
|
if qualifier == 'parents':
|
||||||
self.context.deassignParents(concept)
|
self.context.deassignParents(concept)
|
||||||
elif qualifier == 'children':
|
elif qualifier == 'children':
|
||||||
|
@ -73,9 +80,39 @@ class ConceptView(BaseView):
|
||||||
raise(BadRequest, 'Illegal action: %s.' % action)
|
raise(BadRequest, 'Illegal action: %s.' % action)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getVocabularyForRelated(self):
|
def createAndAssign(self):
|
||||||
source = ConceptSourceList(self.context)
|
request = self.request
|
||||||
terms = zapi.getMultiAdapter((source, self.request), ITerms)
|
name = request.get('create.name')
|
||||||
for candidate in source:
|
if not name:
|
||||||
yield terms.getTerm(candidate)
|
raise(BadRequest, 'Empty name.')
|
||||||
|
title = request.get('create.title', u'')
|
||||||
|
type = request.get('create.type')
|
||||||
|
concept = Concept(title)
|
||||||
|
container = self.loopsRoot.getConceptManager()
|
||||||
|
container[name] = concept
|
||||||
|
assignAs = self.request.get('assignAs', 'child')
|
||||||
|
if assignAs == 'child':
|
||||||
|
self.context.assignChild(removeSecurityProxy(concept))
|
||||||
|
elif assignAs == 'parent':
|
||||||
|
self.context.assignParent(removeSecurityProxy(concept))
|
||||||
|
else:
|
||||||
|
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
|
||||||
|
|
||||||
|
#def getVocabularyForRelated(self): # obsolete
|
||||||
|
# source = ConceptSourceList(self.context)
|
||||||
|
# terms = zapi.getMultiAdapter((source, self.request), ITerms)
|
||||||
|
# for candidate in source:
|
||||||
|
# yield terms.getTerm(candidate)
|
||||||
|
|
||||||
|
def search(self):
|
||||||
|
request = self.request
|
||||||
|
if request.get('action') != 'search':
|
||||||
|
return []
|
||||||
|
searchTerm = request.get('searchTerm', None)
|
||||||
|
if searchTerm:
|
||||||
|
cat = zapi.getUtility(ICatalog)
|
||||||
|
result = cat.searchResults(loops_searchableText=searchTerm)
|
||||||
|
else:
|
||||||
|
result = self.loopsRoot.getConceptManager().values()
|
||||||
|
return self.viewIterator(result)
|
||||||
|
|
||||||
|
|
|
@ -7,36 +7,38 @@
|
||||||
|
|
||||||
<h1 tal:content="context/title">Concept Title</h1><br />
|
<h1 tal:content="context/title">Concept Title</h1><br />
|
||||||
|
|
||||||
<tal:block define="items view/parents;
|
<div tal:define="items view/parents;
|
||||||
action string:remove;
|
action string:remove;
|
||||||
qualifier string:parents;
|
qualifier string:parents;
|
||||||
summary string:Currently assigned objects;
|
summary string:Currently assigned objects;
|
||||||
legend string:Parent Concepts;
|
legend string:Parent Concepts;
|
||||||
buttonText string:Remove Assignment(s);
|
buttonText string:Remove Parents;"
|
||||||
">
|
style="float:left; padding-right:20px">
|
||||||
<metal:parents use-macro="views/relation_macros/listing" />
|
<metal:parents use-macro="views/relation_macros/listing" />
|
||||||
</tal:block>
|
</div>
|
||||||
<tal:block define="items view/children;
|
<div tal:define="items view/children;
|
||||||
action string:remove;
|
action string:remove;
|
||||||
qualifier string:children;
|
qualifier string:children;
|
||||||
summary string:Currently assigned objects;
|
summary string:Currently assigned objects;
|
||||||
legend string:Child Concepts;
|
legend string:Child Concepts;
|
||||||
buttonText string:Remove Assignment(s);
|
buttonText string:Remove Children;"
|
||||||
">
|
style="padding-right:20px">
|
||||||
<metal:children use-macro="views/relation_macros/listing" />
|
<metal:children use-macro="views/relation_macros/listing" />
|
||||||
</tal:block>
|
</div>
|
||||||
|
|
||||||
<tal:block>
|
<div tal:define="legend string:Create Concept;
|
||||||
|
buttonText string:Create Concept"
|
||||||
|
style="padding-right:20px; clear:left">
|
||||||
<metal:create use-macro="views/relation_macros/create" />
|
<metal:create use-macro="views/relation_macros/create" />
|
||||||
</tal:block>
|
</div>
|
||||||
|
|
||||||
<tal:block define="items view/getVocabularyForRelated;
|
<div tal:define="items view/search;
|
||||||
action string:assign;
|
action string:assign;
|
||||||
qualifier nothing;
|
qualifier nothing;
|
||||||
summary string:Assignment candidates;
|
summary string:Assignment candidates;
|
||||||
legend string:Search Results;
|
legend string:Search;
|
||||||
buttonText string:Assign;
|
buttonText string:Assign;"
|
||||||
">
|
style="padding-right:20px">
|
||||||
<metal:assign use-macro="views/relation_macros/listing">
|
<metal:assign use-macro="views/relation_macros/listing">
|
||||||
<metal:search fill-slot="topActions">
|
<metal:search fill-slot="topActions">
|
||||||
<metal:block use-macro="views/relation_macros/search" />
|
<metal:block use-macro="views/relation_macros/search" />
|
||||||
|
@ -44,13 +46,13 @@
|
||||||
<metal:special fill-slot="specialButtons">
|
<metal:special fill-slot="specialButtons">
|
||||||
as
|
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>
|
||||||
object(s)
|
object(s)
|
||||||
</metal:special>
|
</metal:special>
|
||||||
</metal:assign>
|
</metal:assign>
|
||||||
</tal:block>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -415,11 +415,11 @@
|
||||||
<!-- vocabulary, traversing, and other stuff -->
|
<!-- vocabulary, traversing, and other stuff -->
|
||||||
|
|
||||||
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
||||||
for="loops.target.TargetSourceList
|
for="loops.concept.ConceptTypeSourceList
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest" />
|
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||||
|
|
||||||
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
<zope:adapter factory="loops.browser.common.LoopsTerms"
|
||||||
for="loops.concept.ConceptSourceList
|
for="loops.target.TargetSourceList
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest" />
|
zope.publisher.interfaces.browser.IBrowserRequest" />
|
||||||
|
|
||||||
<zope:view factory="loops.view.NodeTraverser"
|
<zope:view factory="loops.view.NodeTraverser"
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
<metal:assignments define-macro="listing">
|
<metal:assignments define-macro="listing">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend tal:content="legend"
|
<legend tal:content="legend"
|
||||||
i18n:translate="">Parent Concepts</legend>
|
i18n:translate="">Listing</legend>
|
||||||
<metal:top define-slot="topActions" />
|
<metal:top define-slot="topActions" />
|
||||||
<form method="post" name="listing" action="."
|
<form metal:define-macro="listing_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"
|
||||||
|
@ -53,27 +54,33 @@
|
||||||
|
|
||||||
<metal:create define-macro="create">
|
<metal:create define-macro="create">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend i18n:translate="">Create Object</legend>
|
<legend tal:content="legend"
|
||||||
|
i18n:translate="">Create Object</legend>
|
||||||
<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="create" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span i18n:translate="">Name</span>
|
<span i18n:translate="">Name</span>
|
||||||
<input />
|
<input name="create.name" size="15"
|
||||||
|
tal:attributes="value nothing" />
|
||||||
<span i18n:translate="">Title</span>
|
<span i18n:translate="">Title</span>
|
||||||
<input />
|
<input name="create.title" size="30"
|
||||||
|
tal:attributes="value nothing" />
|
||||||
<span i18n:translate="">Type</span>
|
<span i18n:translate="">Type</span>
|
||||||
<select>
|
<select name="create.type">
|
||||||
<option>Topic</option>
|
<option value=".loops/concepts/topic"
|
||||||
|
i18n:translate="">Topic</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div><br />
|
||||||
<div class="formControls">
|
<div class="formControls">
|
||||||
<input class="context" type="submit" name="form.button.submit"
|
<input class="context" type="submit" name="form.button.submit"
|
||||||
value="Create Object"
|
value="Create Object"
|
||||||
i18n:attributes="value" />
|
i18n:attributes="value"
|
||||||
|
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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -84,9 +91,17 @@
|
||||||
<metal:search define-macro="search">
|
<metal:search define-macro="search">
|
||||||
<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" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span i18n:translate="">Search Term</span>
|
<span i18n:translate="">Search Term</span>
|
||||||
<input />
|
<input name="searchTerm"
|
||||||
|
tal:attributes="value request/searchTerm | nothing" />
|
||||||
|
<span i18n:translate="">Type</span>
|
||||||
|
<select name="search.type">
|
||||||
|
<option value="*">Any</option>
|
||||||
|
<option value=".loops/concepts/topic"
|
||||||
|
i18n:translate="">Topic</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="formControls">
|
<div class="formControls">
|
||||||
<input class="context" type="submit" name="form.button.submit"
|
<input class="context" type="submit" name="form.button.submit"
|
||||||
|
|
66
concept.py
66
concept.py
|
@ -25,6 +25,8 @@ $Id$
|
||||||
from zope.app import zapi
|
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.cachedescriptors.property import Lazy
|
||||||
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from zope import schema
|
from zope import schema
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
|
@ -32,11 +34,13 @@ from persistent import Persistent
|
||||||
|
|
||||||
from cybertools.relation import DyadicRelation
|
from cybertools.relation import DyadicRelation
|
||||||
from cybertools.relation.registry import getRelations
|
from cybertools.relation.registry import getRelations
|
||||||
|
from cybertools.relation.registry import getRelationSingle, setRelationSingle
|
||||||
from cybertools.relation.interfaces import IRelationRegistry
|
from cybertools.relation.interfaces import IRelationRegistry
|
||||||
|
|
||||||
from interfaces import IConcept, IConceptView
|
from interfaces import IConcept, IConceptRelation, IConceptView
|
||||||
from interfaces import IConceptManager, IConceptManagerContained
|
from interfaces import IConceptManager, IConceptManagerContained
|
||||||
from interfaces import ILoopsContained
|
from interfaces import ILoopsContained
|
||||||
|
from interfaces import ISearchableText
|
||||||
|
|
||||||
|
|
||||||
# relation classes
|
# relation classes
|
||||||
|
@ -44,11 +48,20 @@ from interfaces import ILoopsContained
|
||||||
class ConceptRelation(DyadicRelation):
|
class ConceptRelation(DyadicRelation):
|
||||||
""" A relation between concept objects.
|
""" A relation between concept objects.
|
||||||
"""
|
"""
|
||||||
|
implements(IConceptRelation)
|
||||||
|
|
||||||
|
|
||||||
|
class TypeRelation(DyadicRelation):
|
||||||
|
""" A special relation between two concepts, the parent specifying
|
||||||
|
the type of the child.
|
||||||
|
"""
|
||||||
|
implements(IConceptRelation)
|
||||||
|
|
||||||
|
|
||||||
class ResourceRelation(DyadicRelation):
|
class ResourceRelation(DyadicRelation):
|
||||||
""" A relation between a concept and a resource object.
|
""" A relation between a concept and a resource object.
|
||||||
"""
|
"""
|
||||||
|
implements(IConceptRelation)
|
||||||
|
|
||||||
|
|
||||||
# concept
|
# concept
|
||||||
|
@ -64,6 +77,14 @@ class Concept(Contained, Persistent):
|
||||||
def setTitle(self, title): self._title = title
|
def setTitle(self, title): self._title = title
|
||||||
title = property(getTitle, setTitle)
|
title = property(getTitle, setTitle)
|
||||||
|
|
||||||
|
def getConceptType(self):
|
||||||
|
rel = getRelationSingle(self, TypeRelation)
|
||||||
|
return rel and rel.second or None
|
||||||
|
def setConceptType(self, concept):
|
||||||
|
if self.getConceptType() != concept:
|
||||||
|
setRelationSingle(TypeRelation(self, removeSecurityProxy(concept)))
|
||||||
|
conceptType = property(getConceptType, setConceptType)
|
||||||
|
|
||||||
def __init__(self, title=u''):
|
def __init__(self, title=u''):
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
|
@ -165,3 +186,46 @@ class ConceptSourceList(object):
|
||||||
return len(self.concepts)
|
return len(self.concepts)
|
||||||
|
|
||||||
|
|
||||||
|
class ConceptTypeSourceList(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):
|
||||||
|
return iter(self.conceptTypes)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def conceptTypes(self):
|
||||||
|
result = []
|
||||||
|
typeObject = self.concepts.get('type')
|
||||||
|
unknownType = self.concepts.get('unknown')
|
||||||
|
if typeObject is not None:
|
||||||
|
types = typeObject.getParents((TypeRelation,))
|
||||||
|
if typeObject not in types:
|
||||||
|
result.append(typeObject)
|
||||||
|
if unknownType is not None and unknownType not in types:
|
||||||
|
result.append(unknownType)
|
||||||
|
result.extend(types)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.conceptTypes)
|
||||||
|
|
||||||
|
|
||||||
|
class SearchableText(object):
|
||||||
|
|
||||||
|
implements(ISearchableText)
|
||||||
|
adapts(IConcept)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def searchableText(self):
|
||||||
|
context = self.context
|
||||||
|
return ' '.join((zapi.getName(context), context.title,))
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<require
|
<require
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
attributes="getLoopsUri loopsTraverse" />
|
attributes="getLoopsUri loopsTraverse getConceptManager" />
|
||||||
|
|
||||||
</content>
|
</content>
|
||||||
|
|
||||||
|
@ -227,6 +227,8 @@
|
||||||
|
|
||||||
<!-- adapters -->
|
<!-- adapters -->
|
||||||
|
|
||||||
|
<adapter factory="loops.concept.SearchableText" />
|
||||||
|
|
||||||
<adapter factory="loops.external.NodesLoader" />
|
<adapter factory="loops.external.NodesLoader" />
|
||||||
<adapter factory="loops.external.NodesExporter" />
|
<adapter factory="loops.external.NodesExporter" />
|
||||||
<adapter factory="loops.external.NodesImporter" />
|
<adapter factory="loops.external.NodesImporter" />
|
||||||
|
@ -241,6 +243,11 @@
|
||||||
<adapter factory="loops.target.ConceptProxy"
|
<adapter factory="loops.target.ConceptProxy"
|
||||||
permission="zope.ManageContent" />
|
permission="zope.ManageContent" />
|
||||||
|
|
||||||
|
<vocabulary
|
||||||
|
factory="loops.concept.ConceptTypeSourceList"
|
||||||
|
name="loops.conceptTypeSource"
|
||||||
|
/>
|
||||||
|
|
||||||
<vocabulary
|
<vocabulary
|
||||||
factory="loops.target.TargetSourceList"
|
factory="loops.target.TargetSourceList"
|
||||||
name="loops.targetSource"
|
name="loops.targetSource"
|
||||||
|
|
|
@ -71,6 +71,14 @@ class IConcept(ILoopsObject, IPotentialTarget):
|
||||||
default=u'',
|
default=u'',
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
conceptType = schema.Choice(
|
||||||
|
title=_(u'Concept Type'),
|
||||||
|
description=_(u"The type of the concept, specified by a relation to "
|
||||||
|
"a concept of type 'type'."),
|
||||||
|
default=None,
|
||||||
|
source="loops.conceptTypeSource",
|
||||||
|
required=False)
|
||||||
|
|
||||||
def getChildren(relationships=None):
|
def getChildren(relationships=None):
|
||||||
""" Return a sequence of concepts related to self as child concepts,
|
""" Return a sequence of concepts related to self as child concepts,
|
||||||
possibly restricted to the relationships (typically a list of
|
possibly restricted to the relationships (typically a list of
|
||||||
|
@ -371,12 +379,6 @@ class INodeConfigSchema(INode, ITargetProperties):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
class ITargetRelation(IRelation):
|
|
||||||
""" (Marker) interfaces for relations pointing to a target
|
|
||||||
of a view or node.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# the loops top-level container
|
# the loops top-level container
|
||||||
|
|
||||||
#class ILoops(ILoopsObject, IFolder):
|
#class ILoops(ILoopsObject, IFolder):
|
||||||
|
@ -410,3 +412,28 @@ class ILoops(ILoopsObject):
|
||||||
class ILoopsContained(Interface):
|
class ILoopsContained(Interface):
|
||||||
containers(ILoops)
|
containers(ILoops)
|
||||||
|
|
||||||
|
|
||||||
|
# relation interfaces
|
||||||
|
|
||||||
|
class ITargetRelation(IRelation):
|
||||||
|
""" (Marker) interfaces for relations pointing to a target
|
||||||
|
of a view or node.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IConceptRelation(IRelation):
|
||||||
|
""" (Marker) interfaces for relations originating from a concept.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# interfaces for catalog indexes
|
||||||
|
|
||||||
|
class ISearchableText(Interface):
|
||||||
|
""" Objects to be included in the general full-text index should provide
|
||||||
|
or be adaptable to this interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def searchableText():
|
||||||
|
""" Return a text with all parts to be indexed by a full-text index.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue