[Zope3-checkins] CVS: Zope3/src/zope/app/publisher/browser - __init__.py:1.1.2.1 configure.zcml:1.1.2.1 fileresource.py:1.1.2.1 globalbrowsermenuservice.py:1.1.2.1 i18nfileresource.py:1.1.2.1 i18nresourcemeta.py:1.1.2.1 meta.zcml:1.1.2.1 metaconfigure.py:1.1.2.1 resource.py:1.1.2.1 resourcemeta.py:1.1.2.1 resources.py:1.1.2.1 viewmeta.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:32:05 -0500


Update of /cvs-repository/Zope3/src/zope/app/publisher/browser
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/app/publisher/browser

Added Files:
      Tag: NameGeddon-branch
	__init__.py configure.zcml fileresource.py 
	globalbrowsermenuservice.py i18nfileresource.py 
	i18nresourcemeta.py meta.zcml metaconfigure.py resource.py 
	resourcemeta.py resources.py viewmeta.py 
Log Message:
Initial renaming before debugging

=== Added File Zope3/src/zope/app/publisher/browser/__init__.py ===
#
# This file is necessary to make this directory a package.


=== Added File Zope3/src/zope/app/publisher/browser/configure.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:browser='http://namespaces.zope.org/browser'
>


<serviceType id="BrowserMenu"
             interface="zope.app.interfaces.publisher.browser.IBrowserMenuService" />
<service serviceType="BrowserMenu"
         permission="Zope.Public"
         component="zope.app.publisher.browser.globalbrowsermenuservice.globalBrowserMenuService" />


<content class="zope.publisher.browser.BrowserRequest">
  <allow
      interface="zope.publisher.interfaces.browser.IBrowserApplicationRequest" />
  <allow
      interface="zope.component.interfaces.IPresentationRequest" />
</content>

<content class="zope.app.publisher.browser.fileresource.FileResource">
  <allow interface="zope.publisher.interfaces.browser.IBrowserPublisher" />
  <allow attributes="GET HEAD __call__" />
</content>

<content class="zope.app.publisher.browser.i18nfileresource.I18nFileResource">
  <allow interface="zope.publisher.interfaces.browser.IBrowserPublisher" />
  <allow attributes="GET HEAD __call__" />
</content>


<browser:view name=""
              factory="zope.app.publisher.browser.resources.Resources"
              for="zope.app.interfaces.services.service.IServiceManagerContainer"
              permission="Zope.Public"
              allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
              />

</zopeConfigure>


=== Added File Zope3/src/zope/app/publisher/browser/fileresource.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""

$Id: fileresource.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from zope.exceptions import NotFoundError

from zope.publisher.browser import BrowserView
from zope.publisher.interfaces.browser import IBrowserResource
from zope.publisher.interfaces.browser import IBrowserPublisher

from zope.app.publisher.fileresource import File, Image
from zope.app.publisher.browser.resource import Resource
from zope.app.datetime import time as timeFromDateTimeString

from zope.security.proxy import ProxyFactory

class FileResource(BrowserView, Resource):

    __implements__ = IBrowserResource, IBrowserPublisher

    ############################################################
    # Implementation methods for interface
    # Zope.Publisher.Browser.IBrowserPublisher.

    def publishTraverse(self, request, name):
        '''See interface IBrowserPublisher'''
        raise NotFoundError(name)

    def browserDefault(self, request):
        '''See interface IBrowserPublisher'''
        method = request.get('REQUEST_METHOD', 'GET').upper()
        return getattr(self, method), ()

    #
    ############################################################

    # for unit tests
    def _testData(self):
        file = self.chooseContext()
        f=open(self.context.path,'rb')
        data=f.read()
        f.close()
        return data


    def chooseContext(self):
        """Choose the appropriate context"""
        return self.context


    def GET(self):
        """Default document"""

        file = self.chooseContext()
        request = self.request
        response = request.response

        # HTTP If-Modified-Since header handling. This is duplicated
        # from OFS.Image.Image - it really should be consolidated
        # somewhere...
        header = request.getHeader('If-Modified-Since', None)
        if header is not None:
            header = header.split(';')[0]
            # Some proxies seem to send invalid date strings for this
            # header. If the date string is not valid, we ignore it
            # rather than raise an error to be generally consistent
            # with common servers such as Apache (which can usually
            # understand the screwy date string as a lucky side effect
            # of the way they parse it).
            try:    mod_since=long(timeFromDateTimeString(header))
            except: mod_since=None
            if mod_since is not None:
                if getattr(file, 'lmt', None):
                    last_mod = long(file.lmt)
                else:
                    last_mod = long(0)
                if last_mod > 0 and last_mod <= mod_since:
                    response.setStatus(304)
                    return ''

        response.setHeader('Content-Type', file.content_type)
        response.setHeader('Last-Modified', file.lmh)

        # Cache for one day
        response.setHeader('Cache-Control', 'public,max-age=86400')
        f=open(file.path,'rb')
        data=f.read()
        f.close()
        
        return data

    def HEAD(self):
        file = self.chooseContext()
        response = self.request.response
        response = self.request.response
        response.setHeader('Content-Type', file.content_type)
        response.setHeader('Last-Modified', file.lmh)
        # Cache for one day
        response.setHeader('Cache-Control', 'public,max-age=86400')
        return ''
    

