Back to index

plone3  3.1.7
ActionIconsTool.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2003 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Map CMF actions to icons, for ease of building icon-centric toolbars.
00014 
00015 $Id: ActionIconsTool.py 73137 2007-03-11 12:43:51Z yuppie $
00016 """
00017 
00018 import os
00019 
00020 from AccessControl import ClassSecurityInfo
00021 from Globals import InitializeClass
00022 from Globals import package_home
00023 from OFS.SimpleItem import SimpleItem
00024 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
00025 from zope.interface import implements
00026 
00027 from Products.CMFCore.Expression import Expression
00028 from Products.CMFCore.utils import registerToolInterface
00029 from Products.CMFCore.utils import UniqueObject
00030 
00031 from interfaces import IActionIconsTool
00032 from permissions import ManagePortal
00033 from permissions import View
00034 
00035 _wwwdir = os.path.join( package_home( globals() ), 'www' )
00036 
00037 
00038 class ActionIcon( SimpleItem ):
00039 
00040     security = ClassSecurityInfo()
00041 
00042     _title = None           # Use the one supplied by the provider
00043     _priority = 0           # All animals are equal....
00044     _category = 'object'
00045     _action_id = 'view'
00046     _icon_expr_text = 'document_icon'
00047 
00048     def __init__( self
00049                 , category
00050                 , action_id
00051                 , icon_expr_text=''
00052                 , title=None
00053                 , priority=0
00054                 ):
00055 
00056         self._category = category
00057         self._action_id = action_id
00058         self.updateIconExpression( icon_expr_text )
00059         self._title = title
00060         self._priority = priority
00061 
00062     security.declareProtected( View, 'getTitle' )
00063     def getTitle( self ):
00064 
00065         """ Simple accessor """
00066         return self._title
00067 
00068     security.declareProtected( View, 'getPriority' )
00069     def getPriority( self ):
00070 
00071         """ Simple accessor """
00072         return self._priority
00073 
00074     security.declareProtected( View, 'getCategory' )
00075     def getCategory( self ):
00076 
00077         """ Simple accessor """
00078         return self._category
00079 
00080     security.declareProtected( View, 'getActionId' )
00081     def getActionId( self ):
00082 
00083         """ Simple accessor """
00084         return self._action_id
00085 
00086     security.declareProtected( View, 'getExpression' )
00087     def getExpression( self ):
00088 
00089         """ Simple accessor """
00090         return self._icon_expr_text
00091 
00092     security.declareProtected( View, 'getIconURL' )
00093     def getIconURL( self, context=None ):
00094 
00095         """ Simple accessor """
00096         if context is None:
00097             return self._icon_expr_text
00098 
00099         return self._icon_expr( context )
00100 
00101     security.declareProtected( ManagePortal, 'updateIconExpression' )
00102     def updateIconExpression( self, icon_expr_text ):
00103 
00104         """ Mutate icon expression. """
00105         self._icon_expr_text = icon_expr_text
00106 
00107         if not ':' in icon_expr_text: # default to 'string:' type
00108             icon_expr_text = 'string:%s' % icon_expr_text
00109 
00110         self._icon_expr = Expression( icon_expr_text )
00111 
00112 InitializeClass( ActionIcon )
00113 
00114 
00115 class ActionIconsTool( UniqueObject, SimpleItem ):
00116 
00117     """ Map actions only icons.
00118     """
00119 
00120     implements(IActionIconsTool)
00121 
00122     meta_type = 'Action Icons Tool'
00123     id = 'portal_actionicons'
00124 
00125     security = ClassSecurityInfo()
00126     security.declareObjectProtected( View )
00127 
00128     def __init__( self ):
00129 
00130         self.clearActionIcons()
00131 
00132     #
00133     #   Accessors
00134     #
00135     security.declareProtected( ManagePortal, 'listActionIcons' )
00136     def listActionIcons( self ):
00137 
00138         """ Return a sequence of mappings for action icons
00139 
00140         o Mappings are in the form: ( category, action ) -> icon,
00141           where category and action are strings and icon is an ActionIcon
00142           instance.
00143         """
00144         return [ x.__of__( self ) for x in self._icons ]
00145 
00146     security.declareProtected( View, 'getActionInfo' )
00147     def getActionInfo( self
00148                      , category
00149                      , action_id
00150                      , context=None
00151                      ):
00152 
00153         """ Return a tuple, '(title, priority, icon ID), for the given action.
00154 
00155         o Raise a KeyError if no icon has been defined for the action.
00156         """
00157         ai = self._lookup[ ( category, action_id ) ]
00158         return ( ai.getTitle()
00159                , ai.getPriority()
00160                , ai.getIconURL( context )
00161                )
00162 
00163     security.declareProtected( View, 'queryActionInfo' )
00164     def queryActionInfo( self
00165                        , category
00166                        , action_id
00167                        , default=None
00168                        , context=None
00169                        ):
00170 
00171         """ Return a tuple, '(title, priority, icon ID), for the given action.
00172 
00173         o Return 'default' if no icon has been defined for the action.
00174         """
00175         ai = self._lookup.get( ( category, action_id ) )
00176         return ai and ( ai.getTitle()
00177                       , ai.getPriority()
00178                       , ai.getIconURL( context )
00179                       ) or default
00180 
00181     security.declareProtected( View, 'getActionIcon' )
00182     def getActionIcon( self, category, action_id, context=None ):
00183 
00184         """ Return an icon ID for the given action.
00185 
00186         o Raise a KeyError if no icon has been defined for the action.
00187 
00188         o Context is an Expression context object, used to evaluate
00189           TALES expressions.
00190         """
00191         return self._lookup[ ( category, action_id ) ].getIconURL( context )
00192 
00193     security.declareProtected( View, 'queryActionIcon' )
00194     def queryActionIcon( self, category, action_id
00195                        , default=None, context=None ):
00196 
00197         """ Return an icon ID for the given action.
00198 
00199         o Return 'default' if no icon has been defined for the action.
00200 
00201         o Context is an Expression context object, used to evaluate
00202           TALES expressions.
00203         """
00204         ai = self._lookup.get( ( category, action_id ) )
00205         return ai and ai.getIconURL( context ) or default
00206 
00207     security.declareProtected( View, 'updateActionDicts' )
00208     def updateActionDicts( self, categorized_actions, context=None ):
00209 
00210         """ Update a set of dictionaries, adding 'title, 'priority', and
00211             'icon' keys.
00212 
00213         o S.b. passed a data structure like that returned from ActionsTool's
00214           'listFilteredActionsFor':
00215 
00216           - Dict mapping category -> seq. of dicts, where each of the
00217             leaf dicts must have 'category' and 'id' keys.
00218 
00219         o *Will* overwrite the 'title' key, if title is defined on the tool.
00220 
00221         o *Will* overwrite the 'priority' key.
00222 
00223         o *Will* overwrite the 'icon' key, if icon is defined on the tool
00224 
00225         o XXX:  Don't have a way to pass Expression context yet.
00226         """
00227         result = {}
00228 
00229         for category, actions in categorized_actions.items():
00230 
00231             new_actions = []
00232 
00233             for action in actions:
00234 
00235                 action = action.copy()
00236 
00237                 action_id = action.get( 'id' )
00238 
00239                 #  Hack around DCWorkflow's ID-less worklist actions.
00240                 if action_id is None and action.get( 'category' ) == 'workflow':
00241                     action[ 'id' ] = action_id = action.get( 'name' )
00242 
00243                 if action_id:
00244 
00245                     info = self.queryActionInfo( category
00246                                                , action_id
00247                                                , context=context
00248                                                )
00249                     if info is not None:
00250 
00251                         title, priority, icon = info
00252 
00253                         if title is not None:
00254                             action[ 'title' ] = title
00255 
00256                         if priority is not None:
00257                             action[ 'priority' ] = priority
00258 
00259                         if icon is not None:
00260                             action[ 'icon' ] = icon
00261 
00262                 new_actions.append( action )
00263 
00264             new_actions.sort( lambda x, y: cmp( x.get( 'priority', 0 )
00265                                               , y.get( 'priority', 0 )
00266                                               ) )
00267             result[ category ] = new_actions
00268 
00269         return result
00270 
00271     __call__ = updateActionDicts
00272 
00273     #
00274     #   Mutators
00275     #
00276     security.declareProtected( ManagePortal, 'addActionIcon' )
00277     def addActionIcon( self
00278                      , category
00279                      , action_id
00280                      , icon_expr
00281                      , title=None
00282                      , priority=0
00283                      ):
00284 
00285         """ Add an icon for the given action.
00286 
00287         o Raise KeyError if an icon has already been defined.
00288         """
00289         if self.queryActionInfo( category, action_id ) is not None:
00290             raise KeyError, 'Duplicate definition!'
00291 
00292         icons = list( self._icons )
00293         icons.append( ActionIcon( category
00294                                 , action_id
00295                                 , icon_expr
00296                                 , title
00297                                 , priority
00298                                 ) )
00299         self._lookup[ ( category, action_id ) ] = icons[-1]
00300         self._icons = tuple( icons )
00301 
00302     security.declareProtected( ManagePortal, 'updateActionIcon' )
00303     def updateActionIcon( self
00304                         , category
00305                         , action_id
00306                         , icon_expr
00307                         , title=None
00308                         , priority=0
00309                         ):
00310 
00311         """ Update the icon for the given action.
00312 
00313         o Raise KeyError if an icon has not already been defined.
00314         """
00315         if self._lookup.get( ( category, action_id ) ) is None:
00316             raise KeyError, 'No such definition!'
00317 
00318         icons = list( self._icons )
00319         for ai in icons:
00320             if ( ai.getCategory() == category
00321              and ai.getActionId() == action_id
00322                ):
00323                 ai.updateIconExpression( icon_expr )
00324                 ai._title = title
00325                 ai._priority = priority
00326                 break
00327         else:
00328             raise KeyError, ( category, action_id )
00329         self._icons = tuple( icons )
00330 
00331     security.declareProtected( ManagePortal, 'removeActionIcon' )
00332     def removeActionIcon( self, category, action_id ):
00333 
00334         """ Remove the icon for the given action.
00335 
00336         o Raise KeyError if an icon has not already been defined.
00337         """
00338         if self.queryActionInfo( category, action_id ) is None:
00339             raise KeyError, 'No such definition (%s, %s)!' % (
00340                 category, action_id)
00341 
00342         icons = list( self._icons )
00343         icon = self._lookup[ ( category, action_id ) ]
00344         icons.remove( icon )
00345         del self._lookup[ ( category, action_id ) ]
00346         self._icons = tuple( icons )
00347 
00348     security.declareProtected( ManagePortal, 'clearActionIcons' )
00349     def clearActionIcons( self ):
00350 
00351         """ Remove all mappings from the tool.
00352         """
00353         self._icons = ()
00354         self._lookup = {}
00355 
00356     #
00357     #   ZMI
00358     #
00359     manage_options =  ( { 'label' : 'Icons'
00360                         , 'action' : 'manage_editActionIcons'
00361                         }
00362                       ,
00363                       ) + SimpleItem.manage_options
00364 
00365     security.declareProtected( ManagePortal, 'manage_editActionIcons' )
00366     manage_editActionIcons = PageTemplateFile( 'aitEdit', _wwwdir )
00367 
00368     security.declareProtected( ManagePortal, 'manage_addActionIcon' )
00369     def manage_addActionIcon( self
00370                             , category
00371                             , action_id
00372                             , icon_expr
00373                             , title
00374                             , priority
00375                             , REQUEST
00376                             ):
00377 
00378         """ Add an icon for the given action via the ZMI.
00379         """
00380         self.addActionIcon( category
00381                           , action_id
00382                           , icon_expr
00383                           , title
00384                           , priority
00385                           )
00386 
00387         REQUEST['RESPONSE'].redirect( '%s/manage_editActionIcons'
00388                                       '?manage_tabs_message=Action+added.'
00389                                     % self.absolute_url()
00390                                     )
00391 
00392     security.declareProtected( ManagePortal, 'manage_updateActionIcon' )
00393     def manage_updateActionIcon( self
00394                                , category
00395                                , action_id
00396                                , icon_expr
00397                                , title
00398                                , priority
00399                                , REQUEST
00400                                ):
00401 
00402         """ Update an icon for the given action via the ZMI.
00403         """
00404         self.updateActionIcon( category
00405                              , action_id
00406                              , icon_expr
00407                              , title
00408                              , priority
00409                              )
00410 
00411         REQUEST['RESPONSE'].redirect( '%s/manage_editActionIcons'
00412                                       '?manage_tabs_message=Action+updated.'
00413                                     % self.absolute_url()
00414                                     )
00415 
00416     security.declareProtected( ManagePortal, 'manage_removeActionIcon' )
00417     def manage_removeActionIcon( self, category, action_id, REQUEST ):
00418 
00419         """ Remove the icon for the given action via the ZMI.
00420         """
00421         self.removeActionIcon( category, action_id )
00422 
00423         REQUEST['RESPONSE'].redirect( '%s/manage_editActionIcons'
00424                                       '?manage_tabs_message=Action+removed.'
00425                                     % self.absolute_url()
00426                                     )
00427 
00428 InitializeClass( ActionIconsTool )
00429 registerToolInterface('portal_actionicons', IActionIconsTool)