Back to index

plone3  3.1.7
manager.py
Go to the documentation of this file.
00001 from ZODB.POSException import ConflictError
00002 
00003 from zope.interface import implements, Interface
00004 from zope.component import adapts, getMultiAdapter, getUtilitiesFor
00005 
00006 from zope.publisher.interfaces.browser import IBrowserView
00007 from zope.publisher.interfaces.browser import IBrowserRequest
00008 
00009 from zope.contentprovider.interfaces import UpdateNotCalled
00010 
00011 from plone.portlets.interfaces import IPortletRetriever
00012 from plone.portlets.interfaces import IPortletManager
00013 from plone.portlets.interfaces import IPortletManagerRenderer
00014 from plone.portlets.interfaces import IPortletRenderer
00015 from plone.portlets.interfaces import IPortletType
00016 
00017 from plone.portlets.storage import PortletStorage
00018 
00019 from plone.memoize.view import memoize
00020 
00021 from utils import hashPortletInfo
00022 
00023 import logging
00024 logger = logging.getLogger('portlets')
00025 
00026 class PortletManagerRenderer(object):
00027     """Default renderer for portlet managers.
00028 
00029     When the zope.contentprovider handler for the provider: expression looks up
00030     a name, context, it will find an adapter factory that in turn finds an 
00031     instance of this class, by doing an adapter lookup for (context, request,
00032     view, manager).
00033     """
00034     implements(IPortletManagerRenderer)
00035     adapts(Interface, IBrowserRequest, IBrowserView, IPortletManager)
00036     
00037     template = None
00038     error_message = None
00039 
00040     def __init__(self, context, request, view, manager):
00041         self.__parent__ = view
00042         self.manager = manager # part of interface
00043         self.context = context
00044         self.request = request
00045         self.__updated = False
00046         
00047     @property
00048     def visible(self):
00049         portlets = self.portletsToShow()
00050         return len(portlets) > 0
00051 
00052     def filter(self, portlets):
00053         filtered = []
00054         for p in portlets:
00055             try:
00056                 if p['assignment'].available:
00057                     filtered.append(p)
00058             except ConflictError:
00059                 raise
00060             except Exception, e:
00061                 logger.exception('Error while determining assignment availability of portlet %r: %s' % (p, str(e)))
00062         return filtered 
00063         
00064     def portletsToShow(self):
00065         return self._lazyLoadPortlets(self.manager)
00066 
00067     def update(self):
00068         self.__updated = True
00069         for p in self.portletsToShow():
00070             p['renderer'].update()
00071 
00072     def render(self):
00073         if not self.__updated:
00074             raise UpdateNotCalled
00075             
00076         portlets = self.portletsToShow()
00077         if self.template:
00078             return self.template(portlets=portlets)
00079         else:
00080             return u'\n'.join([p['renderer'].render() for p in portlets])
00081 
00082     def safe_render(self, portlet_renderer):
00083         try:
00084             return portlet_renderer.render()
00085         except ConflictError:
00086             raise
00087         except Exception:
00088             logger.exception('Error while rendering %r' % (self,))
00089             return self.error_message()
00090 
00091     # Note: By passing in a parameter that's different for each portlet
00092     # manager, we avoid the view memoization (which is tied to the request)
00093     # caching the same portlets for all managers on the page. We cache the
00094     # portlets using a view memo because it they be looked up multiple times,
00095     # e.g. first to check if portlets should be displayed and later to 
00096     # actually render
00097     
00098     @memoize
00099     def _lazyLoadPortlets(self, manager):
00100         retriever = getMultiAdapter((self.context, manager), IPortletRetriever)
00101         items = []
00102         for p in self.filter(retriever.getPortlets()):
00103             renderer = self._dataToPortlet(p['assignment'].data)
00104             try:
00105                 isAvailable = renderer.available
00106             except ConflictError:
00107                 raise
00108             except Exception, e:
00109                 isAvailable = False
00110                 logger.exception('Error while determining renderer availability of portlet %r: %s' % (p, str(e)))
00111             if isAvailable:
00112                 info = p.copy()
00113                 info['manager'] = self.manager.__name__
00114                 info['renderer'] = renderer
00115                 hashPortletInfo(info)
00116                 items.append(info)
00117         return items
00118     
00119     def _dataToPortlet(self, data):
00120         """Helper method to get the correct IPortletRenderer for the given
00121         data object.
00122         """
00123         return getMultiAdapter((self.context, self.request, self.__parent__,
00124                                     self.manager, data,), IPortletRenderer)
00125 
00126 class PortletManager(PortletStorage):
00127     """Default implementation of the portlet manager.
00128 
00129     Provides the functionality that allows the portlet manager to act as an
00130     adapter factory.
00131     """
00132 
00133     implements(IPortletManager)
00134 
00135     __name__ = __parent__ = None
00136 
00137     def __call__(self, context, request, view):
00138         return getMultiAdapter((context, request, view, self), IPortletManagerRenderer)
00139 
00140     def getAddablePortletTypes(self):
00141        addable = []
00142        for p in getUtilitiesFor(IPortletType):
00143            #BBB - first condition, because starting with Plone 3.1
00144            #every p[1].for_ should be a list
00145            if not isinstance(p[1].for_, list):
00146                logger.warning("Deprecation Warning Portlet type " + \
00147                  "%s is using a deprecated format for " % p[1].addview + \
00148                  "storing interfaces of portlet managers where it is " + \
00149                  "addable. Its for_ attribute should be a list of portlet " + \
00150                  "manager interfaces, using [zope.interface.Interface] " + \
00151                  "for the portlet type to be addable anywhere. The old " + \
00152                  "format will be unsupported in Plone 4.0.")
00153                if p[1].for_ is None or p[1].for_.providedBy(self):
00154                    addable.append(p[1])
00155            elif [i for i in p[1].for_ if i.providedBy(self)]:
00156                addable.append(p[1])
00157        return addable