[CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.1.2.1 ActionProviderBase.py:1.1.2.1 Expression.py:1.1.2.1 ActionsTool.py:1.19.10.1 CatalogTool.py:1.21.14.1 MemberDataTool.py:1.12.14.1 MembershipTool.py:1.16.14.1 PortalFolder.py:1.28.10.1 RegistrationTool.py:1.7.14.1 SkinsTool.py:1.11.14.1 TypesTool.py:1.26.14.1 UndoTool.py:1.4.14.1 WorkflowTool.py:1.19.4.1

Andrew Sawyers andrew@zope.com
Wed, 2 Jan 2002 17:03:35 -0500


Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv20833/CMFCore

Modified Files:
      Tag: andrew_ttw_actions-branch
	ActionsTool.py CatalogTool.py MemberDataTool.py 
	MembershipTool.py PortalFolder.py RegistrationTool.py 
	SkinsTool.py TypesTool.py UndoTool.py WorkflowTool.py 
Added Files:
      Tag: andrew_ttw_actions-branch
	ActionInformation.py ActionProviderBase.py Expression.py 
Log Message:

*Changes to support Tools TTW Actions
*Changes to support TTW Action Provider configuration
*Docs and Test coming soon...


=== Added File CMF/CMFCore/ActionInformation.py ===
##############################################################################
#
# Copyright (c) 2001 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
# 
##############################################################################

"""Basic action list tool.

$Id: ActionInformation.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]

from utils import SimpleItemWithProperties, _dtmldir, getToolByName
import CMFCorePermissions
from AccessControl import ClassSecurityInfo
from Acquisition import aq_inner, aq_parent
from Globals import InitializeClass, DTMLFile

class ActionInformation(SimpleItemWithProperties):
    """
    Represent a single action which the user can select from a list
    and execut in some context.
    """
    _isActionInformation = 1
    __allow_access_to_unprotected_subobjects__ = 1

    manage_options = (SimpleItemWithProperties.manage_options[:1] +
                      ({'label': 'Actions',
                       'action': 'manage_editActionsForm'},) +
                       SimpleItemWithProperties.manage_options[1:])
    security = ClassSecurityInfo()
    security.declareProtected(CMFCorePermissions.ManagePortal
                            , 'manage_editProperties'
                            , 'manage_changeProperties'
                            , 'manage_propertiesForm'
                             )

    _basic_properties = (
                         {'id': 'title', 'type': 'string', 'mode': 'w', 'label': 'Title'}
                       , {'id': 'description', 'type': 'text', 'mode': 'w', 
                         'label': 'Description'}
                       , {'id': 'category', 'type': 'string', 'mode': 'w', 
                         'label': 'Category'}
                       , {'id': 'priority', 'type': 'boolean', 'mode':  'w', 'label': 'Priority'}
                         )

    title = ''
    description = ''
    category = ''
    priority = 0
    visible = 1
    _action = ''

    def __init__(self
               , id
               , title=''
               , description=''
               , category='object'
               , condition=''
               , permissions=()
               , priority=10
               , visible=1
               , action=''):
       """
       Setup an instance
       """
       self.id = id
       self.title = title
       self.description = description
       self.category = category 
       self.condition = condition
       self.permissions = permissions
       self.priority = priority 
       self.visible = visible
       self._action = action


    security.declareProtected(CMFCorePermissions.View, 'Title')
    def Title(self):
        """
        Return the Action title - name
        """
        if self.title:
            return self.title
        else:
            return self.getId()

    security.declareProtected(CMFCorePermissions.View, 'Description')
    def Description(self):
        """
        Return a description of the action
        """
        return self.description

    security.declarePrivate('testCondition')
    def testCondition(self, ec):
        """
        Evaluate condition and return 0 or 1
        """
        if self.condition:
            return self.condition(ec)
        else:
            return 1

    security.declarePublic('getAction')
    def getAction(self, ec):
        """
        Return the action, which is an TALES expresssion
        """
        if self._action:
            aa = self._action(ec)
        else:
            aa = ''
        action = {}
        action['id'] = self.id
        action['name'] = self.Title()
        action['url'] = aa 
        action['permissions'] = self.getPermissions()
        action['category'] = self.getCategory()
        action['visible'] = self.getVisibility()
        return action 

    security.declarePublic('getCondition')
    def getCondition(self):
        """
        If not an empty string or None, evaluate the expression
        """
        if self.condition:
            return self.condition.text
        else:
            return self.condition

    security.declarePublic('getPermission')
    def getPermissions(self):
        """
        Return the permission if any required for a user to
        execute the action
        """
        return self.permissions

    security.declarePublic('getCategory')
    def getCategory(self):
        """
        Return the category for which the action is
        """
        if self.category:
            return self.category
        else:
            return 'object'

    security.declarePublic('getVisibility')
    def getVisibility(self):
        """
        Return boolean for whether the action
        is visible in the UI
        """
        if self.visible:
            return self.visible
        else:
            return 1

    security.declarePublic('getPriority')
    def getPriority(self):
        """
        Return integer priority for sorting
        """
        if self.priority:
            return self.priority
        else:
            return 10

InitializeClass(ActionInformation)

class oai:
    #Provided for backwards compatability
    # Provides information that may be needed when constructing the list of
    # available actions.
    __allow_access_to_unprotected_subobjects__ = 1

    def __init__(self, tool, folder, object=None):
        self.portal = portal = aq_parent(aq_inner(tool))
        membership = getToolByName(tool, 'portal_membership')
        self.isAnonymous = membership.isAnonymousUser()
        self.portal_url = portal.absolute_url()
        if folder is not None:
            self.folder_url = folder.absolute_url()
            self.folder = folder
        else:
            self.folder_url = self.portal_url
            self.folder = portal
        self.content = object
        if object is not None:
            self.content_url = object.absolute_url()
        else:
            self.content_url = None

    def __getitem__(self, name):
        # Mapping interface for easy string formatting.
        if name[:1] == '_':
            raise KeyError, name
        if hasattr(self, name):
            return getattr(self, name)
        raise KeyError, name



=== Added File CMF/CMFCore/ActionProviderBase.py ===
##############################################################################
#
# Copyright (c) 2001 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
# 
##############################################################################

from OFS.SimpleItem import SimpleItem
from Globals import DTMLFile
from CMFCorePermissions import ManagePortal
from utils import _dtmldir, cookString
from AccessControl import ClassSecurityInfo
from ActionInformation import ActionInformation
from Expression import Expression


"""Basic action list tool.

$Id: ActionProviderBase.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $
"""
__version__='$Revision: 1.1.2.1 $'[11:-2]

class ActionProviderBase:
    """
    Provide ActionTabs and management methods for ActionProviders
    """
    _actions = []
    security = ClassSecurityInfo()
    _actions_form = DTMLFile( 'editToolsActions', _dtmldir )

    manage_options = ({ 'label' : 'Actions', 'action' : 'manage_editActionsForm' }
                    , 
                     )

    security.declarePrivate('listActions')
    def listActions(self):
        """
        Return all the actions defined by a tool
        """
        if self._actions:
            return self._actions
        else:
            return None

    security.declareProtected(ManagePortal, 'manage_editActionsForm')
    def manage_editActionsForm(self, REQUEST, manage_tabs_message=None):
        """
        Shows the 'Actions' management tab.
        """
        actions = []
        if self.listActions() is not None:
            for a in self.listActions():
                a1 = {}
                a1['id'] = a.getId()
                a1['name'] = a.Title()
                p = a.getPermissions()
                if p:
                    a1['permission'] = p[0]
                else:
                    a1['permission'] = ''
                if not a.getCategory():
                    a1['category'] = 'object'
                else:
                    a1['category'] = a.getCategory()
                if not a.getVisibility():
                    a1['visible'] = 1
                else:
                    a1['visible'] = a.getVisibility()
                if a._action:
                    a1['action'] = a._action.text
                else:
                    a1['action'] = ''
                if a.condition:
                    a1['condition'] = a.getCondition()
                else:
                    a1['condition'] = ''
                actions.append(a1)
                # possible_permissions is in AccessControl.Role.RoleManager.
        pp = self.possible_permissions()
        return self._actions_form(self, REQUEST,
                                  actions=actions,
                                  possible_permissions=pp,
                                  management_view='Actions',
                                  manage_tabs_message=manage_tabs_message)

    security.declareProtected(ManagePortal, 'addAction')
    def addAction( self
                 , id
                 , name
                 , action
                 , condition
                 , permission
                 , category
                 , visible=1
                 , REQUEST=None
                 ):
        """
        Adds an action to the list.
        """
        al = self._actions 
        if not name:
            raise ValueError('A name is required.')
        if action:
            a_expr = Expression(text=str(action))
        else:
            a_expr = ''
        if condition:
            c_expr = Expression(text=str(condition))
        else:
            c_expr = ''
        al.append(ActionInformation(id=str(id)
                                         , title=str(name)
                                         , action=a_expr
                                         , condition=c_expr
                                         , permissions=(str(permission),)
                                         , category=str(category)
                                         , visible=int(visible)
                                          ))
        self._actions = al
        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST, manage_tabs_message='Added.')
    
    security.declareProtected(ManagePortal, 'changeActions')
    def changeActions(self, properties=None, REQUEST=None):
        """
        Changes the _actions.
        """
        if properties is None:
            properties = REQUEST
        actions = []
        for idx in range(len(self._actions)):
            s_idx = str(idx)
            action = {
                'id': str(properties.get('id_' + s_idx, '')),
                'name': str(properties.get('name_' + s_idx, '')),
                'action': str(properties.get('action_' + s_idx, '')),
                'condition': str(properties.get('condition_' + s_idx, '')),
                'permissions':
                (properties.get('permission_' + s_idx, ()),),
                'category': str(properties.get('category_' + s_idx, 'object')),
                'visible': not not properties.get('visible_' + s_idx, 0),
                }
            if not action['name']:
                raise ValueError('A name is required.')
            a = self._actions[idx]
            a.id = action['id']
            a.title = action['name']
            if not a._action:
                a._action = Expression(text=action['action'])
            else:
                a._action.text = action['action']
            if not a.condition:
                a.condition = Expression(text=action['condition'])
            else:
                del(a.condition)
                a.condition= Expression(text = action['condition'])
            a.permissions = action['permissions']
            a.category = action['category']
            a.visible = action['visible']
        if REQUEST is not None:
            return self.manage_editActionsForm(REQUEST, manage_tabs_message=
                                               'Actions changed.')

    security.declareProtected(ManagePortal, 'deleteActions')
    def deleteActions(self, selections=(), REQUEST=None):
        """
        Deletes actions.
        """
        actions = list(self._actions)
        sels = list(map(int, selections))  # Convert to a list of integers.
        sels.sort()
        sels.reverse()
        for idx in sels:
            del actions[idx]
        self._actions = actions
        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST, manage_tabs_message=(
                'Deleted %d action(s).' % len(sels)))

    security.declareProtected(ManagePortal, 'moveUpActions')
    def moveUpActions(self, selections=(), REQUEST=None):
        """
        Moves the specified actions up one slot.
        """
        actions = list(self._actions)
        sels = list(map(int, selections))  # Convert to a list of integers.
        sels.sort()
        for idx in sels:
            idx2 = idx - 1
            if idx2 < 0:
                # Wrap to the bottom.
                idx2 = len(actions) - 1
            # Swap.
            a = actions[idx2]
            actions[idx2] = actions[idx]
            actions[idx] = a
        self._actions = actions
        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST, manage_tabs_message=(
                'Moved up %d action(s).' % len(sels)))

    security.declareProtected(ManagePortal, 'moveDownActions')
    def moveDownActions(self, selections=(), REQUEST=None):
        """
        Moves the specified actions down one slot.
        """
        actions = list(self._actions)
        sels = list(map(int, selections))  # Convert to a list of integers.
        sels.sort()
        sels.reverse()
        for idx in sels:
            idx2 = idx + 1
            if idx2 >= len(actions):
                # Wrap to the top.
                idx2 = 0
            # Swap.
            a = actions[idx2]
            actions[idx2] = actions[idx]
            actions[idx] = a
        self._actions = actions
        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST, manage_tabs_message=(
                'Moved down %d action(s).' % len(sels)))


=== Added File CMF/CMFCore/Expression.py ===
##############################################################################
#
# Copyright (c) 2001 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
# 
##############################################################################
'''
Expressions in a web-configurable workflow.
$Id: Expression.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $
'''
__version__='$Revision: 1.1.2.1 $'[11:-2]

import Globals
from Globals import Persistent
from Acquisition import aq_inner, aq_parent
from AccessControl import getSecurityManager, ClassSecurityInfo

from utils import getToolByName
from Products.PageTemplates.Expressions import getEngine
from Products.PageTemplates.TALES import SafeMapping
from Products.PageTemplates.PageTemplate import ModuleImporter


class Expression (Persistent):
    text = ''
    _v_compiled = None

    security = ClassSecurityInfo()

    def __init__(self, text):
        self.text = text
        self._v_compiled = getEngine().compile(text)

    def __call__(self, econtext):
        compiled = self._v_compiled
        if compiled is None:
            compiled = self._v_compiled = getEngine().compile(self.text)
        # ?? Maybe expressions should manipulate the security
        # context stack.
        res = compiled(econtext)
        if isinstance(res, Exception):
            raise res
        #print 'returning %s from %s' % (`res`, self.text)
        return res

Globals.InitializeClass(Expression)


def createExprContext(folder, portal, object):
    '''
    An expression context provides names for TALES expressions.
    '''
    pm = getToolByName(portal, 'portal_membership')
    if object is None:
        object_url = ''
    else:
        object_url = object.absolute_url()
    if pm.isAnonymousUser():
        member = None
    else:
        member = pm.getAuthenticatedMember()
    data = {
        'object_url':   object_url,
        'folder_url':   folder.absolute_url(),
        'portal_url':   portal.absolute_url(),
        'object':       object,
        'content':      object,
        'folder':       folder,
        'portal':       portal,
        'nothing':      None,
        'request':      getattr( object, 'REQUEST', None ),
        'modules':      ModuleImporter,
        'member':       member,
        }
    return getEngine().getContext(data)



=== CMF/CMFCore/ActionsTool.py 1.19 => 1.19.10.1 ===
 
 
-from utils import UniqueObject, _getAuthenticatedUser, _checkPermission
-from utils import getToolByName, _dtmldir
+import OFS
+from utils import UniqueObject, SimpleItemWithProperties, _getAuthenticatedUser, _checkPermission
+from utils import getToolByName, _dtmldir, cookString
 import CMFCorePermissions
 from OFS.SimpleItem import SimpleItem
 from Globals import InitializeClass, DTMLFile, package_home
@@ -27,60 +28,57 @@
 from Acquisition import aq_base, aq_inner, aq_parent
 from AccessControl import ClassSecurityInfo
 from string import join
+from Expression import Expression, createExprContext
+from ActionInformation import ActionInformation, oai
+from ActionProviderBase import ActionProviderBase
 
-class ActionInformation:
-    # Provides information that may be needed when constructing the list of
-    # available actions.
-    __allow_access_to_unprotected_subobjects__ = 1
-
-    def __init__(self, tool, folder, object=None):
-        self.portal = portal = aq_parent(aq_inner(tool))
-        membership = getToolByName(tool, 'portal_membership')
-        self.isAnonymous = membership.isAnonymousUser()
-        self.portal_url = portal.absolute_url()
-        if folder is not None:
-            self.folder_url = folder.absolute_url()
-            self.folder = folder
-        else:
-            self.folder_url = self.portal_url
-            self.folder = portal
-        self.content = object
-        if object is not None:
-            self.content_url = object.absolute_url()
-        else:
-            self.content_url = None
 
-    def __getitem__(self, name):
-        # Mapping interface for easy string formatting.
-        if name[:1] == '_':
-            raise KeyError, name
-        if hasattr(self, name):
-            return getattr(self, name)
-        raise KeyError, name
-
-
-class ActionsTool (UniqueObject, SimpleItem):
+class ActionsTool(UniqueObject, OFS.Folder.Folder, ActionProviderBase):
     """
         Weave together the various sources of "actions" which are apropos
         to the current user and context.
     """
     id = 'portal_actions'
+    _actions = [ActionInformation(id='folderContents'
+                                , title='Folder contents'
+                                , action=Expression(
+               text='string: ${folder_url}/folder_contents')
+                                , condition=Expression(
+               text='python: folder is not object') 
+                                , permissions=('List folder contents',)
+                                , category='object'
+                                , visible=1
+                                 )
+              , ActionInformation(id='folderContents'
+                                , title='Folder contents'
+                                , action=Expression(
+               text='string: ${folder_url}/folder_contents')
+                                , condition=Expression(
+               text='python: folder is object')
+                                , permissions=('List folder contents',)
+                                , category='folder'
+                                , visible=1
+                                 )]
+
     meta_type = 'CMF Actions Tool'
 
-    action_providers = ( 'portal_actions'
-                       , 'portal_memberdata'
-                       , 'portal_registration'
-                       , 'portal_discussion'
-                       , 'portal_membership'
-                       , 'portal_workflow'
-                       , 'portal_undo'
-                       )
+    action_providers = ('portal_membership'
+                      , 'portal_memberdata'
+                      , 'portal_actions'
+                      , 'portal_registration'
+                      , 'portal_discussion'
+                      , 'portal_undo'
+                      , 'portal_syndication'
+                      , 'portal_workflow')
 
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
-                     , 
-                     ) + SimpleItem.manage_options
+    manage_options = ( ActionProviderBase.manage_options +
+                      ({'label' : 'Action Providers', 'action' : 'manage_actionProviders'}
+                     ,   { 'label' : 'Overview', 'action' : 'manage_overview' }
+                     ,
+                     ) + OFS.Folder.Folder.manage_options
+                     ) 
 
     #
     #   ZMI methods
@@ -88,19 +86,56 @@
     security.declareProtected( CMFCorePermissions.ManagePortal
                              , 'manage_overview' )
     manage_overview = DTMLFile( 'explainActionsTool', _dtmldir )
+    manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir)
 
 
     #
     # Programmatically manipulate the list of action providers
     #
 
+    security.declarePrivate('listActions')
+    def listActions(self, info=None):
+        """
+        Lists actions available through the tool.
+        """
+        return self._actions
+
     security.declareProtected( CMFCorePermissions.ManagePortal
                              , 'listActionProviders'
                              )
-    def listActionProviders( self ):
+    def listActionProviders(self):
        """ returns a sequence of action providers known by this tool """
        return self.action_providers
 
+    security.declareProtected(CMFCorePermissions.ManagePortal
+                            , 'manage_aproviders')
+    def manage_aproviders(self
+                        , apname=''
+                        , chosen=()
+                        , add_provider=0
+                        , del_provider=0
+                        , REQUEST=None):
+        """
+        Manage TTW Action Providers
+        """
+        #import pdb; pdb.set_trace()
+        providers = self.listActionProviders()
+        new_providers = []
+        if add_provider:
+            providers.append(apname)
+        elif del_provider:
+            for item in providers:
+                if item not in chosen:
+                    new_providers.append(item)
+            providers = new_providers
+        self.action_providers = providers
+        if REQUEST is not None:
+            return self.manage_actionProviders(self
+                                             , REQUEST
+                                             , manage_tabs_message='Properties changed.')
+        
+
+
     security.declareProtected( CMFCorePermissions.ManagePortal
                              , 'addActionProvider'
                              )
@@ -111,26 +146,6 @@
             p_new = p_old + ( provider_name, )
             self.action_providers = p_new
 
-    security.declarePrivate('listActions')
-    def listActions(self, info):
-        """
-        List actions available from this tool
-        """
-        if info.isAnonymous:
-            return None
-        else:
-            actions = []
-            folder_url = info.folder_url   
-            content_url = info.content_url   
-            if folder_url is not None: 
-                actions.append(
-                    { 'name'          : 'Folder contents'
-                    , 'url'        : folder_url + '/folder_contents'
-                    , 'permissions'   : ['List folder contents']
-                    , 'category'      : 'folder'
-                   })
-            return actions
-
     security.declareProtected( CMFCorePermissions.ManagePortal
                              , 'deleteActionProvider'
                              )
@@ -162,16 +177,24 @@
                     break
                 else:
                     folder = aq_parent(aq_inner(folder))
-
-        info = ActionInformation(self, folder, object)
-
+        ec = createExprContext(folder, portal, object)
+        ai_objs = []
         actions = []
+        info = oai(self, folder, object)
         # Include actions from specific tools.
         for provider_name in self.listActionProviders():
             provider = getattr(self, provider_name)
             a = provider.listActions(info)
-            if a:
-                actions.extend(list(a))
+            #import pdb; pdb.set_trace()
+            if a and type(a[0]) is not {}:
+                ai_objs.extend(list(a))
+            elif len(a) > 0:
+                actions.append(a)
+
+        if ai_objs:
+            for ai in ai_objs:
+                if ai.testCondition(ec):
+                    actions.append(ai.getAction(ec))
 
         # Include actions from object.
         if object is not None:
@@ -181,7 +204,7 @@
             if ti is not None:
                 defs = ti.getActions()
                 if defs:
-                    c_url = info.content_url
+                    c_url = object.absolute_url()
                     for d in defs:
                         a = d['action']
                         if a:
@@ -197,7 +220,7 @@
                             'visible': d.get('visible', 1),
                             })
             if hasattr(base, 'listActions'):
-                a = object.listActions(info)
+                a = object.listActions()
                 if a:
                     actions.extend(list(a))
 


=== CMF/CMFCore/CatalogTool.py 1.21 => 1.21.14.1 ===
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
+    manage_options = ( ZCatalog.manage_options +
+                      ({ 'label' : 'Overview', 'action' : 'manage_overview' }
                      , 
-                     ) + ZCatalog.manage_options
+                     ))
 
     def __init__(self):
         ZCatalog.__init__(self, self.getId())


=== CMF/CMFCore/MemberDataTool.py 1.12 => 1.12.14.1 ===
 from CMFCorePermissions import ViewManagementScreens
 import CMFCorePermissions
+from ActionProviderBase import ActionProviderBase
 
 _marker = []  # Create a new marker object.
 
 
-class MemberDataTool (UniqueObject, SimpleItem, PropertyManager):
+class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase):
     '''This tool wraps user objects, making them act as Member objects.
     '''
     id = 'portal_memberdata'
     meta_type = 'CMF Member Data Tool'
+    _actions = []
     _v_temps = None
     _properties = ()
 
     security = ClassSecurityInfo()
 
-    manage_options=( ( { 'label' : 'Overview'
+    manage_options=( ActionProviderBase.manage_options +
+                     ({ 'label' : 'Overview'
                        , 'action' : 'manage_overview'
                        }
                      , { 'label' : 'Contents'
@@ -83,8 +86,11 @@
     #   'portal_memberdata' interface methods
     #
     security.declarePrivate('listActions')
-    def listActions(self, info):
-        return None
+    def listActions(self, info=None):
+        """
+        Return actions provided via tool.
+        """
+        return self._actions
 
     security.declarePrivate('getMemberDataContents')
     def getMemberDataContents(self):


=== CMF/CMFCore/MembershipTool.py 1.16 => 1.16.14.1 ===
 from CMFCorePermissions import ManagePortal
 import CMFCorePermissions
+from ActionProviderBase import ActionProviderBase
 import Acquisition
 
 default_member_content = '''Default page for %s
@@ -37,22 +38,23 @@
   in the Tool Box on the left.
 '''
 
-class MembershipTool (UniqueObject, SimpleItem):
+class MembershipTool (UniqueObject, SimpleItem, ActionProviderBase):
     # This tool accesses member data through an acl_users object.
     # It can be replaced with something that accesses member data in
     # a different way.
     id = 'portal_membership'
     meta_type = 'CMF Membership Tool'
-
+    _actions = []
     security = ClassSecurityInfo()
 
-    manage_options=( { 'label' : 'Overview'
-                     , 'action' : 'manage_overview'
-                     }
-                   , { 'label' : 'Configuration'
+    manage_options=( ({ 'label' : 'Configuration'
                      , 'action' : 'manage_mapRoles'
-                     }
-                   ) + SimpleItem.manage_options
+                     },) +
+                     ActionProviderBase.manage_options + 
+                   ( { 'label' : 'Overview'
+                     , 'action' : 'manage_overview'
+                     },
+                   ) + SimpleItem.manage_options)
 
     #
     #   ZMI methods
@@ -387,7 +389,7 @@
 
 
     security.declarePrivate('listActions')
-    def listActions(self, info):
+    def listActions(self):
         return None
 
     security.declarePublic('getHomeFolder')


=== CMF/CMFCore/PortalFolder.py 1.28 => 1.28.10.1 ===
                                   , 'category'      : 'folder'
                                   }
-                                , { 'id'            : 'syndication'
-                                  , 'name'          : 'Syndication'
-                                  , 'action'        : 'synPropertiesForm'
-                                  , 'permissions'   : (ManageProperties,)
-                                  , 'category'      : 'folder'
-                                  }
                                 )
                              }
                            ,


=== CMF/CMFCore/RegistrationTool.py 1.7 => 1.7.14.1 ===
 import CMFCorePermissions
 import string, random
+from ActionProviderBase import ActionProviderBase
 
 
-class RegistrationTool (UniqueObject, SimpleItem):
+class RegistrationTool (UniqueObject, SimpleItem, ActionProviderBase):
     # This tool creates and modifies users by making calls
     # to portal_membership.
     id = 'portal_registration'
@@ -37,9 +38,10 @@
 
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
+    manage_options = (ActionProviderBase.manage_options +
+                     ({ 'label' : 'Overview', 'action' : 'manage_overview' }
                      , 
-                     ) + SimpleItem.manage_options
+                     ) + SimpleItem.manage_options)
 
     #
     #   ZMI methods
@@ -51,9 +53,6 @@
     #
     #   'portal_registration' interface methods
     #
-    security.declarePrivate('listActions')
-    def listActions(self, info):
-        return none
 
     security.declarePublic('isRegistrationAllowed')
     def isRegistrationAllowed(self, REQUEST):


=== CMF/CMFCore/SkinsTool.py 1.11 => 1.11.14.1 ===
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
+    manage_options = ( modifiedOptions() +
+                      ({ 'label' : 'Overview', 'action' : 'manage_overview' }
                      , 
-                     ) + modifiedOptions()
+                     ))
 
     def __init__(self):
         self.selections = PersistentMapping()


=== CMF/CMFCore/TypesTool.py 1.26 => 1.26.14.1 ===
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
+    manage_options = ( OFS.Folder.Folder.manage_options +
+                      ({ 'label' : 'Overview', 'action' : 'manage_overview' }
                      , 
-                     ) + OFS.Folder.Folder.manage_options
+                     ))
 
     #
     #   ZMI methods


=== CMF/CMFCore/UndoTool.py 1.4 => 1.4.14.1 ===
 from string import split
 from AccessControl import ClassSecurityInfo
-
+from Expression import Expression
+from ActionInformation import ActionInformation
+from ActionProviderBase import ActionProviderBase
 from CMFCorePermissions import ManagePortal, UndoChanges, ListUndoableChanges
 
-class UndoTool (UniqueObject, SimpleItem):
+class UndoTool (UniqueObject, SimpleItem, ActionProviderBase):
     id = 'portal_undo'
     meta_type = 'CMF Undo Tool'
     # This tool is used to undo changes.
+    _actions = [ActionInformation(id='undo'
+                                , title='Undo'
+                                , action=Expression(
+               text='string: ${portal_url}/undo_form')
+                                , condition=Expression(
+               text='member') 
+                                , permissions=(ListUndoableChanges,)
+                                , category='global'
+                                , visible=1
+                                 )]
 
 
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
+    manage_options = ( ActionProviderBase.manage_options +
+                       SimpleItem.manage_options +
+                       ({ 'label' : 'Overview', 'action' : 'manage_overview' }
                      , 
-                     ) + SimpleItem.manage_options
-
+                     ))
     #
     #   ZMI methods
     #
@@ -46,14 +59,11 @@
     manage_overview = DTMLFile( 'explainUndoTool', _dtmldir )
 
     security.declarePrivate('listActions')
-    def listActions( self, info ):
-        if info.isAnonymous:
-            return []
-        return [ { 'name': 'Undo'
-                 , 'url': 'undo_form'
-                 , 'permissions': [ ListUndoableChanges ]
-                 , 'category': 'global'
-                 } ]
+    def listActions(self, info=None):
+        """
+        List actions available through tool
+        """
+        return self._actions
 
     #
     #   'portal_undo' interface methods


=== CMF/CMFCore/WorkflowTool.py 1.19 => 1.19.4.1 ===
     security = ClassSecurityInfo()
 
-    manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' }
-                     , { 'label' : 'Workflows'
+    manage_options = ( { 'label' : 'Workflows'
                        , 'action' : 'manage_selectWorkflows'
                        }
+                     , { 'label' : 'Overview', 'action' : 'manage_overview' }
                      ) + Folder.manage_options
 
     #