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'): """ 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' """ 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) 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