diff --git a/composer/layout/README.txt b/composer/layout/README.txt
index 9ce03e2..9d0ae06 100644
--- a/composer/layout/README.txt
+++ b/composer/layout/README.txt
@@ -4,40 +4,52 @@ Layout Management
($Id$)
+Let's start with some basic setup; the traversable adapter is needed for
+rendering the page templates.
+
>>> from zope import component
>>> from zope.interface import Interface
+ >>> from zope.traversing.adapters import DefaultTraversable
+ >>> component.provideAdapter(DefaultTraversable, (Interface,))
+
+For testing we define a simple content class.
+
+ >>> class Document(object):
+ ... text = ''
+
+The layout management is controlled by a global utility, the layout
+manager.
+
+ >>> from cybertools.composer.layout.base import LayoutManager, LayoutInstance
+ >>> from cybertools.composer.layout.interfaces import ILayout
- >>> from cybertools.composer.layout.base import LayoutManager
>>> manager = LayoutManager()
>>> component.provideUtility(manager)
- >>> from zope.traversing.adapters import DefaultTraversable
- >>> component.provideAdapter(DefaultTraversable, (Interface,))
+The layouts themselves are also specified as utilities.
+
+ >>> #from cybertools.composer.layout.browser.liquid.default import css
+ >>> #component.provideUtility(css, ILayout, name='css')
+
+ >>> from cybertools.composer.layout.browser.liquid.default import body
+ >>> component.provideUtility(body, ILayout, name='body.liquid')
+
+ >>> from cybertools.composer.layout.browser.default import footer
+ >>> component.provideUtility(footer, ILayout, name='footer.default')
+
+In addition we have to provide at least one layout instance adapter that
+connects a layout with the client object.
+
+ >>> component.provideAdapter(LayoutInstance, (object,))
Browser Views
=============
- >>> from zope.app.pagetemplate import ViewPageTemplateFile
- >>> standardRenderers = ViewPageTemplateFile('browser/standard.pt').macros
-
- >>> from cybertools.composer.layout.base import Layout
- >>> from cybertools.composer.layout.interfaces import ILayout
-
- >>> #css = Layout('page.css', renderer=standardRenderers['css'])
- >>> # css = ResourceCollection('css', resourceRenderers['css'])
- >>> #component.provideUtility(css, ILayout, name='css')
-
- >>> from cybertools.composer.layout.browser.liquid.default import BodyLayout
- >>> bodyLayout = BodyLayout()
- >>> component.provideUtility(bodyLayout, ILayout, name='body.liquid')
-
- >>> footerLayout = Layout('body.footer', renderer=standardRenderers['footer'])
- >>> component.provideUtility(footerLayout, ILayout, name='footer.default')
-
>>> from cybertools.composer.layout.browser.view import Page
>>> from zope.publisher.browser import TestRequest
- >>> page = Page(None, TestRequest())
+
+ >>> page = Page(Document(), TestRequest())
>>> page()
u'.........'
diff --git a/composer/layout/base.py b/composer/layout/base.py
index ae65121..9431ef0 100644
--- a/composer/layout/base.py
+++ b/composer/layout/base.py
@@ -47,37 +47,35 @@ class LayoutManager(object):
region.layouts.append(layout)
return result
- def getLayouts(self, key, **kw):
+ def getLayouts(self, key, instance):
region = self.regions.get(key)
if region is None:
return []
- # TODO: filter region.layouts
- return region.layouts
+ result = []
+ for layout in region.layouts:
+ if self.check(layout, instance):
+ result.append(layout)
+ return result
- def register(self, layout, regionName):
- region = self.regions.setdefault(regionName, Region(regionName))
- region.layouts.append(layout)
+ def check(self, layout, instance):
+ if instance is None or instance.checkLayout(layout):
+ return True
class Layout(Template):
implements(ILayout)
- name = ''
+ title = description = u''
+ category = 'default'
renderer = None
- regionName = None
- skin = 'default'
- def __init__(self, regionName, **kw):
+ def __init__(self, name, regionName, **kw):
+ self.name = name
self.regionName = regionName
for k, v in kw.items():
setattr(self, k, v)
- def registerFor(self, regionName):
- manager = component.getUtility(ILayoutManager)
- manager.register(self, regionName)
- self.regionName = regionName
-
class LayoutInstance(object):
@@ -91,3 +89,7 @@ class LayoutInstance(object):
@property
def renderer(self):
return self.template.renderer
+
+ def checkLayout(self, layout):
+ return True
+
diff --git a/composer/layout/browser/default.pt b/composer/layout/browser/default.pt
new file mode 100644
index 0000000..5497492
--- /dev/null
+++ b/composer/layout/browser/default.pt
@@ -0,0 +1,3 @@
+
+ Some footer text.
+
diff --git a/composer/layout/browser/default.py b/composer/layout/browser/default.py
index 1949e26..974a664 100644
--- a/composer/layout/browser/default.py
+++ b/composer/layout/browser/default.py
@@ -27,7 +27,8 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from cybertools.composer.layout.base import Layout
-standardRenderers = ViewPageTemplateFile('standard.pt').macros
+defaultRenderers = ViewPageTemplateFile('default.pt').macros
-footer = Layout('body.footer', renderer=standardRenderers['footer'])
+footer = Layout('footer.default', 'body.footer',
+ renderer=defaultRenderers['footer'])
diff --git a/composer/layout/browser/liquid/default.py b/composer/layout/browser/liquid/default.py
index cbc0b49..598caa4 100644
--- a/composer/layout/browser/liquid/default.py
+++ b/composer/layout/browser/liquid/default.py
@@ -30,17 +30,8 @@ from zope.interface import implements
from cybertools.composer.layout.base import Layout
-template = ViewPageTemplateFile('default.pt')
+defaultRenderers = ViewPageTemplateFile('default.pt').macros
-
-class BodyLayout(Layout):
-
- regionName = 'page.body'
-
- def __init__(self):
- pass
-
- @Lazy
- def renderer(self):
- return template.macros['body']
+body = Layout('body.liquid', 'page.body',
+ renderer=defaultRenderers['body'])
diff --git a/composer/layout/browser/main.pt b/composer/layout/browser/main.pt
index 7159ef9..86154cf 100644
--- a/composer/layout/browser/main.pt
+++ b/composer/layout/browser/main.pt
@@ -9,8 +9,8 @@
-
-
+
+
diff --git a/composer/layout/browser/standard.pt b/composer/layout/browser/standard.pt
index fae3f7e..10dedf3 100644
--- a/composer/layout/browser/standard.pt
+++ b/composer/layout/browser/standard.pt
@@ -1,12 +1,7 @@
-
- Some footer text.
-
-
-
diff --git a/composer/layout/browser/standard.py b/composer/layout/browser/standard.py
new file mode 100644
index 0000000..cc44315
--- /dev/null
+++ b/composer/layout/browser/standard.py
@@ -0,0 +1,34 @@
+#
+# 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
+#
+
+"""
+Default layouts.
+
+$Id$
+"""
+
+from zope.app.pagetemplate import ViewPageTemplateFile
+
+from cybertools.composer.layout.base import Layout
+
+
+standardRenderers = ViewPageTemplateFile('standard.pt').macros
+
+
+footer = Layout('footer.default', 'body.footer',
+ renderer=standardRenderers['footer'])
diff --git a/composer/layout/browser/view.py b/composer/layout/browser/view.py
index a58b43a..2433684 100644
--- a/composer/layout/browser/view.py
+++ b/composer/layout/browser/view.py
@@ -27,38 +27,56 @@ from zope.interface import Interface, implements
from zope.cachedescriptors.property import Lazy
from zope.app.pagetemplate import ViewPageTemplateFile
-from cybertools.composer.layout.base import Layout, LayoutInstance
-from cybertools.composer.layout.interfaces import ILayoutManager
+from cybertools.composer.layout.base import Layout
+from cybertools.composer.layout.interfaces import ILayoutManager, ILayoutInstance
class BaseView(object):
template = ViewPageTemplateFile('base.pt')
- def __init__(self, context, request, name=None):
+ page = None
+ parent = None
+ skin = None
+
+ def __init__(self, context, request, **kw):
self.context = self.__parent__ = context
self.request = request
- if name is not None:
- self.name = name
-
- def update(self):
- return True
+ for k, v in kw.items():
+ setattr(self, k, v)
def __call__(self):
return self.template(self)
+ def update(self):
+ return True
+
class Page(BaseView):
+ macroName = 'page'
+
+ @Lazy
+ def rootView(self):
+ return self
+
def __call__(self):
- layout = Layout('page')
- layout.renderer = ViewPageTemplateFile('main.pt').macros['page']
- instance = LayoutInstance(self.context)
+ layout = Layout('page', 'page')
+ layout.renderer = ViewPageTemplateFile('main.pt').macros[self.macroName]
+ instance = ILayoutInstance(self.context)
instance.template = layout
- view = LayoutView(instance, self.request, name='page')
+ view = LayoutView(instance, self.request, name='page',
+ parent=self, page=self)
view.body = view.layouts['body'][0]
+ instance.view = view
return view.template(view)
+ @Lazy
+ def resourceBase(self):
+ skinSetter = self.skin and ('/++skin++' + self.skin.__name__) or ''
+ # TODO: put '/@@' etc after path to site instead of directly after URL0
+ return self.request.URL[0] + skinSetter + '/@@/'
+
class LayoutView(BaseView):
@@ -83,9 +101,9 @@ class LayoutView(BaseView):
def resources(self):
return ViewResources(self)
- def getLayoutsFor(self, key, **kw):
+ def getLayoutsFor(self, key):
manager = component.getUtility(ILayoutManager)
- return manager.getLayouts('.'.join((self.name, key)), **kw)
+ return manager.getLayouts('.'.join((self.name, key)), self.context)
# subview providers
@@ -99,10 +117,12 @@ class ViewLayouts(object):
view = self.view
subviews = []
for layout in view.getLayoutsFor(key):
- instance = LayoutInstance(view.client)
+ instance = ILayoutInstance(view.client)
instance.template = layout
- instance.view = view
- subviews.append(LayoutView(instance, view.request, name=key))
+ v = LayoutView(instance, view.request, name=key,
+ parent=view, page=view.page)
+ instance.view = v
+ subviews.append(v)
return subviews
diff --git a/composer/layout/interfaces.py b/composer/layout/interfaces.py
index e4775a6..d3ae2b5 100644
--- a/composer/layout/interfaces.py
+++ b/composer/layout/interfaces.py
@@ -37,17 +37,24 @@ class ILayoutManager(Interface):
""" A utility that manages layouts and regions.
"""
- def register(layout, regionName):
- """ Register the layout given for the region specified.
+ def getLayouts(regionName, instance):
+ """ Return a sequence of layouts for the region given that are
+ valid sub-layouts for the layout instance given.
"""
+ def check(layout, instance):
+ """ Return True if the layout given is a valid sub-layout
+ for the instance given.
+ """
+
+
class ILayout(ITemplate):
""" Represents an ordered sequence of layout elements.
"""
name = schema.ASCIILine(
- title=_(u'Layout name'),
+ title=_(u'Layout Name'),
description=_(u'The internal name of the layout.'),
required=True,)
title = schema.TextLine(
@@ -63,13 +70,14 @@ class ILayout(ITemplate):
description=_(u'The name of a layout category this layout '
u'belongs to.'),
required=False,)
+ regionName = schema.ASCIILine(
+ title=_(u'Region Name'),
+ description=_(u'A dotted name that specifies the region '
+ u'this layout should be used for.'),
+ required=True,)
renderer = Attribute(u'An object responsible for rendering the layout.')
- def registerFor(regionName):
- """ Register the layout for the region specified.
- """
-
class ILayoutComponent(IComponent):
""" May be used for data entry or display.
@@ -77,11 +85,11 @@ class ILayoutComponent(IComponent):
name = schema.ASCIILine(
title=_(u'Component name'),
- description=_(u'The internal name of the component'),
+ description=_(u'The internal name of the component.'),
required=True,)
title = schema.TextLine(
title=_(u'Title'),
- description=_(u'The title or label of the component'),
+ description=_(u'The title or label of the component.'),
required=True,)
description = schema.Text(
title=_(u'Description'),
@@ -100,16 +108,25 @@ class ILayoutInstance(IInstance):
renderer = Attribute(u'An object responsible for rendering the layout.')
+ def checkLayout(layout):
+ """ Return True if the layout given is a valid sub-layout
+ for this instance.
+ """
+
class IRegion(Interface):
""" A part of a layout "canvas" that may be filled with layout objects.
"""
+ name = schema.ASCIILine(
+ title=_(u'Region name'),
+ description=_(u'The internal name of the region.'),
+ required=True,)
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'),
+ u'in this region.'),
value_type=schema.ASCIILine(),
required=False,)