class FileResourceFactory:

    def __init__(self, path):
        self.__file = File(path)

    def __call__(self, request):
        return ProxyFactory(FileResource(self.__file, request))

class ImageResourceFactory:

    def __init__(self, path):
        self.__file = Image(path)

    def __call__(self, request):
        return ProxyFactory(FileResource(self.__file, request))


=== Added File Zope3/src/zope/app/publisher/browser/globalbrowsermenuservice.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################

from zope.app.interfaces.publisher.browser import IBrowserMenuService
from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import ISubdirectiveHandler
from zope.configuration.action import Action
from zope.interface.type import TypeRegistry
from zope.exceptions import DuplicationError, Unauthorized, Forbidden
from zope.app.pagetemplate.engine import Engine
from zope.app.publication.browser \
     import PublicationTraverser
from zope.app.component.metaconfigure import handler

class GlobalBrowserMenuService:
    """Global Browser Menu Service
    """

    __implements__ = IBrowserMenuService

    def __init__(self):
        self._registry = {}

    _clear = __init__
        
    def menu(self, menu_id, title, description=''):
        # XXX we have nothing to do with the title and description. ;)

        if menu_id in self._registry:
            raise DuplicationError("Menu %s is already defined." % menu_id)

        self._registry[menu_id] = TypeRegistry()

    def menuItem(self, menu_id, interface,
                 action, title, description='', filter_string=None):

        registry = self._registry[menu_id]

        if filter_string:
            filter = Engine.compile(filter_string)
        else:
            filter = None

        data = registry.get(interface) or []
        data.append((action, title, description, filter))
        registry.register(interface, data)

    def getMenu(self, menu_id, object, request, max=999999):
        registry = self._registry[menu_id]
        traverser = PublicationTraverser()

        result = []
        seen = {}
        
        for items in registry.getAllForObject(object):
            for action, title, description, filter in items:

                # Make sure we don't repeat a specification for a given title
                if title in seen:
                    continue
                seen[title] = 1
                
                if filter is not None:
                    
                    try:
                        include = filter(Engine.getContext(
                            context = object,
                            nothing = None))
                    except Unauthorized:
                        include = 0

                    if not include:
                        continue
   
                if action:
                    try:
                        v = traverser.traverseRelativeURL(
                            request, object, action)
                        # XXX
                        # tickle the security proxy's checker
                        # we're assuming that view pages are callable
                        # this is a pretty sound assumption
                        v.__call__
                    except (Unauthorized, Forbidden):
                        continue # Skip unauthorized or forbidden

                if request.getURL().endswith(action):
                    selected='selected'
                else:
                    selected=''

                result.append({
                    'title': title,
                    'description': description,
                    'action': "%s" % action,
                    'selected': selected
                    })

                if len(result) >= max:
                    return result
        
        return result

    def getFirstMenuItem(self, menu_id, object, request):
        r = self.getMenu(menu_id, object, request, max=1)
        if r:
            return r[0]
        return None

def menuDirective(_context, id, title, description=''):
    return [Action(
        discriminator = ('browser:menu', id),
        callable = globalBrowserMenuService.menu,
        args = (id, title, description),
        )]

def menuItemDirective(_context, menu, for_,
                      action, title, description='', filter=None):
    return menuItemsDirective(_context, menu, for_).menuItem(
        _context, action, title, description, filter)        

    
class menuItemsDirective:

    __class_implements__ = INonEmptyDirective
    __implements__ = ISubdirectiveHandler

    def __init__(self, _context, menu, for_):
        self.menu = menu
        self.interface = _context.resolve(for_)

    def menuItem(self, _context, action, title, description='', filter=None):
        return [
            Action(
              discriminator = ('browser:menuItem',
                               self.menu, self.interface, title),
              callable = globalBrowserMenuService.menuItem,
              args = (self.menu, self.interface,
                      action, title, description, filter),
              ),
                ]
        
    def __call__(self):
        return [
            Action(
              discriminator = None,
              callable = handler,
              args = ('Interfaces', 'provideInterface',
                      self.interface.__module__+'.'+self.interface.__name__,
                      self.interface)
              )
            ]


globalBrowserMenuService = GlobalBrowserMenuService()

_clear = globalBrowserMenuService._clear

# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
from zope.testing.cleanup import addCleanUp
addCleanUp(_clear)
del addCleanUp

__doc__ = GlobalBrowserMenuService.__doc__ + """

$Id: globalbrowsermenuservice.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""


=== Added File Zope3/src/zope/app/publisher/browser/i18nfileresource.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
Internationalized file resource.

$Id: i18nfileresource.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from zope.publisher.interfaces.browser import IBrowserResource
from zope.publisher.interfaces.browser import IBrowserPublisher

from zope.app.publisher.fileresource import File, Image

from zope.app.publisher.browser.fileresource import FileResource

from zope.i18n.negotiator import negotiator
from zope.interfaces.i18n import II18nAware


class I18nFileResource(FileResource):

    __implements__ = IBrowserResource, IBrowserPublisher, II18nAware

    def __init__(self, data, request, defaultLanguage='en'):
        """Creates an internationalized file resource.  data should be
        a mapping from languages to File or Image objects.
        """
        self._data = data
        self.request = request
        self.defaultLanguage = defaultLanguage


    def chooseContext(self):
        """Choose the appropriate context according to language"""
        langs = self.getAvailableLanguages()
        language = negotiator.getLanguage(langs, self.request)
        try:
            return self._data[language]
        except KeyError:
            return self._data[self.defaultLanguage]


    # for unit tests
    def _testData(self, language):
        file = self._data[language]
        f=open(file.path,'rb')
        data=f.read()
        f.close()
        return data


    ############################################################
    # Implementation methods for interface
    # II18nAware.py

    def getDefaultLanguage(self):
        'See Zope.I18n.II18nAware.II18nAware'
        return self.defaultLanguage

    def setDefaultLanguage(self, language):
        'See Zope.I18n.II18nAware.II18nAware'
        if not self._data.has_key(language):
            raise ValueError, \
                  'cannot set nonexistent language (%s) as default' % language
        self.defaultLanguage = language

    def getAvailableLanguages(self):
        'See Zope.I18n.II18nAware.II18nAware'
        return self._data.keys()

    #
    ############################################################


class I18nFileResourceFactory:

    def __init__(self, data, defaultLanguage):
        self.__data = data
        self.__defaultLanguage = defaultLanguage

    def __call__(self, request):
        return I18nFileResource(self.__data, request, self.__defaultLanguage)



=== Added File Zope3/src/zope/app/publisher/browser/i18nresourcemeta.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Browser configuration code

$Id: i18nresourcemeta.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""

from zope.security.proxy import Proxy
from zope.security.checker \
     import CheckerPublic, NamesChecker, Checker

from zope.interfaces.configuration import ISubdirectiveHandler
from zope.interfaces.configuration import INonEmptyDirective
from zope.configuration.action import Action
from zope.configuration.exceptions import ConfigurationError

from zope.publisher.interfaces.browser import IBrowserPresentation

from zope.app.component.metaconfigure import handler

from zope.app.publisher.fileresource import File, Image
from zope.app.publisher.browser.i18nfileresource \
     import I18nFileResourceFactory

class I18nResource(object):

    __class_implements__ = INonEmptyDirective
    __implements__ = ISubdirectiveHandler

    type = IBrowserPresentation
    default_allowed_attributes = '__call__'

    def __init__(self, _context, name=None, defaultLanguage='en',
                 layer='default', permission=None):
        self.name = name
        self.defaultLanguage = defaultLanguage
        self.layer = layer
        self.permission = permission
        self.__data = {}
        self.__format = None


    def translation(self, _context, language, file=None, image=None):

        if file is not None and image is not None:
            raise ConfigurationError(
                "Can't use more than one of file, and image "
                "attributes for resource directives"
                )
        elif file is not None:
            if self.__format is not None and self.__format != File:
                raise ConfigurationError(
                    "Can't use both files and images in the same "
                    "i18n-resource directive"
                    )
            self.__data[language] = File(_context.path(file))
            self.__format = File
        elif image is not None:
            if self.__format is not None and self.__format != Image:
                raise ConfigurationError(
                    "Can't use both files and images in the same "
                    "i18n-resource directive"
                    )
            self.__data[language] = Image(_context.path(image))
            self.__format = Image
        else:
            raise ConfigurationError(
                "At least one of the file, and image "
                "attributes for resource directives must be specified"
                )

        return ()


    def __call__(self, require = None):
        if self.name is None:
            return ()

        if not self.__data.has_key(self.defaultLanguage):
            raise ConfigurationError(
                "A translation for the default language (%s) "
                "must be specified" % self.defaultLanguage
                )

        permission = self.permission
        factory = I18nFileResourceFactory(self.__data, self.defaultLanguage)

        if permission:
            if require is None:
                require = {}

            if permission == 'Zope.Public':
                permission = CheckerPublic

        if require:
            checker = Checker(require.get)

            factory = self._proxyFactory(factory, checker)

        return [
            Action(
                discriminator = ('i18n-resource', self.name, self.type,
                                 self.layer),
                callable = handler,
                args = ('Resources', 'provideResource', self.name, self.type,
                        factory, self.layer)
                )
            ]


    def _proxyFactory(self, factory, checker):
        def proxyView(request,
                      factory=factory, checker=checker):
            resource = factory(request)

            # We need this in case the resource gets unwrapped and
            # needs to be rewrapped 
            resource.__Security_checker__ = checker

            return Proxy(resource, checker)

        return proxyView


=== Added File Zope3/src/zope/app/publisher/browser/meta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
  
  <directives namespace="http://namespaces.zope.org/browser">

    <directive 
        name="view" 
        handler="zope.app.publisher.browser.metaconfigure.view" >
      <attribute
          name="name"
          description="The name of the view. 
 
              The name shows up in URLs/paths. For example 'foo' or 
              'foo.html'. This attribute is required unless you use the
              subdirective 'page' to create sub views. If you do not have
              sub pages, it is common to use an extension for the view name 
              such as '.html'. If you do have sub pages and you want to
              provide a view name, you shouldn't use extensions." />
       <attribute
          name="for"
          description="The interface this view applies to. 

              The view will be for all objects that implement this interface.
              If 'for' is not supplied, the view applies to all objects 
              (XXX this ought to change)." />
      <attribute
          name="factory"
          description="A callable that realizes the view. 

              The view factory interface is documented in IViewFactory. View
              factories are passed two arguments, the context object
              and the request object. You must specify either 'factory' or 
              'template'. If it not allowed to use 'class' when you use
              the 'factory' attribute. Attributes of the view can be exposed 
              as pages with the 'page' subdirective." />
       <attribute
          name="template"
          description="The name of a page template.

              Refers to a file containing a page template (must end in
              extension '.pt'). You must specify either 'template' or
              'factory'. If you supply a template, you must
              also supply a name. You can also optionally supply a
              'class' attribute which contains a view class that has
              methods that can be used by the template.

              You cannot have sub pages if you use 'template'." />
       <attribute
          name="class"
          description="A class to use with the template.

              If you use the 'template' attribute you can optionally use
              the 'class' attribute. This should point to a class that
              provides methods that can be used in the template. This class
              will be mixed in with the page template. From the template
              you can refer to the methods using 'view/method_name'.
    
              You cannot use the 'class' attribute in combination with the
              'factory' attribute." />
       <attribute
          name="permission" 
          description="The permission needed to use the view. 

              This attribute is required." />
       <attribute
          name="layer"
          description="The layer the view is in. 

              A skin is composed of layers. It is common to put skin specific
              views in a layer named after the skin. If the 'layer' attribute
              is not supplied, it defaults to 'default'." />
       <attribute
          name="allowed_interface"
          description="Interface that is also allowed if user has permission.

              By default, 'permission' only applies to viewing the view and 
              any possible sub views. By specifying this attribute, you can
              make the permission also apply to everything described in the 
              supplied interface." />
       <attribute
          name="allowed_attributes"
          description="View attributes that are also allowed if user has permission.

              By default, 'permission' only applies to viewing the view and any
              possible sub views. By specifying 'allowed_attributes', you can
              make the permission also apply to the extra attributes on the 
              view object." />
       <subdirective name="page">
         <attribute
             name="name" 
             description="The name of a sub page of a view.

                 The name attribute is always required for the 'page'
                 directive. It is common to use an extension for the name, 
                 such as '.html'." />
         <attribute
             name="attribute"
             description="The name of the view attribute implementing the page.

                 This refers to the attribute (method) on the view that is 
                 implementing a specific sub page." />
         <attribute
             name="permission"
             description="The permission needed to use this page.
 
                 XXX Should we deprecate this? Could always be the same as
                 the main view." />
         <attribute
             name="layer" 
             description="XXX deprecated" />
       </subdirective>
       <subdirective name="defaultPage">
         <attribute
             name="name"
             description="The name of the page that is the default.

                 The named page will be used as the default if no name is
                 specified explicitly in the path. If no defaultPage 
                 directive is supplied, the default page will be the
                 first page listed." />
         <attribute
             name="attribute"
             description="XXX deprecated" />
         <attribute
             name="permission"
             description="XXX deprecated" />
       </subdirective>
    </directive>

    <directive 
       name="defaultView" 
       handler="zope.app.publisher.browser.metaconfigure.defaultView">
      <attribute
          name="name" 
          description="The name of the view that should be the default.
              
              This name refers to another view that should be the
              view used by default (if no view name is supplied
              explicitly)." />
       <attribute
          name="for"
          description="The interface this view is the default for.

              The view is the default view for the supplied interface." />
       <attribute
          name="layer"
          description="The layer the named view is the default view.

              The named view is only the default view in the supplied
              layer" />
      <attribute
          name="factory"
          description="XXX deprecated" />
       <attribute
          name="template"
          description="XXX deprecated" />
       <attribute
          name="permission"
          description="XXX deprecated" />
       <attribute
          name="allowed_interface" 
          description="XXX deprecated" />
       <attribute
          name="allowed_attributes"
          description="XXX deprecated" />
    </directive>

    <directive
        name="resource"
        handler="zope.app.publisher.browser.metaconfigure.resource">
      <attribute
          name="name" />
      <attribute
          name="factory" />
       <attribute
          name="layer" />
       <attribute
          name="file" />
       <attribute
          name="image" />
       <attribute
          name="permission" />
       <attribute
          name="allowed_interface" />
       <attribute
          name="allowed_attributes" />
       <subdirective name="page"> 
         <attribute
             name="name" />
         <attribute
             name="attribute" />
         <attribute
             name="permission" />
         <attribute
             name="layer" />
       </subdirective>
    </directive>

    <directive
        name="i18n-resource"
        attributes="name default_language"
        handler="zope.app.publisher.browser.metaconfigure.I18nResource">
      <attribute
          name="name" />
      <attribute
          name="default_language" />
      <subdirective name="translation">
        <attribute
            name="language" />
        <attribute
            name="file" />
        <attribute
            name="image" />
      </subdirective>
    </directive>

    <directive
        name="skin"
        handler="zope.app.publisher.browser.metaconfigure.skin">
      <attribute
          name="name"
          description="The name of the skin." />
      <attribute
          name="layers"
          description="A list of names of layers. 

              This should be in order of lookup. Usually one of the layers
              has the same name as the skin, and the last skin should be
              'default', unless you want to completely override all views." />
    </directive>

    <directive
        name="menu"
        handler="
            Zope.App.Publisher.Browser.GlobalBrowserMenuService.menuDirective">
      <attribute
          name="name" />
      <attribute
          name="title" />
      <attribute
          name="description" />
    </directive>

    <directive
        name="menuItems"
        attributes="menu for" 
        handler="
        Zope.App.Publisher.Browser.GlobalBrowserMenuService.menuItemsDirective"
    >
      <subdirective
          name="menuItem" 
      >
        <attribute
            name="action" />
        <attribute
            name="title" />
        <attribute
            name="description" />
        <attribute
            name="filter" />
       </subdirective> 
    </directive>

    <directive 
        name="menuItem" 
        handler="
        Zope.App.Publisher.Browser.GlobalBrowserMenuService.menuItemDirective"
    >
      <attribute
          name="menu" />
      <attribute
          name="for" />
      <attribute
          name="action" />
      <attribute
          name="title" />
      <attribute
          name="description" />
      <attribute
          name="filter" />
    </directive>

    <directive
        name="icon"
        handler="zope.app.interfaces.publisher.browser.IconDirective"
    >
      <attribute
          name="name" />
      <attribute
          name="for" />
      <attribute
          name="file" />
      <attribute
          name="resource" />
      <attribute
          name="alt" />
      <attribute
          name="layer" />
    </directive>

  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/app/publisher/browser/metaconfigure.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Browser configuration code

$Id: metaconfigure.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""

from zope.configuration.action import Action

from zope.publisher.interfaces.browser import IBrowserPresentation

from zope.app.component.metaconfigure \
     import defaultView as _defaultView, skin as _skin, handler

from zope.app.publisher.browser.resourcemeta import resource
from zope.app.publisher.browser.i18nresourcemeta import I18nResource
from zope.app.publisher.browser.viewmeta import view
from zope.interface import Interface

def skin(_context, **__kw):
    return _skin(_context,
                 type='Zope.Publisher.Browser.IBrowserPresentation.',
                 **__kw)

def defaultView(_context, name, for_=None, **__kw):

    if __kw:
        actions = view(_context, name=name, for_=for_, **__kw)()
    else:
        actions = []

    if for_ is not None:
        for_ = _context.resolve(for_)

    type = IBrowserPresentation

    actions += [
        Action(
        discriminator = ('defaultViewName', for_, type, name),
        callable = handler,
        args = ('Views','setDefaultViewName', for_, type, name),
        )
        ]
    if for_ is not None:
        actions.append
        (
        Action(
        discriminator = None,
        callable = handler,
        args = ('Interfaces', 'provideInterface',
                for_.__module__+'.'+for_.__name__,
                for_)
              )
        )
        

    return actions


=== Added File Zope3/src/zope/app/publisher/browser/resource.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""

$Id: resource.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from zope.component import queryView
from zope.proxy.context.context import getWrapperContainer, getInnerWrapperData
from zope.proxy.context import ContextMethod

class Resource:

    def __init__(self, request):
        self.request = request

    def __call__(wrapped_self):
        name = getInnerWrapperData(wrapped_self)['name']
        if name.startswith('++resource++'):
            name = name[12:]

        service = getWrapperContainer(wrapped_self)
        site = getWrapperContainer(service)

        skin = wrapped_self.request.getPresentationSkin()
        if skin:
            skin = "++skin++%s/" % skin

        if site is None:
            return "/%s@@/%s" % (skin, name)

        absolute_url = queryView(service,
                                 'absolute_url',
                                 wrapped_self.request)

        if absolute_url is None:
            return "/%s@@/%s" % (skin, name)

        site_url = absolute_url()
        
        return "%s/%s@@/%s" % (site_url, skin, name)

    __call__ = ContextMethod(__call__)


=== Added File Zope3/src/zope/app/publisher/browser/resourcemeta.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Browser configuration code

$Id: resourcemeta.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""

from zope.security.proxy import Proxy
from zope.security.checker \
     import CheckerPublic, NamesChecker, Checker

from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import ISubdirectiveHandler
from zope.configuration.action import Action
from zope.configuration.exceptions import ConfigurationError

from zope.publisher.interfaces.browser import IBrowserPresentation

from zope.app.component.metaconfigure import handler

from zope.app.publisher.browser.fileresource \
     import FileResourceFactory, ImageResourceFactory

class resource(object):

    __class_implements__ = INonEmptyDirective
    __implements__ = ISubdirectiveHandler

    type = IBrowserPresentation
    default_allowed_attributes = '__call__'  # space separated string

    def __init__(self, _context, factory=None, name=None, layer='default',
                 permission=None,
                 allowed_interface=None, allowed_attributes=None,
                 file=None, image=None):

        if ((allowed_attributes or allowed_interface)
            and ((name is None) or not permission)):
            raise ConfigurationError(
                "Must use name attribute with allowed_interface or "
                "allowed_attributes"
                )

        if allowed_interface is not None:
            allowed_interface = _context.resolve(allowed_interface)

        self.__file = file
        self.__image = image

        self.factory = self._factory(_context, factory)
        self.layer = layer
        self.name = name
        self.permission = permission
        self.allowed_attributes = allowed_attributes
        self.allowed_interface = allowed_interface
        self.pages = 0

    def _factory(self, _context, factory):
        if ((factory is not None)
            + (self.__file is not None)
            + (self.__image is not None)
            ) > 1:
            raise ConfigurationError(
                "Can't use more than one of factory, file, and image "
                "attributes for resource directives"
                )
            
        if factory is not None:
            return _context.resolve(factory)

        if self.__file is not None:
            return FileResourceFactory(_context.path(self.__file))

        if self.__image is not None:
            return ImageResourceFactory(_context.path(self.__image))

        raise ConfigurationError(
            "At least one of the factory, file, and image "
            "attributes for resource directives must be specified"
            )
        

    def page(self, _context, name, attribute, permission=None,
             layer=None, factory=None):

        permission = permission or self.permission

        factory = self._pageFactory(factory or self.factory,
                                    attribute, permission)

        self.pages += 1

        if layer is None:
            layer = self.layer

        return [
            Action(
                discriminator = self._discriminator(name, layer),
                callable = handler,
                args = self._args(name, factory, layer),
                )
            ]

    def _discriminator(self, name, layer):
        return ('resource', name, self.type, layer)

    def _args(self, name, factory, layer):
        return ('Resources', 'provideResource',
                name, self.type, factory, layer)
        
    def _pageFactory(self, factory, attribute, permission):
        if permission:
            if permission == 'Zope.Public':
                permission = CheckerPublic

            def pageView(request,
                         factory=factory, attribute=attribute,
                         permission=permission):
                return Proxy(getattr(factory(request), attribute),
                             NamesChecker(__call__ = permission))

        else:

            def pageView(request,
                         factory=factory, attribute=attribute):
                return getattr(factory(request), attribute)

        return pageView

    def __call__(self, require=None):
        if self.name is None:
            return ()

        permission = self.permission
        allowed_interface = self.allowed_interface
        allowed_attributes = self.allowed_attributes
        factory = self.factory

        if permission:
            if require is None:
                require = {}
                
            if permission == 'Zope.Public':
                permission = CheckerPublic
            
            if ((not allowed_attributes) and (allowed_interface is None)
                and (not self.pages)):
                allowed_attributes = self.default_allowed_attributes

            for name in (allowed_attributes or '').split():
                require[name] = permission

            if allowed_interface:
                for name in allowed_interface.names(1):
                    require[name] = permission

        if require:
            checker = Checker(require.get)

            factory = self._proxyFactory(factory, checker)


        return [
            Action(
                discriminator = self._discriminator(self.name, self.layer),
                callable = handler,
                args = self._args(self.name, factory, self.layer),
                )
            ]

    def _proxyFactory(self, factory, checker):
        def proxyView(request,
                      factory=factory, checker=checker):
            resource = factory(request)

            # We need this in case the resource gets unwrapped and
            # needs to be rewrapped 
            resource.__Security_checker__ = checker

            return Proxy(resource, checker)

        return proxyView


=== Added File Zope3/src/zope/app/publisher/browser/resources.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Resource URL acess

$Id: resources.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""
__metaclass__ = type # All classes are new style when run with Python 2.2+

from zope.publisher.browser import BrowserView
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.component import getService
from zope.proxy.context.context import ContextWrapper
from zope.proxy.context import ContextMethod
from zope.exceptions import NotFoundError

class Resources(BrowserView):
    """Provide a URL-accessible resource namespace
    """

    __implements__ = BrowserView.__implements__, IBrowserPublisher

    ############################################################
    # Implementation methods for interface
    # Zope.Publisher.Browser.IBrowserPublisher.

    def publishTraverse(wrapped_self, request, name):
        '''See interface IBrowserPublisher'''
        
        resource_service = getService(wrapped_self, 'Resources')
        resource = resource_service.queryResource(wrapped_self, name, request)
        if resource is None:
            raise NotFoundError(wrapped_self, name)
        return ContextWrapper(resource, resource_service)

    publishTraverse = ContextMethod(publishTraverse)

    def browserDefault(self, request):
        '''See interface IBrowserPublisher'''
        return empty, ()
        
    #
    ############################################################

def empty():
    return ''


=== Added File Zope3/src/zope/app/publisher/browser/viewmeta.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""Browser configuration code

$Id: viewmeta.py,v 1.1.2.1 2002/12/23 19:32:02 jim Exp $
"""

# XXX this will need to be refactored soon. :)

from zope.security.proxy import Proxy
from zope.security.checker import CheckerPublic, NamesChecker

from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import ISubdirectiveHandler
from zope.configuration.action import Action
from zope.configuration.exceptions import ConfigurationError

from zope.publisher.interfaces.browser import IBrowserPresentation
from zope.publisher.interfaces.browser import IBrowserPublisher

from zope.app.component.metaconfigure import handler

from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
from Zope.App.PageTemplate import ViewPageTemplateFile

from zope.app.publisher.browser.resourcemeta import resource

from zope.proxy.context import ContextMethod

class view(resource):

    __class_implements__ = INonEmptyDirective
    __implements__ = ISubdirectiveHandler

    __pages = None
    __default = None

    def __init__(self, _context, factory=None, name=None, for_=None,
                 layer='default',
                 permission=None,
                 allowed_interface=None, allowed_attributes=None,
                 template=None, class_=None):

        if class_ and factory:
            raise ConfigurationError("Can't specify a class and a factory")

            
        factory = factory or class_

        if template:
            if name is None:
                raise ConfigurationError(
                    "Must specify name for template view")

            self.default_allowed_attributes = (
                '__call__ __getitem__ browserDefault')

            template = _context.path(template)

        self.template = template

        if for_ is not None:
            for_ = _context.resolve(for_)
        self.for_ = for_
        
        resource.__init__(self, _context, factory, name, layer,
                          permission, allowed_interface, allowed_attributes)

        if name:
            self.__pages = {}


    def page(self, _context, name, attribute=None, permission=None,
             layer=None, template=None):


        if self.template:
            raise ConfigurationError(
                "Can't use page or defaultPage subdirectives for simple "
                "template views")


        if self.name:
            # Named view with pages.

            if layer is not None:
                raise ConfigurationError(
                    "Can't specify a separate layer for pages of named "
                    "templates.")
            
            if template is not None:
                template = _context.path(template)

            self.__pages[name] = attribute, permission, template
            if self.__default is None:
                self.__default = name

            # Call super(view, self).page() in order to get the side
            # effects. (At the time of writing, this is to increment
            # self.pages by one.)
            # Throw away the result, as all the pages are accessed by
            # traversing the PageTraverser subclass.
            super(view, self).page(_context, name, attribute)
            return ()

        factory = self.factory

        if template is not None:
            attribute = attribute or '__template__'
            klass = factory[-1]
            klass = type(klass.__name__, (klass, object), {
                attribute:
                ViewPageTemplateFile(_context.path(template))
                })
            factory = factory[:]
            factory[-1] = klass

        return super(view, self).page(
            _context, name, attribute, permission, layer,
            factory=factory)

    def defaultPage(self, _context, name):
        if self.name:
            self.__default = name
            return ()

        return [Action(
            discriminator = ('defaultViewName', self.for_, self.type, name),
            callable = handler,
            args = ('Views','setDefaultViewName', self.for_, self.type, name),
            )]
    

    def _factory(self, _context, factory):

        if self.template:
            

            if factory:
                factory = map(_context.resolve, factory.strip().split())
                bases = (factory[-1], )
                klass = SimpleViewClass(
                    str(_context.path(self.template)),
                    used_for=self.for_, bases=bases
                    )
                factory[-1] = klass
                return factory
                
            return [SimpleViewClass(
                str(_context.path(self.template)),
                used_for = self.for_
                )]

        else:
            return map(_context.resolve, factory.strip().split())

    def _discriminator(self, name, layer):
        return ('view', self.for_, name, self.type, layer)

    def _args(self, name, factory, layer):
        return ('Views', 'provideView',
                self.for_, name, self.type, factory, layer)

    def _pageFactory(self, factory, attribute, permission):

        factory = factory[:]        
        
        if permission:
            if permission == 'Zope.Public':
                permission = CheckerPublic

            def pageView(context, request,
                         factory=factory[-1], attribute=attribute,
                         permission=permission):
                return Proxy(getattr(factory(context, request), attribute),
                             NamesChecker(__call__ = permission))

        else:

            def pageView(context, request,
                         factory=factory[-1], attribute=attribute):
                return getattr(factory(context, request), attribute)

        factory[-1] = pageView

        return factory

    def _proxyFactory(self, factory, checker):

        factory = factory[:]        

        def proxyView(context, request,
                      factory=factory[-1], checker=checker):

            view = factory(context, request)

            # We need this in case the resource gets unwrapped and
            # needs to be rewrapped
            view.__Security_checker__ = checker

            return Proxy(view, checker)

        factory[-1] =  proxyView

        return factory

    def __call__(self):
        if not self.__pages:
            return super(view, self).__call__()

        # OK, we have named pages on a named view.
        # We'll replace the original class with a new subclass that
        # can traverse to the necessary pages. 

        require = {}

        factory = self.factory[:]
        klass = factory[-1]

        klassdict = {'_PageTraverser__pages': {},
                     '_PageTraverser__default': self.__default,
                     '__implements__':
                     (klass.__implements__, PageTraverser.__implements__),
                     }
        for name in self.__pages:
            attribute, permission, template = self.__pages[name]

            # We need to set the default permission on pages if the pages
            # don't already have a permission explicitly set
            permission = permission or self.permission
            if permission == 'Zope.Public':
                permission = CheckerPublic

            if not attribute:
                attribute = name

            require[attribute] = permission

            if template:
                klassdict[attribute] = ViewPageTemplateFile(template)

            klassdict['_PageTraverser__pages'][name] = attribute, permission

        klass = type(klass.__name__,
                     (klass, PageTraverser, object),
                     klassdict)
        factory[-1] = klass
        self.factory = factory

        permission_for_browser_publisher = self.permission
        if permission_for_browser_publisher == 'Zope.Public':
            permission_for_browser_publisher = CheckerPublic
        for name in IBrowserPublisher.names(all=1):
            require[name] = permission_for_browser_publisher
       
        return super(view, self).__call__(require=require)


class PageTraverser:

    __implements__ = IBrowserPublisher

    def publishTraverse(self, request, name):
        attribute, permission = self._PageTraverser__pages[name]
        return Proxy(getattr(self, attribute),
                     NamesChecker(__call__=permission)
                     )
    publishTraverse = ContextMethod(publishTraverse)

    def browserDefault(self, request):
        return self, (self._PageTraverser__default, )
    browserDefault = ContextMethod(browserDefault)


def defaultView(_context, name, for_=None, **__kw):

    if __kw:
        actions = view(_context, name=name, for_=for_, **__kw)()
    else:
        actions = []

    if for_ is not None:
        for_ = _context.resolve(for_)

    type = IBrowserPresentation

    actions += [
        Action(
        discriminator = ('defaultViewName', for_, type, name),
        callable = handler,
        args = ('Views','setDefaultViewName', for_, type, name),
        )]

    if for_ is not None:
        actions += [
        Action(
        discriminator = None,
        callable = handler,
        args = ('Interfaces', 'provideInterface',
                for_.__module__+'.'+for_.__name__,
                for_)
        )
        ]

    return actions