Back to index

plone3  3.1.7
context.py
Go to the documentation of this file.
00001 from zope.interface import implements
00002 from zope.component import getMultiAdapter, queryMultiAdapter
00003 from zope.component import getUtility
00004 from plone.memoize.view import memoize
00005 
00006 from Acquisition import aq_base, aq_inner, aq_parent
00007 from Products.Five.browser import BrowserView
00008 
00009 from Products.CMFCore.interfaces import ISiteRoot
00010 from Products.CMFPlone.interfaces import IBrowserDefault
00011 from Products.CMFPlone.interfaces import INonStructuralFolder
00012 from Products.CMFPlone.interfaces.NonStructuralFolder import INonStructuralFolder \
00013      as z2INonStructuralFolder
00014 
00015 from Products.CMFCore.utils import getToolByName
00016 from Products.CMFPlone import utils
00017 
00018 from interfaces import IContextState
00019 
00020 from plone.portlets.interfaces import ILocalPortletAssignable
00021 
00022 BLACKLISTED_PROVIDERS = ('portal_workflow', )
00023 BLACKLISTED_CATEGORIES = ('folder_buttons', 'object_buttons')
00024 
00025 
00026 class ContextState(BrowserView):
00027     """Information about the state of the current context
00028     """
00029     
00030     implements(IContextState)
00031     
00032     @memoize
00033     def current_page_url(self):
00034         url = self.current_base_url()
00035         query = self.request.get('QUERY_STRING', None)
00036         if query:
00037             url += '?' + query
00038         return url
00039         
00040     @memoize
00041     def current_base_url(self):
00042         return self.request.get('ACTUAL_URL',
00043                  self.request.get('VIRTUAL_URL',
00044                    self.request.get('URL', 
00045                      self.context.absolute_url())))
00046                              
00047     @memoize
00048     def canonical_object(self):
00049         if self.is_default_page():
00050             return self.parent()
00051         else:
00052             return self.context
00053             
00054     @memoize
00055     def canonical_object_url(self):
00056         return self.canonical_object().absolute_url()
00057             
00058     @memoize
00059     def view_url(self):
00060         """URL to use for viewing
00061 
00062         Files and Images get downloaded when they are directly
00063         called, instead of with /view appended.  We want to avoid that.
00064         """
00065         view_url = self.object_url()
00066         portal_properties = getToolByName(self.context, 'portal_properties', None)
00067         if portal_properties is not None:
00068             site_properties = getattr(portal_properties, 'site_properties', None)
00069             portal_type = getattr(aq_base(self.context), 'portal_type', None)
00070             if site_properties is not None and portal_type is not None:
00071                 use_view_action = site_properties.getProperty('typesUseViewActionInListings', ())
00072                 if portal_type in use_view_action:
00073                     view_url = view_url + '/view'
00074         return view_url
00075 
00076     @memoize
00077     def view_template_id(self):
00078         context = aq_inner(self.context)
00079         browserDefault = IBrowserDefault(context, None)
00080         
00081         if browserDefault is not None:
00082             try:
00083                 return browserDefault.getLayout()
00084             except AttributeError:
00085                 # Might happen if FTI didn't migrate yet.
00086                 pass
00087 
00088         action = self._lookupTypeActionTemplate('object/view')
00089         if not action:
00090             action = self._lookupTypeActionTemplate('folder/folderlisting')
00091 
00092         return action
00093 
00094     @memoize
00095     def is_view_template(self):
00096         current_url = self.current_base_url()
00097         canonical_url = self.canonical_object_url()
00098         object_url = self.object_url()
00099         
00100         if current_url.endswith('/'):
00101             current_url = current_url[:-1]
00102         
00103         if current_url == canonical_url or current_url == object_url:
00104             return True
00105         elif current_url == object_url + '/view':
00106             return True
00107         
00108         template_id = self.view_template_id()
00109         if current_url == "%s/%s" % (object_url, template_id):
00110             return True
00111         elif current_url == "%s/@@%s" % (object_url, template_id):
00112             return True
00113         
00114         return False
00115 
00116     @memoize
00117     def object_url(self):
00118         return aq_inner(self.context).absolute_url()
00119         
00120     @memoize
00121     def object_title(self):
00122         context = aq_inner(self.context)
00123         return utils.pretty_title_or_id(context, context)
00124         
00125     @memoize
00126     def workflow_state(self):
00127         tool = getToolByName(self.context, "portal_workflow")
00128         return tool.getInfoFor(aq_inner(self.context), 'review_state', None)
00129     
00130     @memoize
00131     def parent(self):
00132         return aq_parent(aq_inner(self.context))
00133 
00134     @memoize
00135     def folder(self):
00136         if self.is_structural_folder() and not self.is_default_page():
00137             return aq_inner(self.context)
00138         else:
00139             return self.parent()
00140     
00141     @memoize
00142     def is_folderish(self):
00143         return bool(getattr(aq_base(aq_inner(self.context)), 'isPrincipiaFolderish', False))
00144             
00145     @memoize
00146     def is_structural_folder(self):
00147         folderish = self.is_folderish()
00148         context = aq_inner(self.context)
00149         if not folderish:
00150             return False
00151         elif INonStructuralFolder.providedBy(context):
00152             return False
00153         elif z2INonStructuralFolder.isImplementedBy(context):
00154             # BBB: for z2 interface compat
00155             return False
00156         else:
00157             return folderish
00158         
00159     @memoize
00160     def is_default_page(self):
00161         context = aq_inner(self.context)
00162         container = aq_parent(context)
00163         if not container:
00164             return False
00165         view = getMultiAdapter((container, self.request), name='default_page')
00166         return view.isDefaultPage(context)
00167     
00168     @memoize
00169     def is_portal_root(self):
00170         context = aq_inner(self.context)
00171         portal = getUtility(ISiteRoot)
00172         return aq_base(context) is aq_base(portal) or \
00173                 (self.is_default_page() and aq_base(self.parent()) is aq_base(portal))
00174     
00175     @memoize
00176     def is_editable(self):
00177         tool = getToolByName(self.context, "portal_membership")
00178         return bool(tool.checkPermission('Modify portal content', aq_inner(self.context)))
00179     
00180     @memoize
00181     def is_locked(self):
00182         # plone_lock_info is registered on marker interface ITTWLockable, since
00183         # not everything may want to parttake in its lock-stealing ways.
00184         lock_info = queryMultiAdapter((self.context, self.request), name='plone_lock_info')
00185         if lock_info is not None:
00186             return lock_info.is_locked_for_current_user()
00187         else:
00188             context = aq_inner(self.context)
00189             lockable = getattr(context.aq_explicit, 'wl_isLocked', None) is not None
00190             return lockable and context.wl_isLocked()
00191 
00192     @memoize
00193     def actions(self):
00194         tool = getToolByName(self.context, "portal_actions")
00195         return tool.listFilteredActionsFor(aq_inner(self.context),
00196                                            ignore_providers=BLACKLISTED_PROVIDERS,
00197                                            ignore_categories=BLACKLISTED_CATEGORIES)
00198 
00199     @memoize
00200     def keyed_actions(self):
00201         actions = self.actions()
00202         keyed_actions = {}
00203         for category in actions.keys():
00204             keyed_actions[category] = {}
00205             for action in actions[category]:
00206                 id = action.get('id', None)
00207                 if id is not None:
00208                     keyed_actions[category][id] = action.copy()
00209         return keyed_actions
00210        
00211     @memoize
00212     def portlet_assignable(self):
00213         return ILocalPortletAssignable.providedBy(self.context)
00214         
00215     # Helper methods
00216     def _lookupTypeActionTemplate(self, actionId):
00217         context = aq_inner(self.context)
00218         fti = context.getTypeInfo()
00219         try:
00220             # XXX: This isn't quite right since it assumes the action starts with ${object_url}
00221             action = fti.getActionInfo(actionId)['url'].split('/')[-1]
00222         except ValueError:
00223             # If the action doesn't exist, stop
00224             return None
00225 
00226         # Try resolving method aliases because we need a real template_id here
00227         action = fti.queryMethodID(action, default = action, context = context)
00228 
00229         # Strip off leading /
00230         if action and action[0] == '/':
00231             action = action[1:]
00232         return action