diff --git a/browser/common.py b/browser/common.py index a324b29..252b188 100644 --- a/browser/common.py +++ b/browser/common.py @@ -28,11 +28,14 @@ from zope.app.form.browser.interfaces import ITerms from zope.app.intid.interfaces import IIntIds from zope.cachedescriptors.property import Lazy from zope.dottedname.resolve import resolve +from zope.formlib.form import FormFields from zope.formlib.form import EditForm as BaseEditForm +from zope.formlib.form import AddForm as BaseAddForm from zope.formlib.namedtemplate import NamedTemplate -from zope.interface import implements +from zope.interface import Interface, implements from zope.app.publisher.browser import applySkin from zope.publisher.interfaces.browser import ISkin +from zope import schema from zope.schema.vocabulary import SimpleTerm from zope.security import canAccess, canWrite from zope.security.proxy import removeSecurityProxy @@ -40,6 +43,29 @@ from zope.security.proxy import removeSecurityProxy from cybertools.typology.interfaces import IType from loops.interfaces import IView from loops import util +from loops.util import _ + + +class NameField(schema.ASCIILine): + + def _validate(self, value): + super(NameField, self)._validate(value) + + +class IAddForm(Interface): + + name = NameField( + title=_(u'Object name'), + description=_(u'Name of the object - will be used for addressing the ' + 'object via a URL; should therefore be unique within ' + 'the container and not contain special characters') + ) + + +class AddForm(BaseAddForm): + + form_fields = FormFields(IAddForm) + template = NamedTemplate('loops.pageform') class EditForm(BaseEditForm): diff --git a/browser/configure.zcml b/browser/configure.zcml index 1833d2e..bf02b92 100644 --- a/browser/configure.zcml +++ b/browser/configure.zcml @@ -85,13 +85,11 @@ - - + class="loops.browser.manager.LoopsEditForm" + permission="zope.ManageApplication" + menu="zmi_views" title="Edit" + /> diff --git a/browser/manager.py b/browser/manager.py new file mode 100644 index 0000000..63eabd3 --- /dev/null +++ b/browser/manager.py @@ -0,0 +1,60 @@ +# +# Copyright (c) 2006 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 view classes for the top-level loops container. + +$Id$ +""" + +from zope.app import zapi +from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent +from zope.event import notify +from zope.formlib.form import FormFields +from loops import Loops +from loops.interfaces import ILoops +from loops.browser.common import AddForm, EditForm, BaseView +from loops.setup import ISetupManager +from loops.util import _ + + +class LoopsAddForm(AddForm): + + form_fields = AddForm.form_fields + FormFields(ILoops) + label = _(u'Create Loops Site') + + def createAndAdd(self, data): + container = self.context.context + name = data.pop('name', 'loopsdemo') + loops = Loops() + self.context.contentName = name + for attr in data: + setattr(loops, attr, data[attr]) + notify(ObjectCreatedEvent(loops)) + self.context.add(loops) + setup = ISetupManager(loops, None) + if setup is not None: + setup.setup() + return loops + + +class LoopsEditForm(EditForm): + + form_fields = FormFields(ILoops) + + diff --git a/browser/pageform.pt b/browser/pageform.pt index 5aa70ee..a274736 100644 --- a/browser/pageform.pt +++ b/browser/pageform.pt @@ -41,12 +41,16 @@ function toggleFormFieldHelp(ob,state) {
-

Edit +

Edit Concept + tal:content="context/title|context/zope:name">Concept

+

Headline

