Basic refactoring of concept stuff as preparation for user interface features
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1070 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
ef597268ec
commit
952cd7e9a8
9 changed files with 153 additions and 104 deletions
34
README.txt
34
README.txt
|
@ -48,30 +48,35 @@ testing we use a simple dummy implementation.
|
|||
>>> from zope.app.testing import ztapi
|
||||
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
|
||||
|
||||
Now we can assign the concept c2 to c1 (using the standard ConceptRelation):
|
||||
Now we can assign the concept c2 as a child to c1 (using the standard
|
||||
ConceptRelation):
|
||||
|
||||
>>> cc1.assignConcept(cc2)
|
||||
>>> cc1.assignChild(cc2)
|
||||
|
||||
We can now ask our concepts for their related concepts:
|
||||
We can now ask our concepts for their related child and parent concepts:
|
||||
|
||||
>>> sc1 = cc1.getSubConcepts()
|
||||
>>> sc1 = cc1.getChildren()
|
||||
>>> len(sc1)
|
||||
1
|
||||
>>> cc2 in sc1
|
||||
True
|
||||
>>> len(cc1.getParentConcepts())
|
||||
>>> len(cc1.getParents())
|
||||
0
|
||||
|
||||
>>> pc2 = cc2.getParentConcepts()
|
||||
>>> pc2 = cc2.getParents()
|
||||
>>> len(pc2)
|
||||
1
|
||||
|
||||
>>> cc1 in pc2
|
||||
True
|
||||
>>> len(cc2.getSubConcepts())
|
||||
>>> len(cc2.getChildren())
|
||||
0
|
||||
|
||||
TODO: Work with views...
|
||||
Concept Views
|
||||
-------------
|
||||
|
||||
>>> from loops.browser.concept import ConceptView
|
||||
>>> view = ConceptView(cc1, TestRequest())
|
||||
|
||||
|
||||
Resources and what they have to do with Concepts
|
||||
|
@ -147,12 +152,15 @@ Views/Nodes: Menus, Menu Items, Listings, Pages, etc
|
|||
====================================================
|
||||
|
||||
Note: the term "view" here is not directly related to the special
|
||||
Zop 3 term "view" (a multiadapter for presentation purposes) but basically
|
||||
Zope 3 term "view" (a multiadapter for presentation purposes) but basically
|
||||
bears the common sense meaning: an object (that may be persistent or
|
||||
created on the fly) that provides a view to content of whatever kind.
|
||||
|
||||
Views (or nodes - that's the only type of views existing at the moment)
|
||||
thus provide the presentation space to concepts and resources.
|
||||
thus provide the presentation space for concepts and resources, i.e. visitors
|
||||
of a site only see views or nodes but never concepts or resources directly;
|
||||
the views or nodes, however, present informations coming from the concepts
|
||||
or resources they are related to.
|
||||
|
||||
We first need a view manager:
|
||||
|
||||
|
@ -333,7 +341,7 @@ based on this source list:
|
|||
True
|
||||
|
||||
There is a special edit view class that can be used to configure a node
|
||||
in a way, that allows the creation of a target object on the fly.
|
||||
in a way that allows the creation of a target object on the fly.
|
||||
(We here use the base class providing the method for this action; the real
|
||||
application uses a subclass that does all the other stuff for form handling.)
|
||||
When creating a new target object you may specify a uri that determines
|
||||
|
@ -440,6 +448,10 @@ cybertools.relation package.)
|
|||
Ordering Nodes
|
||||
--------------
|
||||
|
||||
Note: this functionality has been moved to cybertools.container; we
|
||||
include some testing here to make sure it still works and give a short
|
||||
demonstration.
|
||||
|
||||
Let's add some more nodes and reorder them:
|
||||
|
||||
>>> m113 = Node()
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<div class="row">
|
||||
<span class="label">Sub-Concepts</span>:
|
||||
<span class="field"
|
||||
tal:repeat="concept view/subConcepts">
|
||||
tal:repeat="concept view/children">
|
||||
<a href="#"
|
||||
tal:attributes="href concept/url"
|
||||
tal:content="concept/title">subtask</a>
|
||||
|
@ -21,7 +21,7 @@
|
|||
<div class="row">
|
||||
<span class="label">Parent Concepts</span>:
|
||||
<span class="field"
|
||||
tal:repeat="concept view/parentConcepts">
|
||||
tal:repeat="concept view/parents">
|
||||
<a href="#"
|
||||
tal:attributes="href concept/url"
|
||||
tal:content="concept/title">subtask</a>
|
|
@ -24,13 +24,16 @@ $Id$
|
|||
|
||||
from zope.app import zapi
|
||||
from zope.app.dublincore.interfaces import ICMFDublinCore
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
from cybertools.relation import DyadicRelation
|
||||
|
||||
from loops.interfaces import IConcept
|
||||
class ConceptView(object):
|
||||
|
||||
class Details(object):
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
@Lazy
|
||||
def modified(self):
|
||||
""" get date/time of last modification
|
||||
"""
|
||||
|
@ -38,25 +41,28 @@ class Details(object):
|
|||
d = dc.modified or dc.created
|
||||
return d and d.strftime('%Y-%m-%d %H:%M') or ''
|
||||
|
||||
def subConcepts(self):
|
||||
return [{'object': c,
|
||||
'title': c.title,
|
||||
'url': zapi.absoluteURL(c, self.request)}
|
||||
for c in self.context.getSubConcepts()]
|
||||
@Lazy
|
||||
def url(self):
|
||||
return zapi.absoluteURL(self.context, self.request)
|
||||
|
||||
def parentConcepts(self):
|
||||
return [{'object': c,
|
||||
'title': c.title,
|
||||
'url': zapi.absoluteURL(c, self.request)}
|
||||
for c in self.context.getParentConcepts()]
|
||||
@Lazy
|
||||
def title(self):
|
||||
return self.context.title
|
||||
|
||||
def children(self):
|
||||
request = self.request
|
||||
for c in self.context.getChildren():
|
||||
yield ConceptView(c, request)
|
||||
|
||||
class ConceptRelations(Details):
|
||||
def parents(self):
|
||||
request = self.request
|
||||
for c in self.context.getParents():
|
||||
yield ConceptView(c, request)
|
||||
|
||||
def assignConcept(self, concept_name):
|
||||
""" Assign a concept denoted by the 'concept_name' request parameter.
|
||||
"""
|
||||
concept = zapi.getParent(self.context)[concept_name]
|
||||
self.context.assignConcept(removeSecurityProxy(concept))
|
||||
self.request.response.redirect(zapi.absoluteURL(self.context, self.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))
|
||||
return True
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<html metal:use-macro="views/standard_macros/view">
|
||||
<head>
|
||||
<style metal:fill-slot="style_slot">
|
||||
</style>
|
||||
</head>
|
||||
<tal:tag condition="view/update" />
|
||||
<html metal:use-macro="context/@@standard_macros/view"
|
||||
i18n:domain="zope">
|
||||
<body>
|
||||
|
||||
<div metal:fill-slot="body">
|
||||
|
||||
<h1 tal:content="context/title">Concept Title</h1>
|
||||
|
@ -11,28 +10,30 @@
|
|||
<div class="row">
|
||||
<span class="label">Sub-Concepts</span>:
|
||||
<span class="field"
|
||||
tal:repeat="concept context/getSubConcepts">
|
||||
tal:repeat="concept view/children">
|
||||
<span tal:condition="python: concept is None">**deleted**</span>
|
||||
<span tal:condition="python: concept is not None"
|
||||
tal:content="concept/title">subconcept</span>
|
||||
<a href="#"
|
||||
tal:attributes="href string:${concept/url}/children.html">
|
||||
<span tal:condition="python: concept is not None"
|
||||
tal:replace="concept/title">child</span>
|
||||
</a>
|
||||
<span class="field" tal:condition="not:repeat/concept/end"> - </span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="label">Parent Concepts</span>:
|
||||
<span class="field"
|
||||
tal:repeat="concept context/getParentConcepts">
|
||||
<span tal:content="concept/title">parent concept</span>
|
||||
tal:repeat="concept view/parents">
|
||||
<a href="#"
|
||||
tal:attributes="href string:${concept/url}/children.html">
|
||||
<span tal:replace="concept/title">parent</span>
|
||||
</a>
|
||||
<span class="field" tal:condition="not:repeat/concept/end"> - </span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="label">Last Modified</span>:
|
||||
<span class="field" tal:content="view/modified">2004-08-28</span>
|
||||
</div>
|
||||
|
||||
<form action="." method="post"
|
||||
tal:attributes="action context/@@absolute_url">
|
||||
tal:attributes="action request/URL">
|
||||
<div class="row">
|
||||
<span class="label">Concept Name</span>:
|
||||
<span class="field">
|
||||
|
@ -40,7 +41,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="submit" name="concept_assign:method" value="Assign Concept" />
|
||||
<input type="submit" name="concept_assign" value="Assign Concept" />
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -72,20 +72,6 @@
|
|||
|
||||
<!-- concept -->
|
||||
|
||||
<page
|
||||
name="details.html"
|
||||
for="loops.interfaces.IConcept"
|
||||
class=".concept.Details"
|
||||
template="concept_details.pt"
|
||||
permission="zope.View"
|
||||
menu="zmi_views" title="Details"
|
||||
/>
|
||||
|
||||
<defaultView
|
||||
for="loops.interfaces.IConcept"
|
||||
name="details.html"
|
||||
/>
|
||||
|
||||
<addform
|
||||
label="Add Concept"
|
||||
name="AddLoopsConcept.html"
|
||||
|
@ -114,22 +100,31 @@
|
|||
|
||||
<pages
|
||||
for="loops.interfaces.IConcept"
|
||||
class=".concept.ConceptRelations"
|
||||
class=".concept.ConceptView"
|
||||
permission="zope.ManageContent">
|
||||
|
||||
<page
|
||||
name="assign.html"
|
||||
template="concept_assign.pt"
|
||||
menu="zmi_views" title="Assign Concept"
|
||||
name="children.html"
|
||||
template="concept_children.pt"
|
||||
menu="zmi_views" title="Children"
|
||||
/>
|
||||
|
||||
<page
|
||||
name="concept_assign"
|
||||
attribute="assignConcept"
|
||||
/>
|
||||
|
||||
</pages>
|
||||
|
||||
<page
|
||||
name="concept.html"
|
||||
for="loops.interfaces.IConcept"
|
||||
class=".concept.ConceptView"
|
||||
template="concept.pt"
|
||||
permission="zope.View"
|
||||
menu="zmi_views" title="View"
|
||||
/>
|
||||
|
||||
<defaultView
|
||||
for="loops.interfaces.IConcept"
|
||||
name="concept.html"
|
||||
/>
|
||||
|
||||
<!-- resource manager -->
|
||||
|
||||
<addform
|
||||
|
@ -394,8 +389,14 @@
|
|||
template="node.pt"
|
||||
class=".node.NodeView"
|
||||
permission="zope.View"
|
||||
menu="zmi_views" title="View"
|
||||
/>
|
||||
|
||||
<defaultView
|
||||
for="loops.interfaces.INode"
|
||||
name="node.html"
|
||||
/>
|
||||
|
||||
<page
|
||||
name="target"
|
||||
for="loops.interfaces.INode"
|
||||
|
@ -404,11 +405,6 @@
|
|||
permission="zope.View"
|
||||
/>
|
||||
|
||||
<defaultView
|
||||
for="loops.interfaces.INode"
|
||||
name="node.html"
|
||||
/>
|
||||
|
||||
<!-- vocabulary, traversing, and other stuff -->
|
||||
|
||||
<zope:adapter factory="loops.browser.target.TargetTerms"
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
<tal:tag condition="view/update"/>
|
||||
<tal:tag condition="view/update" />
|
||||
<html metal:use-macro="context/@@standard_macros/view"
|
||||
i18n:domain="zope">
|
||||
i18n:domain="zope">
|
||||
|
||||
<head>
|
||||
<metal:js fill-slot="ecmascript_slot">
|
||||
<script type="text/javascript"
|
||||
src="node.js"
|
||||
tal:attributes="src string:${context/++resource++node.js}">
|
||||
</script>
|
||||
</metal:js>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<metal:js fill-slot="ecmascript_slot">
|
||||
<script type="text/javascript"
|
||||
src="node.js"
|
||||
tal:attributes="src string:${context/++resource++node.js}">
|
||||
</script>
|
||||
</metal:js>
|
||||
|
||||
|
||||
<div metal:fill-slot="body">
|
||||
|
||||
<div metal:define-macro="body">
|
||||
|
||||
<form action="." tal:attributes="action request/URL" method="post"
|
||||
|
|
16
concept.py
16
concept.py
|
@ -70,26 +70,29 @@ class Concept(Contained, Persistent):
|
|||
|
||||
# concept relations
|
||||
|
||||
def getSubConcepts(self, relationships=None):
|
||||
def getChildren(self, relationships=None):
|
||||
if relationships is None:
|
||||
relationships = [ConceptRelation]
|
||||
rels = getRelations(first=self, relationships=relationships)
|
||||
return [r.second for r in rels]
|
||||
# TODO: sort...
|
||||
|
||||
def getParentConcepts(self, relationships=None):
|
||||
def getParents(self, relationships=None):
|
||||
if relationships is None:
|
||||
relationships = [ConceptRelation]
|
||||
rels = getRelations(second=self, relationships=relationships)
|
||||
return [r.first for r in rels]
|
||||
|
||||
def assignConcept(self, concept, relationship=ConceptRelation):
|
||||
def assignChild(self, concept, relationship=ConceptRelation):
|
||||
registry = zapi.getUtility(IRelationRegistry)
|
||||
rel = relationship(self, concept)
|
||||
registry.register(rel)
|
||||
# TODO (?): avoid duplicates
|
||||
|
||||
def deassignConcept(self, concept, relationships=None):
|
||||
def assignParent(self, concept, relationship=ConceptRelation):
|
||||
concept.assignChild(self, relationship)
|
||||
|
||||
def deassignChildren(self, concept, relationships=None):
|
||||
if relationships is None:
|
||||
relationships = [ConceptRelation]
|
||||
registry = zapi.getUtility(IRelationRegistry)
|
||||
|
@ -98,6 +101,9 @@ class Concept(Contained, Persistent):
|
|||
for rel in relations:
|
||||
registry.unregister(relation)
|
||||
|
||||
def deassignParents(self, concept, relationships=None):
|
||||
concept.deassignChildren(self, relationships)
|
||||
|
||||
# resource relations
|
||||
|
||||
def getResources(self, relationships=None):
|
||||
|
@ -133,6 +139,4 @@ class ConceptManager(BTreeContainer):
|
|||
|
||||
def getViewManager(self):
|
||||
return self.getLoopsRoot().getViewManager()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -71,28 +71,40 @@ class IConcept(ILoopsObject, IPotentialTarget):
|
|||
default=u'',
|
||||
required=False)
|
||||
|
||||
def getSubConcepts(relationships=None):
|
||||
""" Return a sequence of concepts related to self as sub-concepts,
|
||||
def getChildren(relationships=None):
|
||||
""" Return a sequence of concepts related to self as child concepts,
|
||||
possibly restricted to the relationships (typically a list of
|
||||
relation classes) given.
|
||||
"""
|
||||
|
||||
def getParentConcepts(relationships=None):
|
||||
def getParents(relationships=None):
|
||||
""" Return a tuple of concepts related to self as parent concepts,
|
||||
possibly restricted to the relationships (typically a list of
|
||||
relation classes) given.
|
||||
"""
|
||||
|
||||
def assignConcept(concept, relationship):
|
||||
def assignChild(concept, relationship):
|
||||
""" Assign an existing concept to self using the relationship given.
|
||||
The assigned concept will be a sub-concept of self.
|
||||
The assigned concept will be a child concept of self.
|
||||
|
||||
The relationship defaults to ConceptRelation.
|
||||
"""
|
||||
|
||||
def deassignConcept(concept, relationships=None):
|
||||
""" Remove the relations to the concept given from self, optionally
|
||||
restricting them to the relationships given.
|
||||
def assignParent(concept, relationship):
|
||||
""" Assign an existing concept to self using the relationship given.
|
||||
The assigned concept will be a parent concept of self.
|
||||
|
||||
The relationship defaults to ConceptRelation.
|
||||
"""
|
||||
|
||||
def deassignChildren(concept, relationships=None):
|
||||
""" Remove the child concept relations to the concept given from self,
|
||||
optionally restricting them to the relationships given.
|
||||
"""
|
||||
|
||||
def deassignParents(concept, relationships=None):
|
||||
""" Remove the child concept relations to the concept given from self,
|
||||
optionally restricting them to the relationships given.
|
||||
"""
|
||||
|
||||
def getResources(relationships=None):
|
||||
|
|
21
target.py
21
target.py
|
@ -108,16 +108,33 @@ class TargetSourceList(object):
|
|||
implements(schema.interfaces.IIterableSource)
|
||||
|
||||
def __init__(self, context):
|
||||
#self.context = context
|
||||
self.context = removeSecurityProxy(context)
|
||||
root = self.context.getLoopsRoot()
|
||||
self.resources = root.getResourceManager()
|
||||
self.concepts = root.getConceptManager()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(list(self.resources.values()) + list(self.concepts.values()))
|
||||
for obj in self.resources.values():
|
||||
yield obj
|
||||
for obj in self.concepts.values():
|
||||
yield obj
|
||||
#return iter(list(self.resources.values()) + list(self.concepts.values()))
|
||||
|
||||
def __len__(self):
|
||||
return len(self.resources) + len(self.concepts)
|
||||
|
||||
|
||||
|
||||
class QueryableTargetSource(object):
|
||||
|
||||
implements(schema.interfaces.ISource)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
root = self.context.getLoopsRoot()
|
||||
self.resources = root.getResourceManager()
|
||||
self.concepts = root.getConceptManager()
|
||||
|
||||
def __contains__(self, value):
|
||||
return value in self.resources.values() or value in self.concepts.values()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue