[Zope3-checkins] CVS: Zope3/src/zope/component - presentation.py:1.2 resource.py:NONE skin.py:NONE view.py:NONE

Jim Fulton cvs-admin at zope.org
Fri Nov 21 12:09:57 EST 2003


Update of /cvs-repository/Zope3/src/zope/component
In directory cvs.zope.org:/tmp/cvs-serv29530/src/zope/component

Added Files:
	presentation.py 
Removed Files:
	resource.py skin.py view.py 
Log Message:
Implemented a new presentation service that replaces the old view,
resource and skin services.


=== Zope3/src/zope/component/presentation.py 1.1 => 1.2 ===
--- /dev/null	Fri Nov 21 12:09:57 2003
+++ Zope3/src/zope/component/presentation.py	Fri Nov 21 12:09:26 2003
@@ -0,0 +1,433 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""XXX short summary goes here.
+
+XXX longer description goes here.
+
+$Id$
+"""
+
+from zope.component.interfaces import IPresentationService
+from zope.component.servicenames import Presentation
+from zope.component.service import GlobalService
+import zope.interface
+from zope.interface.interfaces import IInterface
+import zope.schema
+import zope.interface.surrogate
+from types import ClassType
+
+
+class IGlobalPresentationService(zope.interface.Interface):
+    """Provide abaility to update the flobal presentation service
+    """
+
+    def defineSkin(name, layers):
+        """Define a skin
+
+        A skin is defined for a request type.  It consists of a
+        sequence of layer names.  Layers must be defined before they
+        are used in a skin definition.
+
+        Note that there is one predefined layer, "default".
+        """
+
+    def setDefaultSkin(name):
+        """Set the default skin for a request type
+
+        If not set, it defaults to the "default" skin.
+        """
+
+    def defineLayer(name):
+        """Define a layer
+        """
+
+    def provideAdapter(request_type, factories, name='', contexts=(),
+                       providing=zope.interface.Interface, layer='default'):
+        """Provide a presentation adapter
+        """
+
+class IDefaultViewName(zope.interface.Interface):
+    """A string that contains the default view name
+
+    A default view name is used to select a view when a user hasn't
+    specified one.
+    """
+
+class GlobalPresentationService(GlobalService):
+    """Global presentation service
+
+       The global presentation service provides management of views, and
+       resources arranged in skins, where skins are ordered collections
+       of layers.
+
+       Views are modeled as adapters of objects and requests.
+       Resources are just request adapters.
+
+       The adapters are arranged in layers.
+
+       Let's look at some examples. First, we'll create a service:
+
+       >>> s = GlobalPresentationService()
+
+       And define a custom layer and skin:
+
+       >>> s.defineLayer('custom')
+       >>> s.defineSkin('custom', ['custom', 'default'])
+
+       We'll define a request type and a fake request:
+
+       >>> class IRequest(zope.interface.Interface):
+       ...     "Demonstration request type"
+
+       >>> class Request:
+       ...     zope.interface.implements(IRequest)
+       ...     def getPresentationSkin(self):
+       ...         return getattr(self, 'skin', None)
+
+
+       >>> request = Request()
+
+       With this in place, we can start registering resources. A resource
+       is just a request adapter.
+
+       >>> class MyResource:
+       ...    def __init__(self, request):
+       ...        self.request = request
+
+       To register a resource, we register it as an adapter. Most
+       resources are going to interface with a user, and, so, don't
+       really provide a programatic interface. For this reason, we
+       register them to provide the empty interface, Interface, which is
+       the default provided interface:
+
+       >>> s.provideAdapter(IRequest, [MyResource], name='foo', layer='custom')
+
+       Now we can try to look this up:
+
+       >>> s.queryResource('foo', request)
+
+       But we won't get anything, because our request doesn't specify a
+       skin and, the default skin gets used.  Our resource was registered
+       in the custom layer, which isn't used by the default skin. If we
+       set out request skin to 'custom':
+
+       >>> request.skin = 'custom'
+
+       Then the lookup will suceed:
+
+       >>> r = s.queryResource('foo', request)
+       >>> r.__class__.__name__
+       'MyResource'
+       >>> r.request is request
+       True
+
+       Views are registered as "multi" adapters.  Multi-adapters adapt
+       multiple objects simultaneously.
+
+       >>> class IContact(zope.interface.Interface):
+       ...     "Demonstration content type"
+
+       >>> class MyView:
+       ...     def __init__(self, context, request):
+       ...         self.context, self.request = context, request
+
+       >>> s.provideAdapter(IRequest, [MyView], contexts=[IContact], 
+       ...                  name='foo', layer='custom')
+
+       When defining views, we provide one or more (typically 1) context
+       interfaces, corresponding to the contexts of the view.
+
+       >>> class Contact:
+       ...     zope.interface.implements(IContact)
+
+       >>> c = Contact()
+
+       We look up views with queryView:
+
+       >>> v = s.queryView(c, 'foo', request)
+       >>> v.__class__.__name__
+       'MyView'
+       >>> v.request is request
+       True
+       >>> v.context is c
+       True
+
+       Most views and resources are unnamed and provide no interface. We
+       can also have views that provide interfaces.  For example, we
+       might need a view to help out with finding objects:
+
+       >>> class ITraverse(zope.interface.Interface):
+       ...     "Sample traversal interface (imagine interesting methods :)"
+
+       >>> class Traverser:
+       ...     zope.interface.implements(ITraverse)
+       ...     def __init__(self, context, request):
+       ...         self.context, self.request = context, request
+
+       which we register using the provided interface, rather than a name. 
+
+       >>> s.provideAdapter(IRequest, [Traverser], contexts=[IContact],
+       ...                  providing=ITraverse, layer='custom')
+
+       (We could use a name too, if we wanted to.)
+
+       Then we look up the view using the interface:
+
+       >>> v = s.queryView(c, '', request, providing=ITraverse)
+       >>> v.__class__.__name__
+       'Traverser'
+       >>> v.request is request
+       True
+       >>> v.context is c
+       True
+       """
+
+    zope.interface.implements(IPresentationService, IGlobalPresentationService)
+    
+    def __init__(self):
+        self._layers = {'default': GlobalLayer(self, 'default')}
+        self._skins = {'default': [self._layers['default']]}
+        self.skins = {'default': ('default', )}
+        self.defaultSkin = 'default'
+
+    def defineSkin(self, name, layers):
+        """Define a skin
+
+        A skin is defined for a request type.  It consists of a
+        sequence of layer names.  Layers must be defined before they
+        are used in a skin definition.
+
+        Note that there is one predefined layer, "default".
+
+        >>> s = GlobalPresentationService()
+        >>> s.defineSkin('default', ['default'])
+        Traceback (most recent call last):
+        ...
+        ValueError: ("Can\'t redefine skin", 'default')
+
+
+        The layers used in a skin definition must be defined before
+        they are used:
+
+        >>> s.defineSkin('custom', ['custom', 'default'])
+        Traceback (most recent call last):
+        ...
+        ValueError: ('Undefined layers', ['custom'])
+
+
+        >>> s.defineLayer('custom')
+        >>> s.defineSkin('custom', ['custom', 'default'])
+
+        >>> skins = s.skins.items()
+        >>> skins.sort()
+        >>> skins
+        [('custom', ('custom', 'default')), ('default', ('default',))]
+        """
+
+        if name in self._skins:
+            raise ValueError("Can't redefine skin", name)
+
+        bad = [layer for layer in layers if layer not in self._layers]
+        if bad:
+            raise ValueError, ("Undefined layers", bad)
+
+        self._skins[name] = [self._layers[layer] for layer in layers]
+        self.skins[name] = tuple(layers)
+
+    def querySkin(self, name):
+        return self.skins.get(name)
+
+    def queryLayer(self, name):
+        return self._layers.get(name)
+
+    def setDefaultSkin(self, name):
+        """Set the default skin for a request type
+
+        If not set, it defaults to the "default" skin.
+
+        >>> s = GlobalPresentationService()
+        >>> s.defaultSkin
+        'default'
+
+        >>> s.setDefaultSkin('custom')
+        Traceback (most recent call last):
+        ...
+        ValueError: ('Undefined skin', 'custom')
+
+        >>> s.defineLayer('custom')
+        >>> s.defineSkin('custom', ['custom', 'default'])
+        >>> s.setDefaultSkin('custom')
+        >>> s.defaultSkin
+        'custom'
+
+        """
+
+        # Make sure we are refering to a defined skin
+        if name not in self._skins:
+            raise ValueError, ("Undefined skin", name)
+
+        self.defaultSkin = name
+
+    def defineLayer(self, name):
+        """Define a layer
+
+        >>> s = GlobalPresentationService()
+        >>> s.defineLayer('custom')
+
+        You can't define a layer that's already defined:
+        
+        >>> s.defineLayer('custom')
+        Traceback (most recent call last):
+        ...
+        ValueError: ("Can\'t redefine layer", 'custom')
+
+        """
+
+        if name in self._layers:
+            raise ValueError("Can\'t redefine layer", name)
+
+        self._layers[name] = GlobalLayer(self, name)
+
+    def provideAdapter(self, request_type, factories, name=u'', contexts=(), 
+                       providing=zope.interface.Interface, layer='default'):
+        """Provide a presentation adapter
+
+        This is a fairly low-level interface that supports both
+        resources and views.
+        
+        """
+
+        ifaces = []
+        for context in contexts:
+            if not IInterface.isImplementedBy(context) and context is not None:
+                if not isinstance(context, (type, ClassType)):
+                    raise TypeError(context, IInterface)
+                context = zope.interface.implementedBy(context)
+
+            ifaces.append(context)
+            
+        ifaces.append(request_type)
+        
+        reg = self._layers[layer]
+        reg.provideAdapter(ifaces[0], providing, factories, name, ifaces[1:])
+
+    def queryResource(self, name, request, default=None):
+        """Look up a named resource for a given request
+        
+        The request must implement IPresentationRequest.
+        
+        The default will be returned if the component can't be found.
+        """
+        skin = request.getPresentationSkin() or self.defaultSkin
+        for layer in self._skins[skin]:
+            r = layer.queryNamedAdapter(request, zope.interface.Interface,
+                                        name)
+            if r is not None:
+                return r
+        return default
+
+    def queryView(self, object, name, request,
+                  providing=zope.interface.Interface, default=None):
+        """Look for a named view for a given object and request
+
+        The request must implement IPresentationRequest.
+
+        The default will be returned if the component can't be found.
+        """
+        skin = request.getPresentationSkin() or self.defaultSkin
+        objects = object, request
+        for layer in self._skins.get(skin, ()):
+            r = layer.queryMultiAdapter(objects, providing, name)
+            if r is not None:
+                return r
+        return default
+        
+
+    def queryMultiView(self, objects, name, request,
+                       providing=zope.interface.Interface, default=None):
+        """Adapt the given objects and request
+
+        The first argument is a sequence of objects to be adapted with the
+        request.
+        """
+        skin = request.getPresentationSkin() or self.defaultSkin
+        objects = objects + (request, )
+        for layer in self._skins[skin]:
+            r = layer.queryMultiAdapter(objects, providing, name)
+            if r is not None:
+                return r
+        return default
+
+    ############################################################
+    #
+    # The following methods are provided for convenience and for
+    # backward compatability with old code:
+
+    def provideView(self, for_, name, type, maker, layer='default'):
+        # Helper function for simple view defs
+        if not isinstance(maker, (list, tuple)):
+            maker = [maker]
+        return self.provideAdapter(type, maker, name,
+                                   contexts=[for_], layer=layer)
+
+
+    def setDefaultViewName(self, for_, request_type, name, layer="default"):
+        """Default view names
+
+        A default view name is a name that an application should use
+        if a user hasn't selected one.  This should not be confused
+        with unnamed views.
+
+        The presentation service can store this by storing the name as
+        an "adapter".
+        """
+        return self.provideAdapter(request_type, name,
+                                   providing=IDefaultViewName,
+                                   contexts=[for_], layer=layer)
+
+    def queryDefaultViewName(self, object, request, default=None):
+        skin = request.getPresentationSkin() or 'default'
+        objects = object, request
+        for layer in self._skins[skin]:
+            r = layer.queryMultiAdapter(objects, IDefaultViewName, raw=True)
+            if r is not None:
+                return r
+        return default
+
+    def provideResource(self, name, request_type, factory, layer='default'):
+        # Helper function for simple view defs
+        if not isinstance(factory, (list, tuple)):
+            factory = [factory]
+        return self.provideAdapter(request_type, factory, name, layer=layer)
+
+    def getRegisteredMatching(self, layers=None, **kw):
+        if layers is None:
+            layers = self._layers.keys()
+            layers.sort()
+        for layername in layers:
+            layer = self._layers[layername]
+
+
+def GL(presentation_service, layer_name):
+    return presentation_service.queryLayer(layer_name)
+
+class GlobalLayer(zope.interface.surrogate.SurrogateRegistry):
+
+    def __init__(self, parent, name):
+        zope.interface.surrogate.SurrogateRegistry.__init__(self)
+        self.__parent__ = parent
+        self.__name__ = name
+
+    def __reduce__(self):
+        return GL, (self.__parent__, self.__name__)

=== Removed File Zope3/src/zope/component/resource.py ===

=== Removed File Zope3/src/zope/component/skin.py ===

=== Removed File Zope3/src/zope/component/view.py ===




More information about the Zope3-Checkins mailing list