[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Folder - Folder.py:1.2 FolderLimit.py:1.2 LoadedFolder.py:1.2 LoadedFolderFields.py:1.2 OrderedFolder.py:1.2 RootFolder.py:1.2 __init__.py:1.2 folder.zcml:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:28:31 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Folder
In directory cvs.zope.org:/tmp/cvs-serv17445/lib/python/Zope/App/OFS/Content/Folder

Added Files:
	Folder.py FolderLimit.py LoadedFolder.py LoadedFolderFields.py 
	OrderedFolder.py RootFolder.py __init__.py folder.zcml 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/Folder.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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 Zope.App.OFS.Container.IContainer import IContainer
+
+import Persistence
+from Persistence.BTrees.OOBTree import OOBTree
+from Zope.ComponentArchitecture.ServiceManagerContainer \
+     import ServiceManagerContainer
+
+from Zope.ComponentArchitecture.IServiceManagerContainer import \
+     IServiceManagerContainer
+from types import StringTypes
+from Zope.App.OFS.Annotation.IAnnotatable import IAnnotatable
+from Zope.App.OFS.Container.Exceptions import UnaddableError
+
+class IFolder(IContainer, IServiceManagerContainer):
+    """The standard Zope Folder object interface."""
+
+class Folder(Persistence.Persistent, ServiceManagerContainer):
+    """The standard Zope Folder implementation."""
+
+    __implements__ = IFolder, IAnnotatable
+    
+    def __init__(self):
+        self.data = OOBTree()
+
+    def keys(self):
+        """Return a sequence-like object containing the names 
+           associated with the objects that appear in the folder
+        """
+        return self.data.keys()
+
+    def __iter__(self):
+        return iter(self.data.keys())
+
+    def values(self):
+        """Return a sequence-like object containing the objects that
+           appear in the folder.
+        """
+        return self.data.values()
+
+    def items(self):
+        """Return a sequence-like object containing tuples of the form
+           (name, object) for the objects that appear in the folder.
+        """
+        return self.data.items()
+
+    def __getitem__(self, name):
+        """Return the named object, or the value of the default 
+           argument if given and the named object is not found.
+           If no default is given and the object is not found a
+           KeyError is raised.
+        """
+        return self.data[name]
+
+    def get(self, name, default=None):
+        """Return the named object, or the value of the default 
+           argument if given and the named object is not found.
+           If no default is given and the object is not found a
+           KeyError is raised.
+        """
+        return self.data.get(name, default)
+
+    def __contains__(self, name):
+        """Return true if the named object appears in the folder."""
+        return self.data.has_key(name)
+
+    def __len__(self):
+        """Return the number of objects in the folder."""
+        return len(self.data)
+
+    def setObject(self, name, object):
+        """Add the given object to the folder under the given name."""
+        if type(name) in StringTypes and len(name)==0:
+            raise ValueError
+        self.data[name] = object
+        return name
+
+    def __delitem__(self, name):
+        """Delete the named object from the folder. Raises a KeyError
+           if the object is not found."""
+        del self.data[name]
+


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/FolderLimit.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+
+Revision information: 
+$Id$
+"""
+
+from Zope.App.OFS.Container.IContainerLimit import IContainerLimit
+from Zope.App.OFS.Container.Exceptions import UnaddableError
+
+
+class FolderLimitExceededError(UnaddableError):
+    """Exception that is raised, when the limit of the folder was
+       reached."""
+    pass
+
+
+class FolderLimit:
+    """Implements a feature that allows to restrict the amount of items in
+       a Folder.
+    """
+
+    __implements__ =  IContainerLimit
+
+    _limit = 1000
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.App.OFS.IContainerLimit
+
+    def setLimit(self, limit):
+        '''See interface IContainerLimit'''
+        self._limit = limit
+
+
+    def getLimit(self):
+        '''See interface IContainerLimit'''
+        return self._limit
+
+
+    def isLimitReached(self):
+        '''See interface IContainerLimit'''
+        if len(self) >= self._limit:
+            return 1
+        else:
+            return 0
+
+    #
+    ############################################################


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/LoadedFolder.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+Revision information: 
+$Id$
+
+Implemented LoadedFolder Functionality:
+
+- Order Folder items
+- Define a max amount of items possible
+
+Todo Functionality:
+
+- Define what content objects can be added (user)
+  + add the option to the configuration zpt
+  + how does the security work for this? like if this folder is
+    created under a folder that doesnt allow images for example?
+    so need to figure out how to get a list of "allowed" content
+    objects.  also, will what can be added to this folder be
+    static or dynamic in the sence of if security settings change
+    will this folder know about it?
+"""
+
+from Folder import Folder, IFolder
+from FolderLimit import FolderLimit, FolderLimitExceededError
+from OrderedFolder import OrderedFolder
+from types import StringTypes
+
+from Zope.App.OFS.Container.Exceptions import UnaddableError
+
+class ILoadedFolder(IFolder):
+    """The standard Zope Loaded Folder object interface."""
+
+class LoadedFolder(Folder, FolderLimit, OrderedFolder):
+    """Implements some nice additional features to the regular
+       Folder.
+    """
+
+    __implements__ = (ILoadedFolder, Folder.__implements__,
+                      FolderLimit.__implements__, OrderedFolder.__implements__)
+
+
+    # XXX Reimplementation of some of the IReadContainer API. Shrug.
+    
+    def keys(self):
+        """Return a sequence-like object containing the names 
+           associated with the objects that appear in the folder
+        """
+        return self._orderedIds
+
+
+    def values(self):
+        """Return a sequence-like object containing the objects that
+           appear in the folder.
+        """
+        result = []
+        for id in self.keys():
+            result.append(self.data[id])
+
+        return tuple(result)
+
+
+    def items(self):
+        """Return a sequence-like object containing tuples of the form
+           (name, object) for the objects that appear in the folder.
+        """
+        result = []
+        for id in self.keys():
+            result.append((id, self.data[id]))
+
+        return result
+
+
+    # XXX Reimplementation of some of the IWriteContainer API. Shrug again.
+
+    def setObject(self, name, object):
+        """Add the given object to the folder under the given name."""
+        if type(name) in StringTypes and len(name)==0:
+            raise ValueError
+        if self.isLimitReached():
+            raise FolderLimitExceededError(self, object,
+                       'The folder\'s limit (%d item%s) was exeeded.' %
+                       (self.getLimit(), self.getLimit()==1 and "" or "s" ))
+        else:
+            self.data[name] = object
+            if name not in self._orderedIds:
+                self._orderedIds += (name,)
+
+        return name
+
+    def __delitem__(self, name):
+        """Delete the named object from the folder. Raises a KeyError
+           if the object is not found."""
+        del self.data[name]
+        ids = list(self._orderedIds)
+        ids.remove(name)
+        self._orderedIds = tuple(ids)


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/LoadedFolderFields.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+
+$Id$
+"""
+
+
+from Zope.App.Formulator import getField
+
+
+LimitField = getField('IntegerField')(
+    id='limit',
+    title='Limit',
+    description='Limit of objects in the container.',
+    start=1,
+    default=1000 )


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/OrderedFolder.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################
+"""
+Revision information: 
+$Id$
+
+"""
+
+from Zope.App.OFS.Container.IOrderedContainer import IOrderedContainer
+from types import StringType
+
+
+class OrderedFolder:
+    """Adds the Ordering Feature to a Folder
+    """
+
+    __implements__ = IOrderedContainer
+
+    _orderedIds = ()
+
+
+    def moveObjectsByPositions(self, ids, positionDelta):
+        """ """
+
+        if type(ids) is StringType:
+            ids = (ids,)
+
+        # Interestingly enough, we need to switch the order when
+        # moving, so that the movements won't cancel each
+        # other
+        if positionDelta > 0:
+            ids = list(ids)
+            ids.reverse()
+            
+        moved_objects = 0
+        
+        for id in ids:
+            old_position = self.getObjectPosition(id)
+            new_position = old_position + positionDelta
+            # Make sure the new position makes sense and is valid
+            if not (old_position == new_position  or
+                    new_position > len(self) or
+                    new_position < 0):
+                
+                id_list = list(self._orderedIds)
+                # now delete the entry ...
+                id_list.remove(id)
+                # ... and now add it again
+                id_list.insert(new_position, id)
+                self._orderedIds = tuple(id_list)
+
+                moved_objects += 1
+
+        return moved_objects
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.App.OFS.IOrderedContainer
+
+    def getObjectPosition(self, id):
+        '''See interface IOrderedContainer'''
+
+        if id in self._orderedIds:
+            return list(self._orderedIds).index(id)
+        else:
+            # If the object was not found, throw an error.
+            # Yeah, that is good raise 'ObjectNotFound',
+            raise ( 'ObjectNotFound',
+                    'The object named %s was not found.' %id)
+
+
+    def moveObjectsDown(self, ids):
+        '''See interface IOrderedContainer'''
+        return self.moveObjectsByPositions(ids, +1)
+
+
+    def moveObjectsUp(self, ids):
+        '''See interface IOrderedContainer'''
+        return self.moveObjectsByPositions(ids, -1)
+
+
+    def moveObjectsToTop(self, ids):
+        '''See interface IOrderedContainer'''
+        if type(ids) is StringType:
+            ids = (ids,)
+
+        position_delta = - self.getObjectPosition(ids[0])
+        return self.moveObjectsByPositions(ids, position_delta)
+
+
+    def moveObjectsToBottom(self, ids):
+        '''See interface IOrderedContainer'''
+        if type(ids) is StringType:
+            ids = (ids,)
+
+        # Whee, we will do the reverse twice, but for going to the bottom
+        # there is no other choice.
+        ids = list(ids)
+        ids.reverse()
+
+        position_delta = len(self) - self.getObjectPosition(ids[-1]) - 1
+
+        return self.moveObjectsByPositions(ids, position_delta)
+
+
+    def moveObjectToPosition(self, id, position):
+        '''See interface IOrderedContainer'''
+        return self.moveObjectsByPositions(id,
+                   position - self.getObjectPosition(id))
+
+    #
+    ############################################################
+


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/RootFolder.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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 Folder import IFolder, Folder
+
+
+class IRootFolder(IFolder):
+    """The standard Zope root Folder object interface."""
+
+
+class RootFolder(Folder):
+    """The standard Zope root Folder implementation."""
+
+    __implements__ = Folder.__implements__, IRootFolder
+
+    def __call__(self):
+        return 'You have reached the wrong number (but the right ' \
+               'object!). Please try again later.'


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/__init__.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 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.
+# 
+##############################################################################


=== Zope3/lib/python/Zope/App/OFS/Content/Folder/folder.zcml 1.1 => 1.2 ===
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:security='http://namespaces.zope.org/security'
+   xmlns:zmi='http://namespaces.zope.org/zmi'
+>
+
+  <!-- Simple Folder Directives -->
+
+  <content class=".Folder.">
+    <zmi:factory
+        id="Folder"
+        permission="Zope.ManageContent"
+        title="Son of Folder"
+        description="Minimal folder" />
+    <security:require
+        permission="Zope.View" />
+    <security:allow
+        interface="Zope.ComponentArchitecture.IServiceManagerContainer.IReadServiceManagerContainer" 
+        />
+    <security:require
+        permission="Zope.ManageServices"
+        interface="Zope.ComponentArchitecture.IServiceManagerContainer.IWriteServiceManagerContainer" 
+        />
+    <security:require
+        permission="Zope.View"
+        interface="Zope.App.OFS.Container.IContainer.IReadContainer" />
+    <security:require
+        permission="Zope.ManageContent"
+        interface="Zope.App.OFS.Container.IContainer.IWriteContainer" />
+  </content>
+
+  <!-- XXX Do we really need RootFolder? -->
+  <content class=".RootFolder.">
+    <security:mimic class=".Folder." />
+  </content>
+
+  <zmi:tabs for=".Folder.IFolder.">
+    <zmi:tab label="Contents" action="@@index.html"/>
+    <zmi:tab label="Role Permissions" 
+             action="@@AllRolePermissions.html"/>
+  </zmi:tabs>
+
+
+  <!-- Loaded Folder Directives -->
+  <content class=".LoadedFolder.">
+    <zmi:factory
+        id="LoadedFolder"
+        permission="Zope.ManageContent"
+        title="Loaded Folder"
+        description="A Folder having all the goodies." />
+
+    <security:require
+        permission="Zope.View" />
+    <security:allow
+        interface="Zope.ComponentArchitecture.IServiceManagerContainer.IReadServiceManagerContainer" 
+        />
+    <security:require
+        permission="Zope.ManageServices"
+        interface="Zope.ComponentArchitecture.IServiceManagerContainer.IWriteServiceManagerContainer" 
+        />
+    <security:require
+        permission="Zope.View"
+        interface="Zope.App.OFS.Container.IContainer.IReadContainer"
+        />
+    <security:require
+        permission="Zope.ManageContent"
+        interface="Zope.App.OFS.Container.IContainer.IWriteContainer"
+        />
+    <security:require
+        permission="Zope.View"
+        interface="Zope.App.OFS.Container.IOrderedContainer.IReadOrderedContainer"
+         />
+    <security:require
+        permission="Zope.ManageContent"
+        interface="Zope.App.OFS.Container.IOrderedContainer.IWriteOrderedContainer"
+        />
+    <security:require
+        permission="Zope.View"
+        interface="Zope.App.OFS.Container.IContainerLimit.IReadContainerLimit"
+        />
+    <security:require
+        permission="Zope.ManageContent"
+        interface="Zope.App.OFS.Container.IContainerLimit.IWriteContainerLimit"
+        />
+  </content>
+  
+  <adapter
+      factory="Zope.App.OFS.Annotation.AttributeAnnotations."
+      provides="Zope.App.OFS.Annotation.IAnnotations."
+      for=".Folder.IFolder." />
+
+  <zmi:tabs for="Zope.App.OFS.Container.IContainerLimit.">
+    <zmi:tab label="Limit" action="@@FolderLimitEditForm.html"/>
+  </zmi:tabs>
+
+  <zmi:tabs for=".LoadedFolder.ILoadedFolder.">
+    <zmi:tab label="Contents" action="@@index.html"/>
+    <zmi:tab label="Role Permissions" 
+             action="@@AllRolePermissions.html"/>
+  </zmi:tabs>
+
+
+  <!-- Further Directives -->
+
+  <include package=".Views" file="views.zcml" />
+
+</zopeConfigure>