-##
-## 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'