diff --git a/composer/interfaces.py b/composer/interfaces.py
index b3297eb..e3a7546 100644
--- a/composer/interfaces.py
+++ b/composer/interfaces.py
@@ -63,8 +63,8 @@ class IInstance(Interface):
context = Attribute('Object this instance adapter has been created for')
template = Attribute('A template to be used for this instance')
- aspect = Attribute('A dotted name that helps to store and retrieve the '
- 'template.')
+ aspect = Attribute('Optional: a dotted name that may help to store and '
+ 'retrieve the template.')
def applyTemplate(*args, **kw):
""" Apply the template using the instance's context. Note that this
diff --git a/composer/layout/README.txt b/composer/layout/README.txt
index 5a15908..ce998f7 100644
--- a/composer/layout/README.txt
+++ b/composer/layout/README.txt
@@ -4,5 +4,41 @@ Layout Management
($Id$)
- >>> from cybertools.composer.layout.base import Layout
+ >>> from zope import component
+ >>> from zope.interface import Interface
+ >>> from cybertools.composer.layout.base import Layout, LayoutInstance
+ >>> from cybertools.composer.layout.region import Region, regions
+
+
+Browser Views
+=============
+
+ >>> from zope.traversing.adapters import DefaultTraversable
+ >>> component.provideAdapter(DefaultTraversable, (Interface,))
+
+ >>> from cybertools.composer.layout.browser.layout import PageLayout
+ >>> pageLayout = PageLayout()
+ >>> pageLayoutInstance = LayoutInstance(pageLayout)
+
+ >>> from zope.app.pagetemplate import ViewPageTemplateFile
+
+ >>> bodyLayout = Layout()
+ >>> bodyLayout.renderer = ViewPageTemplateFile('browser/liquid/body.pt').macros['body']
+ >>> bodyRegion = Region('body')
+ >>> bodyRegion.layouts.append(LayoutInstance(bodyLayout))
+ >>> regions['page.body'] = bodyRegion
+
+ >>> standardRenderers = ViewPageTemplateFile('browser/standard.pt').macros
+ >>> footerLayout = Layout()
+ >>> footerLayout.renderer = standardRenderers['footer']
+ >>> footerRegion = Region('footer')
+ >>> footerRegion.layouts.append(LayoutInstance(footerLayout))
+ >>> regions['body.footer'] = footerRegion
+
+ >>> from cybertools.composer.layout.browser.view import Page
+ >>> from zope.publisher.browser import TestRequest
+ >>> page = Page(pageLayoutInstance, TestRequest())
+
+ >>> page()
+ u'.........
diff --git a/composer/layout/base.py b/composer/layout/base.py
index c664bd5..f0d4ca4 100644
--- a/composer/layout/base.py
+++ b/composer/layout/base.py
@@ -26,7 +26,8 @@ from zope.interface import implements
from cybertools.composer.base import Component, Element, Compound
from cybertools.composer.base import Template
-from cybertools.composer.layout.interfaces import ILayout
+from cybertools.composer.layout.interfaces import ILayout, ILayoutInstance
+from cybertools.composer.layout.interfaces import IRegion
from cybertools.util.jeep import Jeep
@@ -36,4 +37,32 @@ class Layout(Template):
name = u''
manager = None
+ renderer = None
+
+
+class LayoutInstance(object):
+
+ implements(ILayoutInstance)
+
+ def __init__(self, template, context=None):
+ self.template = template
+ self.context = context
+
+ @property
+ def renderer(self):
+ return self.template.renderer
+
+
+class Region(object):
+
+ implements(IRegion)
+
+ allowedLayoutCategories = None
+
+ def __init__(self, name):
+ self.name = name
+
+ @property
+ def layouts(self):
+ return []
diff --git a/composer/layout/browser/__init__.py b/composer/layout/browser/__init__.py
new file mode 100644
index 0000000..38314f3
--- /dev/null
+++ b/composer/layout/browser/__init__.py
@@ -0,0 +1,3 @@
+"""
+$Id$
+"""
diff --git a/composer/layout/browser/base.pt b/composer/layout/browser/base.pt
new file mode 100644
index 0000000..5924365
--- /dev/null
+++ b/composer/layout/browser/base.pt
@@ -0,0 +1 @@
+
diff --git a/composer/layout/browser/layout.py b/composer/layout/browser/layout.py
new file mode 100644
index 0000000..fc614f7
--- /dev/null
+++ b/composer/layout/browser/layout.py
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2008 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
+#
+
+"""
+Specialized browser layouts.
+
+$Id$
+"""
+
+from zope.app.pagetemplate import ViewPageTemplateFile
+
+from cybertools.composer.layout.base import Layout
+
+
+class PageLayout(Layout):
+
+ name = u'page'
+
+ @property
+ def renderer(self):
+ return ViewPageTemplateFile('main.pt').macros['page']
+
diff --git a/composer/layout/browser/liquid/__init__.py b/composer/layout/browser/liquid/__init__.py
new file mode 100644
index 0000000..38314f3
--- /dev/null
+++ b/composer/layout/browser/liquid/__init__.py
@@ -0,0 +1,3 @@
+"""
+$Id$
+"""
diff --git a/composer/layout/browser/liquid/body.pt b/composer/layout/browser/liquid/body.pt
new file mode 100644
index 0000000..de854d7
--- /dev/null
+++ b/composer/layout/browser/liquid/body.pt
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
diff --git a/composer/layout/browser/main.pt b/composer/layout/browser/main.pt
new file mode 100644
index 0000000..7159ef9
--- /dev/null
+++ b/composer/layout/browser/main.pt
@@ -0,0 +1,22 @@
+
+
+
+
+
+ Powered by Zope 3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composer/layout/browser/standard.pt b/composer/layout/browser/standard.pt
new file mode 100644
index 0000000..5497492
--- /dev/null
+++ b/composer/layout/browser/standard.pt
@@ -0,0 +1,3 @@
+
+ Some footer text.
+
diff --git a/composer/layout/browser/view.py b/composer/layout/browser/view.py
new file mode 100644
index 0000000..d2c1d3a
--- /dev/null
+++ b/composer/layout/browser/view.py
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2008 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
+#
+
+"""
+Basic view classes for layout-based presentation.
+
+$Id$
+"""
+
+from zope import component
+from zope.interface import Interface, implements
+from zope.cachedescriptors.property import Lazy
+from zope.app.pagetemplate import ViewPageTemplateFile
+
+from cybertools.composer.layout.region import regions
+
+
+class BaseView(object):
+
+ template = ViewPageTemplateFile('base.pt')
+
+ def __init__(self, context, request, name=None):
+ self.context = self.__parent__ = context
+ self.request = request
+ if name is not None:
+ self.name = name
+
+ def update(self):
+ return True
+
+ def __call__(self):
+ return self.template(self)
+
+
+class LayoutView(BaseView):
+
+ name = 'base'
+
+ @Lazy
+ def renderer(self):
+ return self.context.renderer
+
+ @Lazy
+ def layouts(self):
+ return ViewLayouts(self)
+
+ @Lazy
+ def resources(self):
+ return ViewResources(self)
+
+ def getRegion(self, key):
+ return regions['.'.join((self.name, key))]
+
+
+class Page(LayoutView):
+
+ name = 'page'
+
+ #@Lazy
+ def body(self):
+ return self.layouts['body'][0]()
+
+
+class ViewLayouts(object):
+
+ def __init__(self, view):
+ self.view = view
+
+ def __getitem__(self, key):
+ view = self.view
+ region = view.getRegion(key)
+ return [LayoutView(layout, view.request, name=key)
+ for layout in region.layouts]
+
+
+class ViewResources(object):
+
+ def __init__(self, view):
+ self.view = view
+
+ def __getitem__(self, key):
+ return []
diff --git a/composer/layout/interfaces.py b/composer/layout/interfaces.py
index baebe2f..3d96c80 100644
--- a/composer/layout/interfaces.py
+++ b/composer/layout/interfaces.py
@@ -1,4 +1,4 @@
-#
+
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@ from zope import schema
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from cybertools.composer.interfaces import ITemplate, IComponent
-from cybertools.composer.interfaces import IInstance as IBaseInstance
+from cybertools.composer.interfaces import IInstance
_ = MessageFactory('cybertools.composer')
@@ -37,7 +37,7 @@ class ILayout(ITemplate):
""" Represents an ordered sequence of layout elements.
"""
- name = schema.ASCII(
+ name = schema.ASCIILine(
title=_(u'Layout name'),
description=_(u'The internal name of the layout.'),
required=True,)
@@ -49,13 +49,20 @@ class ILayout(ITemplate):
title=_(u'Description'),
description=_(u'A medium-length description.'),
required=False,)
+ category = schema.ASCIILine(
+ title=_(u'Layout category'),
+ description=_(u'The name of a layout category this layout '
+ u'belongs to.'),
+ required=False,)
+
+ renderer = Attribute(u'An object responsible for rendering the layout.')
class ILayoutComponent(IComponent):
""" May be used for data entry or display.
"""
- name = schema.ASCII(
+ name = schema.ASCIILine(
title=_(u'Component name'),
description=_(u'The internal name of the component'),
required=True,)
@@ -73,10 +80,29 @@ class ILayoutComponent(IComponent):
u'or a listing, ...')
-class ILayoutInstance(IBaseInstance):
+class ILayoutInstance(IInstance):
""" An instance adapter for an arbitrary client object that associates
it with a layout.
"""
+ renderer = Attribute(u'An object responsible for rendering the layout.')
+
componentAttributes = Attribute(u'A mapping``{componentName: value, ...}`` '
- u'specifying the parameter values entered for the components.')
+ u'specifying the parameter values entered for the components. '
+ u'If a component is a layout the value is a corresponding '
+ u'layout instance.')
+
+
+class IRegion(Interface):
+ """ A part of a layout "canvas" that may be filled with layout objects.
+ """
+
+ allowedLayoutCategories = schema.List(
+ title=_(u'Allowed layout categories'),
+ description=_(u'A collection of names of layout categories '
+ u'to which layouts may belong that may be placed '
+ u'in this region'),
+ value_type=schema.ASCIILine(),
+ required=False,)
+
+ layouts = Attribute(u'The layout instances currently assigned to this region.')
diff --git a/composer/layout/region.py b/composer/layout/region.py
new file mode 100644
index 0000000..0fff39b
--- /dev/null
+++ b/composer/layout/region.py
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2008 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
+#
+
+"""
+Region class(es) + default regions registry.
+
+$Id$
+"""
+
+from zope.interface import implements
+
+from cybertools.composer.layout.interfaces import IRegion
+
+
+class Region(object):
+
+ implements(IRegion)
+
+ allowedLayoutCategories = None
+
+ def __init__(self, name):
+ self.name = name
+ self.layouts = []
+
+
+regions = {}