diff --git a/README.txt b/README.txt
index d51602c..1e0721b 100755
--- a/README.txt
+++ b/README.txt
@@ -3,17 +3,25 @@ loops - Linked Objects for Organizational Process Services
($Id$)
-Concepts and Relations
-~~~~~~~~~~~~~~~~~~~~~~
+Concepts and Relations between them
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Let's start with creating a few example concepts:
+Let's start with creating a few example concepts, putting them in a
+top-level loops container and a concept manager:
- >>> from loops.concept import Concept
+ >>> from loops import Loops
+ >>> loops = Loops()
+
+ >>> from loops.concept import ConceptManager, Concept
+ >>> loops['concepts'] = ConceptManager()
+ >>> concepts = loops['concepts']
>>> c1 = Concept()
+ >>> concepts['c1'] = c1
>>> c1.title
u''
>>> c2 = Concept(u'c2', u'Second Concept')
+ >>> concepts['c2'] = c2
>>> c2.title
u'Second Concept'
@@ -33,7 +41,7 @@ We also need a Relation class to be used for connecting concepts:
Now we can assign the concept c2 to c1:
- >>> c1.assignConcept(c2, DyadicRelation)
+ >>> c1.assignConcept(c2)
We can now ask our concepts for their related concepts:
diff --git a/__init__.py b/__init__.py
index 4bc90fb..72219eb 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,4 +1,33 @@
+# -*- coding: UTF-8 -*-
+# -*- Mode: Python; py-indent-offset: 4 -*-
+#
+# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
"""
+
$Id$
"""
+from zope.interface import implements
+from zope.app.folder.folder import Folder
+from interfaces import ILoops
+
+class Loops(Folder):
+
+ implements(ILoops)
+
diff --git a/browser/configure.zcml b/browser/configure.zcml
index e565a7e..e58a2ca 100644
--- a/browser/configure.zcml
+++ b/browser/configure.zcml
@@ -6,6 +6,50 @@
i18n_domain="zope"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/concept.py b/concept.py
index d06813c..33db9a5 100644
--- a/concept.py
+++ b/concept.py
@@ -23,6 +23,7 @@ $Id$
"""
from zope.app import zapi
+from zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained
from zope.interface import implements
from persistent import Persistent
@@ -31,11 +32,14 @@ from cybertools.relation.interfaces import IRelationsRegistry
from cybertools.relation import DyadicRelation
from interfaces import IConcept
+from interfaces import IConceptManager, IConceptManagerContained
+from interfaces import ILoopsContained
+from relations import ConceptRelation
-class Concept(Persistent, Contained):
+class Concept(Contained, Persistent):
- implements(IConcept)
+ implements(IConcept, IConceptManagerContained)
_title = u''
def getTitle(self): return self._title
@@ -56,7 +60,7 @@ class Concept(Persistent, Contained):
rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels]
- def assignConcept(self, concept, relationship):
+ def assignConcept(self, concept, relationship=ConceptRelation):
registry = zapi.getUtility(IRelationsRegistry)
registry.register(relationship(self, concept))
# TODO (?): avoid duplicates
@@ -65,7 +69,12 @@ class Concept(Persistent, Contained):
pass # TODO
-# TODO: move this to the relation package
+class ConceptManager(BTreeContainer):
+
+ implements(IConceptManager, ILoopsContained)
+
+
+# TODO: move this to the cybertools.relation package
def getRelations(first=None, second=None, third=None, relationships=None):
registry = zapi.getUtility(IRelationsRegistry)
diff --git a/configure.zcml b/configure.zcml
index fb3fb48..0eca8e3 100644
--- a/configure.zcml
+++ b/configure.zcml
@@ -7,7 +7,51 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -24,10 +66,6 @@
id="loops.Concept"
description="Concept object" />
-
-
@@ -38,6 +76,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/interfaces.py b/interfaces.py
index 5212968..4056469 100644
--- a/interfaces.py
+++ b/interfaces.py
@@ -25,20 +25,28 @@ $Id$
from zope.interface import Interface
from zope.i18nmessageid import MessageFactory
from zope import schema
+from zope.app.container.constraints import contains, containers
+from zope.app.container.interfaces import IContainer
+from zope.app.file.interfaces import IFile as IBaseFile
+from zope.app.folder.interfaces import IFolder
_ = MessageFactory('loops')
+# concept interfaces
+
class IConcept(Interface):
- """ The 'concept' is the central element of the loops framework.
- A concept is related to other concepts.
+ """ The concept is the central element of the loops framework.
+
+ A concept is related to other concepts, may have resources
+ associated with it and may be referenced by views.
"""
title = schema.TextLine(
title=_(u'Title'),
- description=_(u'Name or short title of the concept'),
+ description=_(u'Title of the concept'),
default=u'',
- required=True)
+ required=False)
def getSubConcepts(relationships=None):
""" Return a tuple of concepts related to self as sub-concepts,
@@ -62,3 +70,115 @@ class IConcept(Interface):
restricting them to the relationships given.
"""
+class IConceptManager(IContainer):
+ """ A manager/container for concepts.
+ """
+ contains(IConcept)
+
+
+class IConceptManagerContained(Interface):
+ containers(IConceptManager)
+
+
+# resource interfaces
+
+class IResource(Interface):
+ """ A resource is an atomic information element that is usually
+ available via a concept.
+ """
+
+ title = schema.TextLine(
+ title=_(u'Title'),
+ description=_(u'Title of the document'),
+ required=False)
+
+
+class IDocument(IResource):
+ """ A resource containing an editable body.
+ """
+
+ body = schema.Text(
+ title=_(u'Body'),
+ description=_(u'Body of the document'),
+ required=False)
+
+ format = schema.TextLine(
+ title=_(u'Format'),
+ description=_(u'Format of the body field, default is "text/xml"'),
+ default=_(u'text/xml'),
+ required=False)
+
+
+class IFile(IResource, IBaseFile):
+ """ A resource containing a (typically binary) file-like content
+ or an image.
+ """
+
+
+class IResourceManager(IContainer):
+ """ A manager/container for resources.
+ """
+ contains(IResource)
+
+
+class IResourceManagerContained(Interface):
+ containers(IResourceManager)
+
+
+# view interfaces
+
+class IView(Interface):
+ """ A view is a user interface component that provides access to one
+ or more concepts.
+ """
+
+ title = schema.TextLine(
+ title=_(u'Title'),
+ description=_(u'Title of the view; this will appear e.g. in menus'),
+ default=u'',
+ required=True)
+
+ description = schema.Text(
+ title=_(u'Description'),
+ description=_(u'Detailed description, e.g. for tooltips or listings'),
+ default=u'',
+ required=False)
+
+ def getConcepts():
+ """ Return an ordered sequence of concepts referenced by this view.
+ """
+
+
+class INode(IContainer):
+ """ A node is a view that may contain other views, thus building a
+ menu or folder hierarchy.
+ """
+ contains(IView)
+
+
+class IViewManager(IContainer):
+ """ A manager/container for views.
+ """
+ contains(IView)
+
+
+class INodeContained(Interface):
+ containers(INode, IViewManager)
+
+
+class IViewManagerContained(Interface):
+ containers(IViewManager)
+
+
+# the loops top-level container
+
+class ILoops(IFolder):
+ """ The top-level object of a loops site.
+ """
+ contains(IConceptManager, IResourceManager, IViewManager)
+
+
+class ILoopsContained(Interface):
+ containers(ILoops)
+
+
diff --git a/relations.py b/relations.py
new file mode 100644
index 0000000..8a0688a
--- /dev/null
+++ b/relations.py
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+Definition of relation classes.
+
+$Id$
+"""
+
+from zope.app import zapi
+from zope.interface import implements
+
+from cybertools.relation import DyadicRelation
+
+
+class ConceptRelation(DyadicRelation):
+ """ A relation between concept objects.
+ """
+
+
+class ResourceRelation(DyadicRelation):
+ """ A relation between concept and resource objects.
+ """
+
+
+class ViewRelation(DyadicRelation):
+ """ A relation between view and concept objects.
+ """
+
diff --git a/resource.py b/resource.py
new file mode 100644
index 0000000..fc582d0
--- /dev/null
+++ b/resource.py
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+Definition of the Concept class.
+
+$Id$
+"""
+
+from zope.app import zapi
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.contained import Contained
+from zope.interface import implements
+from persistent import Persistent
+
+from interfaces import IResource, IDocument
+from interfaces import IResourceManager, IResourceManagerContained
+from interfaces import ILoopsContained
+
+
+class Resource(Contained, Persistent):
+
+ implements(IResource, IResourceManagerContained)
+
+ _title = u''
+ def getTitle(self): return self._title
+ def setTitle(self, title): self._title = title
+ title = property(getTitle, setTitle)
+
+ def __init__(self, name=None, title=u''):
+ self.title = title
+
+
+class Document(Resource):
+
+ implements(IDocument)
+
+ _body = u''
+ def setBody(self, body): self._body = body
+ def getBody(self): return self._body
+ body = property(getBody, setBody)
+
+ _format = u'text/xml'
+ def setFormat(self, format): self._format = format
+ def getFormat(self): return self._format
+ format = property(getFormat, setFormat)
+
+
+class ResourceManager(BTreeContainer):
+
+ implements(IResourceManager, ILoopsContained)
+
+
diff --git a/tests.py b/tests.py
index 372e44b..02de377 100755
--- a/tests.py
+++ b/tests.py
@@ -8,15 +8,21 @@ from zope.interface import implements
from zope.app import zapi
from zope.app.intid.interfaces import IIntIds
-from interfaces import IConcept
-from concept import Concept
+from interfaces import ILoops
+from loops import Loops
+from interfaces import IConcept, IConceptManager
+from loops.concept import Concept, ConceptManager
class Test(unittest.TestCase):
"Basic tests for the loops package."
def testInterfaces(self):
+ verifyClass(ILoops, Loops)
+ self.assert_(ILoops.providedBy(Loops()))
verifyClass(IConcept, Concept)
self.assert_(IConcept.providedBy(Concept()))
+ verifyClass(IConceptManager, ConceptManager)
+ self.assert_(IConceptManager.providedBy(ConceptManager()))
def test_suite():