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

Christian Theune ct@gocept.com
Sat, 18 May 2002 13:02:26 -0400


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

Added Files:
      Tag: Zope-3x-branch
	Folder.py FolderLimit.py LoadedFolder.py LoadedFolderFields.py 
	OrderedFolder.py RootFolder.py __init__.py folder.zcml 
Log Message:
Completing OFS.Folder -> OFS.Content.Folder by merging 'ctheune-foldermove-branch' into Zope-3x-branch

=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/Folder.py ===
##############################################################################
#
# 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
from Zope.App.OFS.Memento.IAttributeMementoStorable \
     import IAttributeMementoStorable
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.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,
        IAttributeMementoStorable,
        )

    def __init__(self):
        self.data = OOBTree()

    def objectIds(self):
        """Return a sequence-like object containing the names 
           associated with the objects that appear in the folder
        """
        return self.data.keys()

    def objectValues(self):
        """Return a sequence-like object containing the objects that
           appear in the folder.
        """
        return self.data.values()

    def objectItems(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 getObject(self, name, default=KeyError):
        """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.
        """
        object = self.data.get(name, default)
        if object is KeyError:
            raise KeyError, name
        return object

    def hasObject(self, name):
        """Return true if the named object appears in the folder."""
        return self.data.has_key(name)

    def objectCount(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
        if not self.isAddable(getattr(object,'__implements__', None)):
            raise UnaddableError (self, object, name)
        self.data[name] = object

    def delObject(self, name):
        """Delete the named object from the folder. Raises a KeyError
           if the object is not found."""
        del self.data[name]

    def isAddable(self, interfaces):
        return 1



=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/FolderLimit.py ===
##############################################################################
#
# 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: FolderLimit.py,v 1.1.4.1 2002/05/18 17:02:24 ctheune Exp $
"""

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 self.objectCount() >= self._limit:
            return 1
        else:
            return 0

    #
    ############################################################


=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/LoadedFolder.py ===
##############################################################################
#
# 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: LoadedFolder.py,v 1.1.4.1 2002/05/18 17:02:24 ctheune Exp $

Implemented LoadedFolder Functionality:

- Order Folder items
- Define a max amount of items possible

Todo Functionality:

- Define what content objects can be added (user)
  (* notice isAddable; adding an interfaces service could make
  this functionality more usable TTW)
  + 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


def membership_check(group, item): # use later for more interesting isAddable implementations
    if type(group) is tuple:
        for inter in group:
            if membership_check(inter, item):
                return 1
        return 0
    if type(item) is tuple:
        for inter in item:
            if membership_check(group, inter):
                return 1
        return 0
    return group is item or issubclass(item, group)


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 objectIds(self):
        """Return a sequence-like object containing the names 
           associated with the objects that appear in the folder
        """
        return self._orderedIds


    def objectValues(self):
        """Return a sequence-like object containing the objects that
           appear in the folder.
        """
        result = []
        for id in self.objectIds():
            result.append(self.data[id])

        return tuple(result)


    def objectItems(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.objectIds():
            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 not self.isAddable(getattr(object,'__implements__', None)):
            raise UnaddableError (self, object, name)
        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,)


    def delObject(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)

    def isAddable(self, interfaces):
        return 1 # could return 0 if self.isLimitReached(), and eliminate check above...


=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/LoadedFolderFields.py ===
##############################################################################
#
# 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: LoadedFolderFields.py,v 1.1.4.1 2002/05/18 17:02:24 ctheune Exp $
"""


from Zope.App.Formulator import getField


LimitField = getField('IntegerField')(
    id='limit',
    title='Limit',
    description='Limit of objects in the container.',
    start=1,
    default=1000 )


=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/OrderedFolder.py ===
##############################################################################
#
# 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: OrderedFolder.py,v 1.1.4.1 2002/05/18 17:02:24 ctheune Exp $

"""

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 > self.objectCount() 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 = self.objectCount() - \
                         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))

    #
    ############################################################



=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/RootFolder.py ===
##############################################################################
#
# 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.'


=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/__init__.py ===
##############################################################################
#
# 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.
# 
##############################################################################


=== Added File Zope3/lib/python/Zope/App/OFS/Content/Folder/folder.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:security='http://namespaces.zope.org/security'
   xmlns:zmi='http://namespaces.zope.org/zmi'
>

  <!-- Simple Folder Directives -->

  <zmi:factoryFromClass name="Folder"
                    	class=".Folder."
                    	permission_id="Zope.ManageContent"
                    	title="Son of Folder"
                    	description="Minimal folder" />

  <security:protectClass name=".Folder."
                         permission_id="Zope.View">
    <security:protect 
              interface="Zope.ComponentArchitecture.IServiceManagerContainer.IReadServiceManagerContainer" 
  	      permission_id="Zope.Public" />
    <security:protect 
              interface="Zope.ComponentArchitecture.IServiceManagerContainer.IWriteServiceManagerContainer" 
  	      permission_id="Zope.ManageServices" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainer.IReadContainer"
              permission_id="Zope.View" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainer.IWriteContainer"
              permission_id="Zope.ManageContent" />
  </security:protectClass>

  <!-- XXX Do we really need RootFolder? -->
  <security:protectClass name=".RootFolder." like_unto=".Folder." /> 

  <zmi:tabs for=".Folder.IFolder.">
    <zmi:tab label="Contents" action="contents;view"/>
    <zmi:tab label="Role Permissions" 
             action="RolePermissionsManagement;view"/>
  </zmi:tabs>


  <!-- Loaded Folder Directives -->

  <zmi:factoryFromClass name="LoadedFolder"
                    	class=".LoadedFolder."
                    	permission_id="Zope.ManageContent"
                    	title="Loaded Folder"
                    	description="A Folder having all the goodies." />

  <security:protectClass name=".LoadedFolder."
                         permission_id="Zope.View">
    <security:protect 
              interface="Zope.ComponentArchitecture.IServiceManagerContainer.IReadServiceManagerContainer" 
              permission_id="Zope.Public" />
    <security:protect 
              interface="Zope.ComponentArchitecture.IServiceManagerContainer.IWriteServiceManagerContainer" 
              permission_id="Zope.ManageServices" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainer.IReadContainer"
              permission_id="Zope.View" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainer.IWriteContainer"
              permission_id="Zope.ManageContent" />
    <security:protect
              interface="Zope.App.OFS.Container.IOrderedContainer.IReadOrderedContainer"
              permission_id="Zope.View" />
    <security:protect
              interface="Zope.App.OFS.Container.IOrderedContainer.IWriteOrderedContainer"
              permission_id="Zope.ManageContent" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainerLimit.IReadContainerLimit"
              permission_id="Zope.View" />
    <security:protect
              interface="Zope.App.OFS.Container.IContainerLimit.IWriteContainerLimit"
              permission_id="Zope.ManageContent" />
  </security:protectClass>

  <zmi:tabs for="Zope.App.OFS.Container.IContainerLimit.">
    <zmi:tab label="Limit" action="limit;view"/>
  </zmi:tabs>

  <zmi:tabs for=".LoadedFolder.ILoadedFolder.">
    <zmi:tab label="Contents" action="contents;view"/>
    <zmi:tab label="Role Permissions" 
             action="RolePermissionsManagement;view"/>
  </zmi:tabs>


  <!-- Further Directives -->

  <include package=".Views" file="views.zcml" />

</zopeConfigure>