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:
helmutm 2006-02-12 15:38:29 +00:00
parent ef597268ec
commit 952cd7e9a8
9 changed files with 153 additions and 104 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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