X-Git-Url: https://svn.cri.ensmp.fr/git/Plinn.git/blobdiff_plain/9e85dc4e389607f4a944c97f476235321b751c58..af9b2459c45635addd229e3265bd0018d71fde3b:/HugePlinnFolder.py?ds=sidebyside

diff --git a/HugePlinnFolder.py b/HugePlinnFolder.py
index 2348316..563bf18 100644
--- a/HugePlinnFolder.py
+++ b/HugePlinnFolder.py
@@ -31,116 +31,192 @@ from BTrees.OIBTree import OIBTree
 from Folder import PlinnFolder
 from zope.event import notify
 try :
-	from zope.app.container.contained import notifyContainerModified
+    from zope.app.container.contained import notifyContainerModified
 except ImportError :
-	## Zope-2.13 compat
-	from zope.container.contained import notifyContainerModified
+    ## Zope-2.13 compat
+    from zope.container.contained import notifyContainerModified
 from events import ObjectPositionModified
 from zope.component.factory import Factory
 from Products.CMFCore.permissions import AddPortalFolders, \
-										 ManageProperties, \
-										 AccessContentsInformation
+                                         ManageProperties, \
+                                         AccessContentsInformation
 from AccessControl import ClassSecurityInfo
 from Globals import InitializeClass
 from types import StringType
 
 
 class HugePlinnFolder(BTreeFolder2Base, PlinnFolder) :