+
+ diff --git a/helpers.txt b/helpers.txt index 5697b5d..b75a1c1 100755 --- a/helpers.txt +++ b/helpers.txt @@ -19,26 +19,30 @@ Let's first do some basic imports >>> from zope.interface import Interface >>> from zope.publisher.browser import TestRequest -and setup a simple loops site with its manager objects, +and provide a relation registry: + + >>> from cybertools.relation.interfaces import IRelationRegistry + >>> from cybertools.relation.registry import DummyRelationRegistry + >>> from zope.app.testing import ztapi + >>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry()) + +Now we can setup a simple loops site with its manager objects, using a +loops setup manager: >>> from loops import Loops >>> site['loops'] = Loops() >>> loopsRoot = site['loops'] - >>> from loops.concept import ConceptManager, Concept - >>> loopsRoot['concepts'] = ConceptManager() + >>> from loops.setup import SetupManager + >>> setup = SetupManager(loopsRoot) + >>> setup.setup() >>> concepts = loopsRoot['concepts'] - - >>> from loops.resource import ResourceManager, Document, MediaAsset - >>> loopsRoot['resources'] = ResourceManager() >>> resources = loopsRoot['resources'] - - >>> from loops.view import ViewManager, Node - >>> loopsRoot['views'] = ViewManager() >>> views = loopsRoot['views'] -some concepts, +We also add some example concepts, + >>> from loops.concept import Concept >>> cc1 = Concept(u'Zope') >>> concepts['cc1'] = cc1 >>> cc1.title @@ -51,6 +55,7 @@ some concepts, resources, + >>> from loops.resource import Document, MediaAsset >>> doc1 = Document(u'Zope Info') >>> resources['doc1'] = doc1 >>> doc1.title @@ -61,6 +66,7 @@ resources, and nodes (in view space): + >>> from loops.view import Node >>> m1 = Node(u'Home') >>> views['m1'] = m1 >>> m1.nodeType = 'menu' @@ -69,12 +75,6 @@ and nodes (in view space): >>> m1['p1'] = m1p1 >>> m1p1.nodeType = 'page' -Finally, we also need a relation registry: - - >>> from cybertools.relation.interfaces import IRelationRegistry - >>> from cybertools.relation.registry import DummyRelationRegistry - >>> from zope.app.testing import ztapi - >>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry()) Type management with typology ============================= @@ -98,11 +98,10 @@ As we have not yet associated a type with one of our content objects we get >>> cc1_type.token '.unknown' -So we create two special concepts: one ('hasType') as the predicate signifying -a type relation, and the other ('type') as the one and only type concept: +During setup we created two special concepts: one ('hasType') as the predicate +signifying a type relation, and the other ('type') as the one and only type +concept: - >>> concepts['hasType'] = Concept(u'has type') - >>> concepts['type'] = Concept(u'Type') >>> typeObject = concepts['type'] Assigning a type to a concept is a core functionality of concepts as @@ -189,8 +188,9 @@ get a type manager from all loops objects, always with the same context: >>> types = typeManager.types >>> sorted(t.token for t in types) - ['.loops/concepts/topic', '.loops/concepts/type', - 'loops.resource.Document', 'loops.resource.MediaAsset'] + ['.loops/concepts/predicate', '.loops/concepts/topic', + '.loops/concepts/type', 'loops.resource.Document', + 'loops.resource.MediaAsset'] >>> typeManager.getType('.loops/concepts/topic') == cc1_type True @@ -200,7 +200,7 @@ condition: >>> types = typeManager.listTypes(include=('concept',)) >>> sorted(t.token for t in types) - ['.loops/concepts/topic', '.loops/concepts/type'] + ['.loops/concepts/predicate', '.loops/concepts/topic', '.loops/concepts/type'] >>> types = typeManager.listTypes(exclude=('concept',)) >>> sorted(t.token for t in types) ['loops.resource.Document', 'loops.resource.MediaAsset'] diff --git a/interfaces.py b/interfaces.py index 1aa1c8d..f044a44 100644 --- a/interfaces.py +++ b/interfaces.py @@ -32,8 +32,7 @@ from zope.app.folder.interfaces import IFolder from cybertools.relation.interfaces import IRelation import util - -_ = MessageFactory('loops') +from util import _ # common interfaces diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..25370a8 --- /dev/null +++ b/setup.py @@ -0,0 +1,86 @@ +# +# Copyright (c) 2006 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 +# + +""" +Automatic setup of a loops site. + +$Id$ +""" + +import transaction +from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent +from zope.event import notify +from zope.component import adapts +from zope.interface import implements, Interface +from zope.cachedescriptors.property import Lazy + +from loops.interfaces import ILoops +from loops.concept import ConceptManager, Concept +from loops.resource import ResourceManager +from loops.view import ViewManager, Node + + +class ISetupManager(Interface): + """ An object that controls the setup of a loops site. + """ + + def setup(): + """ Set up a loops site: create all necessary objects and the + relations between them. + """ + + +class SetupManager(object): + + adapts(ILoops) + implements(ISetupManager) + + def __init__(self, context): + self.context = context + + def setup(self): + concepts, resources, views = self.setupManagers() + self.setupCoreConcepts(concepts) + + def setupManagers(self): + loopsRoot = self.context + concepts = self.addObject(loopsRoot, ConceptManager, 'concepts') + resources = self.addObject(loopsRoot, ResourceManager, 'resources') + views = self.addObject(loopsRoot, ViewManager, 'views') + return concepts, resources, views + + def setupCoreConcepts(self, conceptManager): + typeConcept = self.addObject(conceptManager, Concept, 'type', u'Type') + hasType = self.addObject(conceptManager, Concept, 'hasType', u'has type') + predicate = self.addObject(conceptManager, Concept, 'predicate', u'Predicate') + standard = self.addObject(conceptManager, Concept, 'standard', u'subobject') + typeConcept.conceptType = typeConcept + predicate.conceptType = typeConcept + hasType.conceptType = predicate + standard.conceptType = predicate + + def addObject(self, container, class_, name, title=None): + if name in container: + return container[name] + if title: + obj = container[name] = class_(title) + else: + obj = container[name] = class_() + notify(ObjectCreatedEvent(obj)) + notify(ObjectModifiedEvent(obj)) + return obj diff --git a/tests/test_loops.py b/tests/test_loops.py index 330425d..cc6a8f3 100755 --- a/tests/test_loops.py +++ b/tests/test_loops.py @@ -17,6 +17,12 @@ from loops.concept import Concept, ConceptManager from loops.resource import Document, MediaAsset, ResourceManager from loops.view import Node, ViewManager +# just for making sure there aren't any syntax and other errors during +# Zope startup: + +from loops.browser.manager import LoopsAddForm, LoopsEditForm + + class Test(unittest.TestCase): "Basic tests for the loops package." diff --git a/util.py b/util.py index 30c6e61..41d14a5 100644 --- a/util.py +++ b/util.py @@ -23,9 +23,12 @@ $Id$ """ from zope.interface import directlyProvides, directlyProvidedBy +from zope.i18nmessageid import MessageFactory from zope.schema import vocabulary #from view import TargetRelation +_ = MessageFactory('loops') + class KeywordVocabulary(vocabulary.SimpleVocabulary):