[Zope-Checkins] CVS: Zope/lib/python/OFS - IOrderSupport.py:1.2 OrderSupport.py:1.2 OrderedFolder.py:1.2 Folder.py:1.102

Yvo Schubbe schubbe@web.de
Thu, 12 Jun 2003 06:21:30 -0400


Update of /cvs-repository/Zope/lib/python/OFS
In directory cvs.zope.org:/tmp/cvs-serv760/lib/python/OFS

Modified Files:
	Folder.py 
Added Files:
	IOrderSupport.py OrderSupport.py OrderedFolder.py 
Log Message:
Merged yuppie-ordersupport-branch:
- Added OrderSupport and OrderedFolder.
- Added optional 'id' argument to Folder constructor.
- Modified main.dtml to play well with Folder and OrderedFolder.


=== Zope/lib/python/OFS/IOrderSupport.py 1.1 => 1.2 ===
--- /dev/null	Thu Jun 12 06:21:30 2003
+++ Zope/lib/python/OFS/IOrderSupport.py	Thu Jun 12 06:20:59 2003
@@ -0,0 +1,110 @@
+##############################################################################
+#
+# Copyright (c) 2003 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
+#
+##############################################################################
+""" Order support interfaces.
+
+$Id$
+"""
+
+from Interface import Interface
+
+
+class IOrderedContainer(Interface):
+    """ Ordered Container interface.
+
+    This interface provides a common mechanism for maintaining ordered
+    collections.
+    """
+
+    def moveObjectsByDelta(ids, delta):
+        """ Move specified sub-objects by delta.
+
+        If delta is higher than the possible maximum, objects will be moved to
+        the bottom. If delta is lower than the possible minimum, objects will
+        be moved to the top.
+
+        The order of the objects specified by ids will always be preserved. So
+        if you don't want to change their original order, make sure the order
+        of ids corresponds to their original order.
+
+        If an object with id doesn't exist an error will be raised.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def moveObjectsUp(ids, delta=1):
+        """ Move specified sub-objects up by delta in container.
+
+        If no delta is specified, delta is 1. See moveObjectsByDelta for more
+        details.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def moveObjectsDown(ids, delta=1):
+        """ Move specified sub-objects down by delta in container.
+
+        If no delta is specified, delta is 1. See moveObjectsByDelta for more
+        details.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def moveObjectsToTop(ids):
+        """ Move specified sub-objects to top of container.
+
+        See moveObjectsByDelta for more details.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def moveObjectsToBottom(ids):
+        """ Move specified sub-objects to bottom of container.
+
+        See moveObjectsByDelta for more details.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def orderObjects(key, reverse=None):
+        """ Order sub-objects by key and direction.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """
+
+    def getObjectPosition(id):
+        """ Get the position of an object by its id.
+
+        Permission -- Access contents information
+
+        Returns -- Position
+        """
+
+    def moveObjectToPosition(id, position):
+        """ Moves specified object to absolute position.
+
+        Permission -- Manage properties
+
+        Returns -- Number of moved sub-objects
+        """


=== Zope/lib/python/OFS/OrderSupport.py 1.1 => 1.2 ===
--- /dev/null	Thu Jun 12 06:21:30 2003
+++ Zope/lib/python/OFS/OrderSupport.py	Thu Jun 12 06:20:59 2003
@@ -0,0 +1,251 @@
+##############################################################################
+#
+# Copyright (c) 2003 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
+#
+##############################################################################
+""" Order support for 'Object Manager'.
+
+$Id$
+"""
+
+from types import StringType
+
+from AccessControl import ClassSecurityInfo
+from AccessControl.Permissions import access_contents_information
+from AccessControl.Permissions import manage_properties
+from DocumentTemplate.sequence import sort
+from Globals import InitializeClass
+
+from IOrderSupport import IOrderedContainer
+from ObjectManager import ObjectManager
+
+
+class OrderSupport:
+    """ Ordered container mixin class.
+    
+    This is an extension to the regular ObjectManager. It saves the objects in
+    order and lets you change the order of the contained objects. This is
+    particular helpful, if the order does not depend on object attributes, but
+    is totally user-specific.
+    """
+
+    __implements__ = IOrderedContainer
+    security = ClassSecurityInfo()
+
+    has_order_support = 1
+    _default_sort_key = 'position'
+    _default_sort_reverse = 0
+
+    manage_options = ( { 'label':'Contents',
+                         'action':'manage_main',
+                         'help':('OFSP','OrderSupport_Contents.stx') }
+                     ,
+                     )
+
+    #
+    #   ZMI Methods
+    #
+
+    security.declareProtected(manage_properties, 'manage_move_objects_up')
+    def manage_move_objects_up(self, REQUEST, ids=None, delta=None):
+        """ Move specified sub-objects up by delta in container.
+        """
+        if ids:
+            try:
+                attempt = self.moveObjectsUp(ids, delta)
+                message = '%d item%s moved up.' % ( attempt,
+                                              ( (attempt!=1) and 's' or '' ) )
+            except ValueError, errmsg:
+                message = 'Error: %s' % (errmsg)
+        else:
+            message = 'Error: No items were specified!'
+        return self.manage_main(self, REQUEST, skey='position',
+                                manage_tabs_message=message)
+
+    security.declareProtected(manage_properties, 'manage_move_objects_down')
+    def manage_move_objects_down(self, REQUEST, ids=None, delta=None):
+        """ Move specified sub-objects down by delta in container.
+        """
+        if ids:
+            try:
+                attempt = self.moveObjectsDown(ids, delta)
+                message = '%d item%s moved down.' % ( attempt,
+                                              ( (attempt!=1) and 's' or '' ) )
+            except ValueError, errmsg:
+                message = 'Error: %s' % (errmsg)
+        else:
+            message = 'Error: No items were specified!'
+        return self.manage_main(self, REQUEST, skey='position',
+                                manage_tabs_message=message)
+
+    security.declareProtected(manage_properties, 'manage_move_objects_to_top')
+    def manage_move_objects_to_top(self, REQUEST, ids=None):
+        """ Move specified sub-objects to top of container.
+        """
+        if ids:
+            try:
+                attempt = self.moveObjectsToTop(ids)
+                message = '%d item%s moved to top.' % ( attempt,
+                                              ( (attempt!=1) and 's' or '' ) )
+            except ValueError, errmsg:
+                message = 'Error: %s' % (errmsg)
+        else:
+            message = 'Error: No items were specified!'
+        return self.manage_main(self, REQUEST, skey='position',
+                                manage_tabs_message=message)
+
+    security.declareProtected(manage_properties, 'manage_move_objects_to_bottom')
+    def manage_move_objects_to_bottom(self, REQUEST, ids=None):
+        """ Move specified sub-objects to bottom of container.
+        """
+        if ids:
+            try:
+                attempt = self.moveObjectsToBottom(ids)
+                message = '%d item%s moved to bottom.' % ( attempt,
+                                              ( (attempt!=1) and 's' or '' ) )
+            except ValueError, errmsg:
+                message = 'Error: %s' % (errmsg)
+        else:
+            message = 'Error: No items were specified!'
+        return self.manage_main(self, REQUEST, skey='position',
+                                manage_tabs_message=message)
+
+    security.declareProtected(manage_properties, 'manage_set_default_sorting')
+    def manage_set_default_sorting(self, REQUEST, key, reverse):
+        """ Set default sorting key and direction.
+        """
+        self.setDefaultSorting(key, reverse)
+        return self.manage_main(self, REQUEST)
+
+
+    #
+    #   IOrderedContainer Interface Methods
+    #
+
+    security.declareProtected(manage_properties, 'moveObjectsByDelta')
+    def moveObjectsByDelta(self, ids, delta):
+        """ Move specified sub-objects by delta.
+        """
+        if type(ids) is StringType:
+            ids = (ids,)
+        min_position = 0
+        objects = list(self._objects)
+        obj_dict = {}
+        for obj in self._objects:
+            obj_dict[ obj['id'] ] = obj
+        # unify moving direction
+        if delta > 0:
+            ids = list(ids)
+            ids.reverse()
+            objects.reverse()
+        counter = 0
+
+        for id in ids:
+            try:
+                object = obj_dict[id]
+            except KeyError:
+                raise (ValueError,
+                       'The object with the id "%s" does not exist.' % id)
+            old_position = objects.index(object)
+            new_position = max( old_position - abs(delta), min_position )
+            if new_position == min_position:
+                min_position += 1
+            if not old_position == new_position:
+                objects.remove(object)
+                objects.insert(new_position, object)
+                counter += 1
+
+        if counter > 0:
+            if delta > 0:
+                objects.reverse()
+            self._objects = tuple(objects)
+
+        return counter
+
+    security.declareProtected(manage_properties, 'moveObjectsUp')
+    def moveObjectsUp(self, ids, delta=1):
+        """ Move specified sub-objects up by delta in container.
+        """
+        return self.moveObjectsByDelta(ids, -delta)
+
+    security.declareProtected(manage_properties, 'moveObjectsDown')
+    def moveObjectsDown(self, ids, delta=1):
+        """ Move specified sub-objects down by delta in container.
+        """
+        return self.moveObjectsByDelta(ids, delta)
+
+    security.declareProtected(manage_properties, 'moveObjectsToTop')
+    def moveObjectsToTop(self, ids):
+        """ Move specified sub-objects to top of container.
+        """
+        return self.moveObjectsByDelta( ids, -len(self._objects) )
+
+    security.declareProtected(manage_properties, 'moveObjectsToBottom')
+    def moveObjectsToBottom(self, ids):
+        """ Move specified sub-objects to bottom of container.
+        """
+        return self.moveObjectsByDelta( ids, len(self._objects) )
+
+    security.declareProtected(manage_properties, 'orderObjects')
+    def orderObjects(self, key, reverse=None):
+        """ Order sub-objects by key and direction.
+        """
+        ids = [ id for id, obj in sort( self.objectItems(),
+                                        ( (key, 'cmp', 'asc'), ) ) ]
+        if reverse:
+            ids.reverse()
+        return self.moveObjectsByDelta( ids, -len(self._objects) )
+
+    security.declareProtected(access_contents_information,
+                              'getObjectPosition')
+    def getObjectPosition(self, id):
+        """ Get the position of an object by its id.
+        """
+        ids = self.objectIds()
+        if id in ids:
+            return ids.index(id)
+        raise ValueError, 'The object with the id "%s" does not exist.' % id
+
+    security.declareProtected(manage_properties, 'moveObjectToPosition')
+    def moveObjectToPosition(self, id, position):
+        """ Move specified object to absolute position.
+        """        
+        delta = position - self.getObjectPosition(id)
+        return self.moveObjectsByDelta(id, delta)
+
+    security.declareProtected(access_contents_information, 'getDefaultSorting')
+    def getDefaultSorting(self):
+        """ Get default sorting key and direction.
+        """
+        return self._default_sort_key, self._default_sort_reverse
+
+    security.declareProtected(manage_properties, 'setDefaultSorting')
+    def setDefaultSorting(self, key, reverse):
+        """ Set default sorting key and direction.
+        """
+        self._default_sort_key = key
+        self._default_sort_reverse = reverse and 1 or 0
+
+
+    #
+    #   Override Inherited Method of ObjectManager Subclass
+    #
+
+    _old_manage_renameObject = ObjectManager.inheritedAttribute(
+                                                        'manage_renameObject')
+    def manage_renameObject(self, id, new_id, REQUEST=None):
+        """ Rename a particular sub-object without changing its position.
+        """
+        old_position = self.getObjectPosition(id)
+        result = self._old_manage_renameObject(id, new_id, REQUEST)
+        self.moveObjectToPosition(new_id, old_position)
+        return result
+
+InitializeClass(OrderSupport)


=== Zope/lib/python/OFS/OrderedFolder.py 1.1 => 1.2 ===
--- /dev/null	Thu Jun 12 06:21:30 2003
+++ Zope/lib/python/OFS/OrderedFolder.py	Thu Jun 12 06:20:59 2003
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# Copyright (c) 2003 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
+#
+##############################################################################
+""" 'Folder' with order support.
+
+$Id$
+"""
+
+from AccessControl import getSecurityManager
+from AccessControl import Unauthorized
+from AccessControl.Permissions import add_page_templates
+from AccessControl.Permissions import add_user_folders
+from Globals import DTMLFile
+
+from Folder import Folder
+from OrderSupport import OrderSupport
+
+manage_addOrderedFolderForm = DTMLFile('dtml/addOrderedFolder', globals())
+
+def manage_addOrderedFolder(self, id, title='', createPublic=0, createUserF=0,
+                            REQUEST=None):
+    """Add a new ordered Folder object with id *id*.
+
+    If the 'createPublic' and 'createUserF' parameters are set to any true
+    value, an 'index_html' and a 'UserFolder' objects are created respectively
+    in the new folder.
+    """
+    ob = OrderedFolder(id)
+    ob.title = title
+    self._setObject(id, ob)
+    ob = self._getOb(id)
+
+    checkPermission = getSecurityManager().checkPermission
+
+    if createUserF:
+        if not checkPermission(add_user_folders, ob):
+            raise Unauthorized, (
+                  'You are not authorized to add User Folders.'
+                  )
+        ob.manage_addUserFolder()
+
+    if createPublic:
+        if not checkPermission(add_page_templates, ob):
+            raise Unauthorized, (
+                  'You are not authorized to add Page Templates.'
+                  )
+        ob.manage_addProduct['PageTemplates'].manage_addPageTemplate(
+            id='index_html', title='')
+
+    if REQUEST:
+        return self.manage_main(self, REQUEST, update_menu=1)
+
+
+class OrderedFolder(OrderSupport, Folder):
+    """ Extends the default Folder by order support.
+    """
+    __implements__ = (OrderSupport.__implements__,
+                      Folder.__implements__)
+    meta_type='Folder (Ordered)'
+
+    manage_options = ( OrderSupport.manage_options +
+                       Folder.manage_options[1:] )


=== Zope/lib/python/OFS/Folder.py 1.101 => 1.102 ===
--- Zope/lib/python/OFS/Folder.py:1.101	Wed Aug 14 17:42:56 2002
+++ Zope/lib/python/OFS/Folder.py	Thu Jun 12 06:20:59 2003
@@ -22,10 +22,11 @@
 import Globals, SimpleItem, ObjectManager, PropertyManager
 import AccessControl.Role, webdav.Collection, FindSupport
 from webdav.WriteLockInterface import WriteLockInterface
+from AccessControl import getSecurityManager
 from AccessControl import Unauthorized
-
+from AccessControl.Permissions import add_page_templates
+from AccessControl.Permissions import add_user_folders
 from Globals import DTMLFile
-from AccessControl import getSecurityManager
 
 
 manage_addFolderForm=DTMLFile('dtml/folderAdd', globals())
@@ -40,23 +41,22 @@
     value, an 'index_html' and a 'UserFolder' objects are created respectively
     in the new folder.
     """
-    ob=Folder()
-    ob.id=str(id)
-    ob.title=title
+    ob = Folder(id)
+    ob.title = title
     self._setObject(id, ob)
-    ob=self._getOb(id)
+    ob = self._getOb(id)
 
     checkPermission=getSecurityManager().checkPermission
 
     if createUserF:
-        if not checkPermission('Add User Folders', ob):
+        if not checkPermission(add_user_folders, ob):
             raise Unauthorized, (
                   'You are not authorized to add User Folders.'
                   )
         ob.manage_addUserFolder()
 
     if createPublic:
-        if not checkPermission('Add Page Templates', ob):
+        if not checkPermission(add_page_templates, ob):
             raise Unauthorized, (
                   'You are not authorized to add Page Templates.'
                   )
@@ -67,7 +67,6 @@
         return self.manage_main(self, REQUEST, update_menu=1)
 
 
-
 class Folder(
     ObjectManager.ObjectManager,
     PropertyManager.PropertyManager,
@@ -100,5 +99,8 @@
 
     __ac_permissions__=()
 
+    def __init__(self, id=None):
+        if id is not None:
+            self.id = str(id)
 
 Globals.default__class_init__(Folder)