-	""" Plinn Folder for large set of objects
-	"""
-	
-	security = ClassSecurityInfo()
-	
-	def __init__(self, id, title='') :
-		PlinnFolder.__init__(self, id, title)
-		BTreeFolder2Base.__init__(self, id)
-
-	def _initBTrees(self):
-		super(HugePlinnFolder, self)._initBTrees()
-		self._pos2id_index = IOBTree()
-		self._id2pos_index = OIBTree()
-	
-	def _checkId(self, id, allow_dup=0) :
-		PlinnFolder._checkId(self, id, allow_dup)
-		BTreeFolder2Base._checkId(self, id, allow_dup)
-	
-	security.declareProtected(AddPortalFolders, 'manage_addHugePlinnFolder')
-	def manage_addHugePlinnFolder(self, id, title='', REQUEST=None) :
-		""" Add new a new HugePlinnFolder object with id *id*.
-		"""
-		ob = HugePlinnFolder(id, title)
-		self._setObject(id, ob)
-		if REQUEST is not None :
-			return self.folder_contents(self, REQUEST, portal_status_message='Folder added')
-	
-	def _setOb(self, id, object):
-		super(HugePlinnFolder, self)._setOb(id, object)
-		pos = self.objectCount() - 1
-		self._pos2id_index[pos] = id
-		self._id2pos_index[id] = pos
-	
-	def _delOb(self, id):
-		pos = self._id2pos_index[id]
-		self._id2pos_index.pop(id)
-		 	
-		for p in xrange(pos+1, self.objectCount()) :
-			ident = self._pos2id_index[p]
-			self._pos2id_index[p-1] = ident
-			self._id2pos_index[ident] = p-1
-		
-		self._pos2id_index.pop(self.objectCount()-1)
-
-		super(HugePlinnFolder, self)._delOb(id)
-			
-	security.declareProtected(AccessContentsInformation, 'objectIds')
-	def objectIds(self, spec=None) :
-		if spec is not None :
-			return super(HugePlinnFolder, self).objectIds(spec)
-		
-		pos2id = lambda pos : self._pos2id_index[pos]
-		return LazyMap(pos2id, xrange(self.objectCount()))
-		
-
-
-	security.declareProtected(ManageProperties, 'moveObjectsByDelta')
-	def moveObjectsByDelta(self, ids, delta, subset_ids=None,
-						   suppress_events=False):
-		""" Move specified sub-objects by delta.
-		"""
-		if isinstance(ids, StringType):
-			ids = (ids,)
-
-		id2pos = self._id2pos_index
-		pos2id = self._pos2id_index
-		for id in ids :
-			oldPosition = id2pos[id]
-			newPosition = max(oldPosition + delta, 0)
-			
-			shift = delta > 0 and 1 or -1
-			for p in xrange(oldPosition, newPosition, shift) :
-				ident = pos2id[p+shift]
-				pos2id[p] = ident
-				id2pos[ident] = p
-				if not suppress_events :
-					notify(ObjectPositionModified(self[ident], self, p))
-			
-			id2pos[id] = newPosition
-			pos2id[newPosition] = id
-			if not suppress_events :
-				notify(ObjectPositionModified(self[id], self, newPosition))
-		
-		if not suppress_events :
-			notifyContainerModified(self)
-	
-	
-	def getObjectPosition(self, id):
-		""" Get the position of an object by its id.
-		"""
-		try :
-			return self._id2pos_index[id]
-		except KeyError :
-			raise ValueError('The object with the id "%s" does not exist.' % id)
-	
+    """ Plinn Folder for large set of objects
+    """
+    
+    security = ClassSecurityInfo()
+    
+    __getitem__ = PlinnFolder.__getitem__
+    
+    def __init__(self, id, title='') :
+        PlinnFolder.__init__(self, id, title)
+        BTreeFolder2Base.__init__(self, id)
+
+    def _initBTrees(self):
+        super(HugePlinnFolder, self)._initBTrees()
+        self._pos2id_index = IOBTree()
+        self._id2pos_index = OIBTree()
+    
+    def _checkId(self, id, allow_dup=0) :
+        PlinnFolder._checkId(self, id, allow_dup)
+        BTreeFolder2Base._checkId(self, id, allow_dup)
+    
+    security.declareProtected(AddPortalFolders, 'manage_addHugePlinnFolder')
+    def manage_addHugePlinnFolder(self, id, title='', REQUEST=None) :
+        """ Add new a new HugePlinnFolder object with id *id*.
+        """
+        ob = HugePlinnFolder(id, title)
+        self._setObject(id, ob)
+        if REQUEST is not None :
+            return self.folder_contents(self, REQUEST, portal_status_message='Folder added')
+    
+    def _setOb(self, id, object):
+        super(HugePlinnFolder, self)._setOb(id, object)
+        pos = self.objectCount() - 1
+        self._pos2id_index[pos] = id
+        self._id2pos_index[id] = pos
+    
+    def _delOb(self, id):
+        pos = self._id2pos_index[id]
+        self._id2pos_index.pop(id)
+            
+        for p in xrange(pos+1, self.objectCount()) :
+            ident = self._pos2id_index[p]
+            self._pos2id_index[p-1] = ident
+            self._id2pos_index[ident] = p-1
+        
+        self._pos2id_index.pop(self.objectCount()-1)
+
+        super(HugePlinnFolder, self)._delOb(id)
+            
+    security.declareProtected(AccessContentsInformation, 'objectIds')
+    def objectIds(self, spec=None) :
+        if spec is not None :
+            return super(HugePlinnFolder, self).objectIds(spec)
+        
+        pos2id = lambda pos : self._pos2id_index[pos]
+        return LazyMap(pos2id, xrange(self.objectCount()))
+        
+
+
+    security.declareProtected(ManageProperties, 'moveObjectsByDelta')
+    def moveObjectsByDelta(self, ids, delta, subset_ids=None,
+                           suppress_events=False):
+        """ Move specified sub-objects by delta.
+        """
+        if isinstance(ids, StringType):
+            ids = (ids,)
+
+        id2pos = self._id2pos_index
+        pos2id = self._pos2id_index
+        for id in ids :
+            oldPosition = id2pos[id]
+            newPosition = max(oldPosition + delta, 0)
+            
+            shift = delta > 0 and 1 or -1
+            for p in xrange(oldPosition, newPosition, shift) :
+                ident = pos2id[p+shift]
+                pos2id[p] = ident
+                id2pos[ident] = p
+                if not suppress_events :
+                    notify(ObjectPositionModified(self[ident], self, p))
+            
+            id2pos[id] = newPosition
+            pos2id[newPosition] = id
+            if not suppress_events :
+                notify(ObjectPositionModified(self[id], self, newPosition))
+        
+        if not suppress_events :
+            notifyContainerModified(self)
+    
+    security.declareProtected(ManageProperties, 'moveObjectsAfter')
+    def moveObjectsAfter(self, ids, targetId, suppress_events=False):
+        assert targetId not in ids
+
+        id2pos = self._id2pos_index
+        pos2id = self._pos2id_index
+        targetPos = id2pos[targetId]
+        minMovedPos = min([id2pos[id] for id in ids])
+        maxMovedPos = max([id2pos[id] for id in ids])
+        
+        for id in ids :
+            assert id == pos2id.pop(id2pos.pop(id))
+        
+        id2posUpdate = {}
+        pos2idUpdate = {}
+
+        # moved before the firt item position
+        if targetPos < minMovedPos :
+            for i, id in enumerate(ids) :
+                pos = i + targetPos + 1
+                id2posUpdate[id] = pos
+                pos2idUpdate[pos] = id
+
+            for id in IndexIterator(pos2id, maxMovedPos, start=targetPos+1):
+                pos = pos + 1
+                id2posUpdate[id] = pos
+                pos2idUpdate[pos] = id
+            
+        elif targetPos > minMovedPos and targetPos < maxMovedPos :
+            print minMovedPos, maxMovedPos, targetPos
+            print "déposé entre la première et la dernière de la sélection"
+            raise NotImplementedError()
+        else :
+            print minMovedPos, maxMovedPos, targetPos
+            print "déposé après la dernière"
+            raise NotImplementedError()
+        
+        id2pos.update(id2posUpdate)
+        pos2id.update(pos2idUpdate)
+        
+        # just for debug
+        for pos in xrange(len(self)) :
+            assert pos2id.has_key(pos)
+            assert id2pos.has_key(pos2id[pos])
+        if not suppress_events :
+            for id, pos in id2posUpdate.items() :
+                notify(ObjectPositionModified(self[id], self, pos))
+                
+            notifyContainerModified(self)
+    
+    def getObjectPosition(self, id):
+        """ Get the position of an object by its id.
+        """
+        try :
+            return self._id2pos_index[id]
+        except KeyError :
+            raise ValueError('The object with the id "%s" does not exist.' % id)
+
+
+class IndexIterator :
+    def __init__(self, d, maxPos, start=0, length=None) :
+        self.d = d
+        self.pos = start
+        self.maxPos = maxPos
+        self.length = length
+        self.fetchedValuesCpt = 0
+    
+    def __iter__(self) :
+        return self
+    
+    def next(self) :
+        try :
+            if self.pos > self.maxPos or \
+                 self.fetchedValuesCpt == self.length:
+                raise StopIteration
+            v = self.d[self.pos]
+            self.pos = self.pos + 1
+            self.fetchedValuesCpt = self.fetchedValuesCpt + 1
+            return v
+        except KeyError :
+            self.pos = self.pos + 1
+            return self.next()
+    
 
 InitializeClass(HugePlinnFolder)
 HugePlinnFolderFactory = Factory(HugePlinnFolder)