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 >>> from zope.app.testing import ztapi
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry()) >>> 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) >>> len(sc1)
1 1
>>> cc2 in sc1 >>> cc2 in sc1
True True
>>> len(cc1.getParentConcepts()) >>> len(cc1.getParents())
0 0
>>> pc2 = cc2.getParentConcepts() >>> pc2 = cc2.getParents()
>>> len(pc2) >>> len(pc2)
1 1
>>> cc1 in pc2 >>> cc1 in pc2
True True
>>> len(cc2.getSubConcepts()) >>> len(cc2.getChildren())
0 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 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 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 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. 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) 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: We first need a view manager:
@ -333,7 +341,7 @@ based on this source list:
True True
There is a special edit view class that can be used to configure a node 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 (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.) 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 When creating a new target object you may specify a uri that determines
@ -440,6 +448,10 @@ cybertools.relation package.)
Ordering Nodes 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: Let's add some more nodes and reorder them:
>>> m113 = Node() >>> m113 = Node()

View file

@ -11,7 +11,7 @@
<div class="row"> <div class="row">
<span class="label">Sub-Concepts</span>: <span class="label">Sub-Concepts</span>:
<span class="field" <span class="field"
tal:repeat="concept view/subConcepts"> tal:repeat="concept view/children">
<a href="#" <a href="#"
tal:attributes="href concept/url" tal:attributes="href concept/url"
tal:content="concept/title">subtask</a> tal:content="concept/title">subtask</a>
@ -21,7 +21,7 @@
<div class="row"> <div class="row">
<span class="label">Parent Concepts</span>: <span class="label">Parent Concepts</span>:
<span class="field" <span class="field"
tal:repeat="concept view/parentConcepts"> tal:repeat="concept view/parents">
<a href="#" <a href="#"
tal:attributes="href concept/url" tal:attributes="href concept/url"
tal:content="concept/title">subtask</a> tal:content="concept/title">subtask</a>

View file

@ -24,13 +24,16 @@ $Id$
from zope.app import zapi from zope.app import zapi
from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.cachedescriptors.property import Lazy
from zope.security.proxy import removeSecurityProxy 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): def modified(self):
""" get date/time of last modification """ get date/time of last modification
""" """
@ -38,25 +41,28 @@ class Details(object):
d = dc.modified or dc.created d = dc.modified or dc.created
return d and d.strftime('%Y-%m-%d %H:%M') or '' return d and d.strftime('%Y-%m-%d %H:%M') or ''
def subConcepts(self): @Lazy
return [{'object': c, def url(self):
'title': c.title, return zapi.absoluteURL(self.context, self.request)
'url': zapi.absoluteURL(c, self.request)}
for c in self.context.getSubConcepts()]
def parentConcepts(self): @Lazy
return [{'object': c, def title(self):
'title': c.title, return self.context.title
'url': zapi.absoluteURL(c, self.request)}
for c in self.context.getParentConcepts()]
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): def update(self):
""" Assign a concept denoted by the 'concept_name' request parameter. concept_name = self.request.get('concept_name', None)
""" if concept_name:
concept = zapi.getParent(self.context)[concept_name] concept = zapi.getParent(self.context)[concept_name]
self.context.assignConcept(removeSecurityProxy(concept)) self.context.assignChild(removeSecurityProxy(concept))
self.request.response.redirect(zapi.absoluteURL(self.context, self.request)) return True

View file

@ -1,9 +1,8 @@
<html metal:use-macro="views/standard_macros/view"> <tal:tag condition="view/update" />
<head> <html metal:use-macro="context/@@standard_macros/view"
<style metal:fill-slot="style_slot"> i18n:domain="zope">
</style>
</head>
<body> <body>
<div metal:fill-slot="body"> <div metal:fill-slot="body">
<h1 tal:content="context/title">Concept Title</h1> <h1 tal:content="context/title">Concept Title</h1>
@ -11,28 +10,30 @@
<div class="row"> <div class="row">
<span class="label">Sub-Concepts</span>: <span class="label">Sub-Concepts</span>:
<span class="field" <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 None">**deleted**</span>
<a href="#"
tal:attributes="href string:${concept/url}/children.html">
<span tal:condition="python: concept is not None" <span tal:condition="python: concept is not None"
tal:content="concept/title">subconcept</span> tal:replace="concept/title">child</span>
</a>
<span class="field" tal:condition="not:repeat/concept/end"> - </span> <span class="field" tal:condition="not:repeat/concept/end"> - </span>
</span> </span>
</div> </div>
<div class="row"> <div class="row">
<span class="label">Parent Concepts</span>: <span class="label">Parent Concepts</span>:
<span class="field" <span class="field"
tal:repeat="concept context/getParentConcepts"> tal:repeat="concept view/parents">
<span tal:content="concept/title">parent concept</span> <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 class="field" tal:condition="not:repeat/concept/end"> - </span>
</span> </span>
</div> </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" <form action="." method="post"
tal:attributes="action context/@@absolute_url"> tal:attributes="action request/URL">
<div class="row"> <div class="row">
<span class="label">Concept Name</span>: <span class="label">Concept Name</span>:
<span class="field"> <span class="field">
@ -40,7 +41,7 @@
</span> </span>
</div> </div>
<div class="row"> <div class="row">
<input type="submit" name="concept_assign:method" value="Assign Concept" /> <input type="submit" name="concept_assign" value="Assign Concept" />
</div> </div>
</form> </form>

View file

