vendor/Five/1.2b-r20590

view viewable.py @ 0:3673ed425f80

Vendor import of Five 1.2b+ (r20590)
author fguillaume
date Fri, 02 Dec 2005 20:25:42 +0000
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2004, 2005 Zope Corporation and Contributors.
4 # All Rights Reserved.
5 #
6 # This software is subject to the provisions of the Zope Public License,
7 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11 # FOR A PARTICULAR PURPOSE.
12 #
13 ##############################################################################
14 """Machinery for making things viewable
16 $Id: viewable.py 19645 2005-11-08 15:45:35Z yuppie $
17 """
18 import inspect
19 from zExceptions import NotFound
20 from zope.exceptions import NotFoundError
21 from zope.component import getDefaultViewName, ComponentLookupError
22 from zope.interface import implements
23 from zope.publisher.interfaces.browser import IBrowserRequest
25 from Products.Five.traversable import FakeRequest
26 from Products.Five.interfaces import IBrowserDefault
28 _marker = object
30 class Viewable:
31 """A mixin to make an object viewable.
32 """
33 __five_viewable__ = True
35 def __fallback_default__(self, request):
36 """Try to dispatch to existing index_html or __call__"""
37 if getattr(self, 'index_html', None):
38 return self, ('index_html',)
39 if getattr(self, 'fallback_call__', None):
40 return self, ('fallback_call__',)
41 # XXX Should never get this far. But if it does?
43 # def fallback_call__(self, *args, **kw):
44 # """By default, return self"""
45 # return self
47 # we have a default view, tell zpublisher to go there
48 def __browser_default__(self, request):
49 obj = self
50 path = None
51 if request['REQUEST_METHOD'] not in ('GET', 'POST'):
52 return obj, [request['REQUEST_METHOD']]
53 try:
54 obj, path = IBrowserDefault(self).defaultView(request)
55 except ComponentLookupError:
56 pass
57 if path:
58 if len(path) == 1 and path[0] == '__call__':
59 return obj, ('fallback_call__',)
60 return obj, path
61 return self.__fallback_default__(request)
62 __browser_default__.__five_method__ = True
64 # this is technically not needed because ZPublisher finds our
65 # attribute through __browser_default__; but we also want to be
66 # able to call pages from python modules, PythonScripts or ZPT
67 # def __call__(self, *args, **kw):
68 # """ """
69 # request = kw.get('REQUEST')
70 # if not IBrowserRequest.providedBy(request):
71 # request = getattr(self, 'REQUEST', None)
72 # if not IBrowserRequest.providedBy(request):
73 # request = FakeRequest()
74 # obj, path = self.__browser_default__(request)
75 # if path and not simpleRecursion():
76 # meth = obj.unrestrictedTraverse(path)
77 # if meth is not None:
78 # return meth(*args, **kw)
79 # return self.fallback_call__(*args, **kw)
80 # __call__.__five_method__ = True
82 # def simpleRecursion():
83 # # This tests for simple recursion, which can easily happen
84 # # in CMF, like the following:
85 # # - Object has a method named 'view'
86 # # - 'view' method calls '__call__'
87 # # - five:viewable overrides call to use '__browser_default__'
88 # # to find a default view and call it
89 # # - defaultView is set to 'view'
90 # # Bang. Infinite recursion.
91 # stack = inspect.stack()
92 # try:
93 # if len(stack) < 4:
94 # return False
95 # if stack[2][1:4] == stack[4][1:4]:
96 # return True
97 # finally:
98 # del stack
99 # return False
101 class BrowserDefault(object):
102 implements(IBrowserDefault)
104 def __init__(self, context):
105 self.context = context
107 def defaultView(self, request):
108 context = self.context
109 try:
110 name = getDefaultViewName(context, request)
111 return context, [name,]
112 except ComponentLookupError:
113 return context, None