Déplacement pour eggification.
[Plinn.git] / Products / Plinn / PloneMisc.py
diff --git a/Products/Plinn/PloneMisc.py b/Products/Plinn/PloneMisc.py
new file mode 100644 (file)
index 0000000..e573468
--- /dev/null
@@ -0,0 +1,244 @@
+##
+## The following code comes from Plone project http://plone.org
+##
+""" Useful utilities function from the Plone project like Batch.
+
+
+
+"""
+
+
+from __future__ import nested_scopes
+
+from ZTUtils.Batch import Batch as ZTUBatch
+from ZTUtils import make_query
+from ExtensionClass import Base
+
+# These have to be duplicated from ZTUtils.Batch to use the correct Batch
+# class, otherwise orphans will come out wrong in the 'show x next messages'.
+class LazyPrevBatch(Base):
+       def __of__(self, parent):
+               return Batch(parent._sequence, parent._size,
+                                        parent.first - parent._size + parent.overlap, 0,
+                                        parent.orphan, parent.overlap)
+
+class LazyNextBatch(Base):
+       def __of__(self, parent):
+               try: parent._sequence[parent.end]
+               except IndexError: return None
+               return Batch(parent._sequence, parent._size,
+                                        parent.end - parent.overlap, 0,
+                                        parent.orphan, parent.overlap)
+
+class LazySequenceLength(Base):
+       def __of__(self, parent):
+               parent.sequence_length = l = len(parent._sequence)
+               return l
+
+class Batch(ZTUBatch):
+       """Create a sequence batch"""
+       __allow_access_to_unprotected_subobjects__ = 1
+
+       previous = LazyPrevBatch()
+       next = LazyNextBatch()
+       sequence_length = LazySequenceLength()
+
+       size = first= start = end = orphan = overlap = navlist = None
+       numpages = pagenumber = pagerange = pagerangeend = pagerangestart = pagenumber = quantumleap = None
+
+       def __init__( self
+                               , sequence
+                               , size
+                               , start=0
+                               , end=0
+                               , orphan=0
+                               , overlap=0
+                               , pagerange=7
+                               , quantumleap=0
+                               , b_start_str='b_start'
+                               , before_getitem=lambda item: item
+                               , ):
+               """ Encapsulate sequence in batches of size
+               sequence                - the data to batch.
+               size                    - the number of items in each batch. This will be computed if left out.
+               start                   - the first element of sequence to include in batch (0-index)
+               end                             - the last element of sequence to include in batch (0-index, optional)
+               orphan                  - the next page will be combined with the current page if it does not contain more than orphan elements
+               overlap                 - the number of overlapping elements in each batch
+               pagerange               - the number of pages to display in the navigation
+               quantumleap             - 0 or 1 to indicate if bigger increments should be used in the navigation list for big results.
+               b_start_str             - the request variable used for start, default 'b_start'
+               before_getitem  - function that compute the item before getting it
+               """
+               start = start + 1
+
+               start,end,sz = opt(start,end,size,orphan,sequence)
+
+               self._sequence = sequence
+               self.size = sz
+               self._size = size
+               self.start = start
+               self.end = end
+               self.orphan = orphan
+               self.overlap = overlap
+               self.first = max(start - 1, 0)
+               self.length = self.end - self.first
+
+               self.b_start_str = b_start_str
+
+               self.last = self.sequence_length - size
+
+               # Set up next and previous
+               if self.first == 0:
+                       self.previous = None
+
+               # Set up the total number of pages
+               self.numpages = calculate_pagenumber(self.sequence_length - self.orphan, self.size, self.overlap)
+
+               # Set up the current page number
+               self.pagenumber = calculate_pagenumber(self.start, self.size, self.overlap)
+
+               # Set up pagerange for the navigation quick links
+               self.pagerange, self.pagerangestart, self.pagerangeend = calculate_pagerange(self.pagenumber,self.numpages,pagerange)
+
+               # Set up the lists for the navigation: 4 5 [6] 7 8
+               #  navlist is the complete list, including pagenumber
+               #  prevlist is the 4 5 in the example above
+               #  nextlist is 7 8 in the example above
+               self.navlist = self.prevlist = self.nextlist = []
+               if self.pagerange and self.numpages >= 1:
+                       self.navlist  = range(self.pagerangestart, self.pagerangeend)
+                       self.prevlist = range(self.pagerangestart, self.pagenumber)
+                       self.nextlist = range(self.pagenumber + 1, self.pagerangeend)
+
+               # QuantumLeap - faster navigation for big result sets
+               self.quantumleap = quantumleap
+               self.leapback = self.leapforward = []
+               if self.quantumleap:
+                       self.leapback = calculate_leapback(self.pagenumber, self.numpages, self.pagerange)
+                       self.leapforward = calculate_leapforward(self.pagenumber, self.numpages, self.pagerange)
+               
+               # comptute item before getting it
+               self.before_getitem = before_getitem
+       
+       def __getitem__(self, index):
+               if index < 0:
+                       if index + self.end < self.first: raise IndexError, index
+                       item = self._sequence[index + self.end]
+                       return self.before_getitem(item)
+
+               if index >= self.length: raise IndexError, index
+               item = self._sequence[index+self.first]
+               return self.before_getitem(item)
+
+       def pageurl(self, formvariables, pagenumber=-1):
+               """ Makes the url for a given page """
+               if pagenumber == -1:
+                       pagenumber = self.pagenumber
+               b_start = pagenumber * (self.size - self.overlap) - self.size
+               return make_query(formvariables, {self.b_start_str:b_start})
+
+       def navurls(self, formvariables, navlist=[]):
+               """ Returns the page number and url for the navigation quick links """
+               if not navlist: navlist = self.navlist
+               return map(lambda x, formvariables = formvariables: (x, self.pageurl(formvariables, x)), navlist)
+
+       def prevurls(self, formvariables):
+               """ Helper method to get prev navigation list from templates """
+               return self.navurls(formvariables, self.prevlist)
+
+       def nexturls(self, formvariables):
+               """ Helper method to get next navigation list from templates """
+               return self.navurls(formvariables, self.nextlist)
+
+# Calculate start, end, batchsize
+# This is copied from ZTUtils.Batch.py because orphans were not correct there.
+# 04/16/04 modified by Danny Bloemendaal (_ender_). Removed try/except structs because
+# in some situations they cause some unexpected problems. Also fixed some problems with the orphan stuff. Seems to work now.
+def opt(start,end,size,orphan,sequence):
+       length = len(sequence)
+       if size < 1:
+               if start > 0 and end > 0 and end >= start:
+                       size = end + 1 - start
+               else: size = 25
+       if start > 0: 
+               if start>length: 
+                       start = length
+               if end > 0:
+                       if end < start: end = start
+               else:
+                       end = start + size - 1
+                       if (end+orphan)>=length:
+                               end = length
+       elif end > 0:
+               if (end)>length:
+                       end = length
+               start = end + 1 - size
+               if start - 1 < orphan: start = 1
+       else:
+               start = 1
+               end = start + size - 1
+               if (end+orphan)>=length:
+                       end = length
+       return start,end,size
+
+def calculate_pagenumber(elementnumber, batchsize, overlap=0):
+       """ Calculate the pagenumber for the navigation """
+       # To find first element in a page,
+       # elementnumber = pagenumber * (size - overlap) - size (- orphan?)
+       try:
+               pagenumber,remainder = divmod(elementnumber, batchsize - overlap)
+       except ZeroDivisionError:
+               pagenumber, remainder = divmod(elementnumber, 1)
+       if remainder > overlap:
+               pagenumber = pagenumber + 1
+       pagenumber = max(pagenumber, 1)
+       return pagenumber
+
+def calculate_pagerange(pagenumber, numpages, pagerange):
+       """ Calculate the pagerange for the navigation quicklinks """
+       # Pagerange is the number of pages linked to in the navigation, odd number
+       pagerange = max(0 , pagerange + pagerange % 2 - 1)
+       # Making sure the list will not start with negative values
+       pagerangestart = max ( 1, pagenumber - (pagerange - 1 ) / 2 )
+       # Making sure the list does not expand beyond the last page
+       pagerangeend = min ( pagenumber + (pagerange - 1 ) / 2, numpages) + 1
+       return pagerange, pagerangestart, pagerangeend
+
+def calculate_quantum_leap_gap(numpages, pagerange):
+       """ Find the QuantumLeap gap. Current width of list is 6 clicks (30/5) """
+       return int(max(1,round(float(numpages - pagerange)/30))*5)
+
+def calculate_leapback(pagenumber, numpages, pagerange):
+       """ Check the distance between start and 0 and add links as necessary """
+       leapback = []
+       quantum_leap_gap = calculate_quantum_leap_gap(numpages, pagerange)
+       num_back_leaps = max(0,min(3, int(round(float(pagenumber - pagerange)/quantum_leap_gap) - 0.3)))
+       if num_back_leaps:
+               pagerange, pagerangestart, pagerangeend = calculate_pagerange( pagenumber, numpages, pagerange)
+               leapback = range(pagerangestart - num_back_leaps * quantum_leap_gap, pagerangestart, quantum_leap_gap)
+       return leapback
+
+def calculate_leapforward(pagenumber, numpages, pagerange):
+       """ Check the distance between end and length and add links as necessary """
+       leapforward = []
+       quantum_leap_gap = calculate_quantum_leap_gap(numpages, pagerange)
+       num_forward_leaps = max(0,min(3, int(round(float(numpages - pagenumber - pagerange)/quantum_leap_gap) - 0.3)))
+       if num_forward_leaps:
+               pagerange, pagerangestart, pagerangeend = calculate_pagerange( pagenumber, numpages, pagerange)
+               leapforward = range(pagerangeend-1 + quantum_leap_gap, pagerangeend-1 + (num_forward_leaps+1) * quantum_leap_gap, quantum_leap_gap)
+       return leapforward
+
+
+class IndexIterator:
+       __allow_access_to_unprotected_subobjects__ = 1
+
+       def __init__(self, upper=100000, pos=0):
+               self.upper=upper
+               self.pos=pos
+
+       def next(self):
+               if self.pos <= self.upper:
+                       self.pos += 1
+                       return self.pos
+               raise KeyError, 'Reached upper bounds'