Bugfix : la méthode « history » de la ZODB a changé d'api.
[Plinn.git] / HugePlinnFolder.py
1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2007 Benoît PIN <benoit.pin@ensmp.fr> #
5 # #
6 # This program is free software; you can redistribute it and/or #
7 # modify it under the terms of the GNU General Public License #
8 # as published by the Free Software Foundation; either version 2 #
9 # of the License, or (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program; if not, write to the Free Software #
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
19 #######################################################################################
20 """ Plinn implementation of CMFBTree
21
22
23
24 """
25
26
27 from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2Base
28 from Products.ZCatalog.Lazy import LazyMap
29 from BTrees.IOBTree import IOBTree
30 from BTrees.OIBTree import OIBTree
31 from Folder import PlinnFolder
32 from zope.event import notify
33 from zope.app.container.contained import notifyContainerModified
34 from events import ObjectPositionModified
35 from zope.component.factory import Factory
36 from Products.CMFCore.permissions import AddPortalFolders, \
37 ManageProperties, \
38 AccessContentsInformation
39 from AccessControl import ClassSecurityInfo
40 from Globals import InitializeClass
41 from types import StringType
42
43
44 class HugePlinnFolder(BTreeFolder2Base, PlinnFolder) :
45 """ Plinn Folder for large set of objects
46 """
47
48 security = ClassSecurityInfo()
49
50 def __init__(self, id, title='') :
51 PlinnFolder.__init__(self, id, title)
52 BTreeFolder2Base.__init__(self, id)
53
54 def _initBTrees(self):
55 super(HugePlinnFolder, self)._initBTrees()
56 self._pos2id_index = IOBTree()
57 self._id2pos_index = OIBTree()
58
59 def _checkId(self, id, allow_dup=0) :
60 PlinnFolder._checkId(self, id, allow_dup)
61 BTreeFolder2Base._checkId(self, id, allow_dup)
62
63 security.declareProtected(AddPortalFolders, 'manage_addHugePlinnFolder')
64 def manage_addHugePlinnFolder(self, id, title='', REQUEST=None) :
65 """ Add new a new HugePlinnFolder object with id *id*.
66 """
67 ob = HugePlinnFolder(id, title)
68 self._setObject(id, ob)
69 if REQUEST is not None :
70 return self.folder_contents(self, REQUEST, portal_status_message='Folder added')
71
72 def _setOb(self, id, object):
73 super(HugePlinnFolder, self)._setOb(id, object)
74 pos = self.objectCount() - 1
75 self._pos2id_index[pos] = id
76 self._id2pos_index[id] = pos
77
78 def _delOb(self, id):
79 pos = self._id2pos_index[id]
80 self._id2pos_index.pop(id)
81
82 for p in xrange(pos+1, self.objectCount()) :
83 ident = self._pos2id_index[p]
84 self._pos2id_index[p-1] = ident
85 self._id2pos_index[ident] = p-1
86
87 self._pos2id_index.pop(self.objectCount()-1)
88
89 super(HugePlinnFolder, self)._delOb(id)
90
91 security.declareProtected(AccessContentsInformation, 'objectIds')
92 def objectIds(self, spec=None) :
93 if spec is not None :
94 return super(HugePlinnFolder, self).objectIds(spec)
95
96 pos2id = lambda pos : self._pos2id_index[pos]
97 return LazyMap(pos2id, xrange(self.objectCount()))
98
99
100
101 security.declareProtected(ManageProperties, 'moveObjectsByDelta')
102 def moveObjectsByDelta(self, ids, delta, subset_ids=None,
103 suppress_events=False):
104 """ Move specified sub-objects by delta.
105 """
106 if isinstance(ids, StringType):
107 ids = (ids,)
108
109 id2pos = self._id2pos_index
110 pos2id = self._pos2id_index
111 for id in ids :
112 oldPosition = id2pos[id]
113 newPosition = max(oldPosition + delta, 0)
114
115 shift = delta > 0 and 1 or -1
116 for p in xrange(oldPosition, newPosition, shift) :
117 ident = pos2id[p+shift]
118 pos2id[p] = ident
119 id2pos[ident] = p
120 if not suppress_events :
121 notify(ObjectPositionModified(self[ident], self, p))
122
123 id2pos[id] = newPosition
124 pos2id[newPosition] = id
125 if not suppress_events :
126 notify(ObjectPositionModified(self[id], self, newPosition))
127
128 if not suppress_events :
129 notifyContainerModified(self)
130
131
132 def getObjectPosition(self, id):
133 """ Get the position of an object by its id.
134 """
135 try :
136 return self._id2pos_index[id]
137 except KeyError :
138 raise ValueError('The object with the id "%s" does not exist.' % id)
139
140
141 InitializeClass(HugePlinnFolder)
142 HugePlinnFolderFactory = Factory(HugePlinnFolder)
143 manage_addHugePlinnFolder = HugePlinnFolder.manage_addHugePlinnFolder.im_func