@ -72,20 +72,6 @@
<!-- concept --> <!-- 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 <addform
label="Add Concept" label="Add Concept"
name="AddLoopsConcept.html" name="AddLoopsConcept.html"
@ -114,22 +100,31 @@
<pages <pages
for="loops.interfaces.IConcept" for="loops.interfaces.IConcept"
class=".concept.ConceptRelations" class=".concept.ConceptView"
permission="zope.ManageContent"> permission="zope.ManageContent">
<page <page
name="assign.html" name="children.html"
template="concept_assign.pt" template="concept_children.pt"
menu="zmi_views" title="Assign Concept" menu="zmi_views" title="Children"
/>
<page
name="concept_assign"
attribute="assignConcept"
/> />
</pages> </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 --> <!-- resource manager -->
<addform <addform
@ -394,6 +389,12 @@
template="node.pt" template="node.pt"
class=".node.NodeView" class=".node.NodeView"
permission="zope.View" permission="zope.View"
menu="zmi_views" title="View"
/>
<defaultView
for="loops.interfaces.INode"
name="node.html"
/> />
<page <page
@ -404,11 +405,6 @@
permission="zope.View" permission="zope.View"
/> />
<defaultView
for="loops.interfaces.INode"
name="node.html"
/>
<!-- vocabulary, traversing, and other stuff --> <!-- vocabulary, traversing, and other stuff -->
<zope:adapter factory="loops.browser.target.TargetTerms" <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" <html metal:use-macro="context/@@standard_macros/view"
i18n:domain="zope"> i18n:domain="zope">
<body>
<head>
<metal:js fill-slot="ecmascript_slot"> <metal:js fill-slot="ecmascript_slot">
<script type="text/javascript" <script type="text/javascript"
src="node.js" src="node.js"
tal:attributes="src string:${context/++resource++node.js}"> tal:attributes="src string:${context/++resource++node.js}">
</script> </script>
</metal:js> </metal:js>
</head>
<body>
<div metal:fill-slot="body"> <div metal:fill-slot="body">
<div metal:define-macro="body"> <div metal:define-macro="body">
<form action="." tal:attributes="action request/URL" method="post" <form action="." tal:attributes="action request/URL" method="post"

View file

@ -70,26 +70,29 @@ class Concept(Contained, Persistent):
# concept relations # concept relations
def getSubConcepts(self, relationships=None): def getChildren(self, relationships=None):
if relationships is None: if relationships is None:
relationships = [ConceptRelation] relationships = [ConceptRelation]
rels = getRelations(first=self, relationships=relationships) rels = getRelations(first=self, relationships=relationships)
return [r.second for r in rels] return [r.second for r in rels]
# TODO: sort... # TODO: sort...
def getParentConcepts(self, relationships=None): def getParents(self, relationships=None):
if relationships is None: if relationships is None:
relationships = [ConceptRelation] relationships = [ConceptRelation]
rels = getRelations(second=self, relationships=relationships) rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels] return [r.first for r in rels]
def assignConcept(self, concept, relationship=ConceptRelation): def assignChild(self, concept, relationship=ConceptRelation):
registry = zapi.getUtility(IRelationRegistry) registry = zapi.getUtility(IRelationRegistry)
rel = relationship(self, concept) rel = relationship(self, concept)
registry.register(rel) registry.register(rel)
# TODO (?): avoid duplicates # 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: if relationships is None:
relationships = [ConceptRelation] relationships = [ConceptRelation]
registry = zapi.getUtility(IRelationRegistry) registry = zapi.getUtility(IRelationRegistry)
@ -98,6 +101,9 @@ class Concept(Contained, Persistent):
for rel in relations: for rel in relations:
registry.unregister(relation) registry.unregister(relation)
def deassignParents(self, concept, relationships=None):
concept.deassignChildren(self, relationships)
# resource relations # resource relations
def getResources(self, relationships=None): def getResources(self, relationships=None):
@ -134,5 +140,3 @@ class ConceptManager(BTreeContainer):
def getViewManager(self): def getViewManager(self):
return self.getLoopsRoot().getViewManager() return self.getLoopsRoot().getViewManager()

View file

@ -71,28 +71,40 @@ class IConcept(ILoopsObject, IPotentialTarget):
default=u'', default=u'',
required=False) required=False)
def getSubConcepts(relationships=None): def getChildren(relationships=None):
""" Return a sequence of concepts related to self as sub-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
relation classes) given. relation classes) given.
""" """
def getParentConcepts(relationships=None): def getParents(relationships=None):
""" Return a tuple of concepts related to self as parent concepts, """ Return a tuple of concepts related to self as parent concepts,
possibly restricted to the relationships (typically a list of possibly restricted to the relationships (typically a list of
relation classes) given. relation classes) given.
""" """
def assignConcept(concept, relationship): def assignChild(concept, relationship):
""" Assign an existing concept to self using the relationship given. """ 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. The relationship defaults to ConceptRelation.
""" """
def deassignConcept(concept, relationships=None): def assignParent(concept, relationship):
""" Remove the relations to the concept given from self, optionally """ Assign an existing concept to self using the relationship given.
restricting them to the relationships 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): def getResources(relationships=None):

View file

@ -108,16 +108,33 @@ class TargetSourceList(object):
implements(schema.interfaces.IIterableSource) implements(schema.interfaces.IIterableSource)
def __init__(self, context): def __init__(self, context):
#self.context = context
self.context = removeSecurityProxy(context) self.context = removeSecurityProxy(context)
root = self.context.getLoopsRoot() root = self.context.getLoopsRoot()
self.resources = root.getResourceManager() self.resources = root.getResourceManager()
self.concepts = root.getConceptManager() self.concepts = root.getConceptManager()
def __iter__(self): 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): def __len__(self):
return len(self.resources) + len(self.concepts) 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()