--- a/reportlab/platypus/tables.py Thu May 24 16:49:19 2007 +0000
+++ b/reportlab/platypus/tables.py Thu May 31 15:20:42 2007 +0000
@@ -246,15 +246,15 @@
if not _seqRH: rowHeights = nrows*[rowHeights]
elif len(rowHeights) != nrows:
raise ValueError, "%s data error - %d rows in data but %d in grid" % (self.identity(),nrows, len(rowHeights))
- for i in range(nrows):
+ for i in xrange(nrows):
if len(data[i]) != ncols:
raise ValueError, "%s not enough data points in row %d!" % (self.identity(),i)
self._rowHeights = self._argH = rowHeights
self._colWidths = self._argW = colWidths
cellrows = []
- for i in range(nrows):
+ for i in xrange(nrows):
cellcols = []
- for j in range(ncols):
+ for j in xrange(ncols):
cellcols.append(CellStyle(`(i,j)`))
cellrows.append(cellcols)
self._cellStyles = cellrows
@@ -262,6 +262,7 @@
self._bkgrndcmds = []
self._linecmds = []
self._spanCmds = []
+ self._nosplitCmds = []
self.repeatRows = repeatRows
self.repeatCols = repeatCols
self.splitByRow = splitByRow
@@ -519,6 +520,9 @@
if None in self._argH:
self._calc_width(availWidth,W=W)
+ if self._nosplitCmds:
+ self._calcNoSplitRanges()
+
# calculate the full table height
self._calc_height(availHeight,availWidth,W=W)
@@ -535,8 +539,8 @@
Allow a couple which we know are fixed size such as
images and graphics."""
if upToRow is None: upToRow = self._nrows
- for row in range(min(self._nrows, upToRow)):
- for col in range(self._ncols):
+ for row in xrange(min(self._nrows, upToRow)):
+ for col in xrange(self._ncols):
value = self._cellvalues[row][col]
if not self._canGetWidth(value):
return 1
@@ -592,12 +596,12 @@
minimums = {}
totalMinimum = 0
elementWidth = self._elementWidth
- for colNo in range(self._ncols):
+ for colNo in xrange(self._ncols):
w = W[colNo]
if w is None or w=='*' or _endswith(w,'%'):
siz = 1
current = final = None
- for rowNo in range(self._nrows):
+ for rowNo in xrange(self._nrows):
value = self._cellvalues[rowNo][colNo]
style = self._cellStyles[rowNo][colNo]
new = elementWidth(value,style)+style.leftPadding+style.rightPadding
@@ -758,6 +762,52 @@
if y0 > y1: y0, y1 = y1, y0
if x0!=x1 or y0!=y1:
+ if x0!=x1: #column span
+ for y in xrange(y0, y1+1):
+ for x in xrange(x0,x1+1):
+ csa((x,y))
+ if y0!=y1: #row span
+ for y in xrange(y0, y1+1):
+ for x in xrange(x0,x1+1):
+ rsa((x,y))
+
+ for y in xrange(y0, y1+1):
+ for x in xrange(x0,x1+1):
+ spanRanges[x,y] = None
+ # set the main entry
+ spanRanges[x0,y0] = (x0, y0, x1, y1)
+
+ def _calcNoSplitRanges(self):
+ """
+ This creates some mappings to let the later code determine
+ if a cell is part of a "nosplit" range.
+ self._nosplitRanges shows the 'coords' in integers of each
+ 'cell range', or None if it was clobbered:
+ (col, row) -> (col0, row0, col1, row1)
+
+ Any cell not in the key is not part of a spanned region
+ """
+ self._nosplitRanges = nosplitRanges = {}
+ for x in xrange(self._ncols):
+ for y in xrange(self._nrows):
+ nosplitRanges[x,y] = (x, y, x, y)
+ self._colNoSplitCells = []
+ self._rowNoSplitCells = []
+ csa = self._colNoSplitCells.append
+ rsa = self._rowNoSplitCells.append
+ for (cmd, start, stop) in self._nosplitCmds:
+ x0, y0 = start
+ x1, y1 = stop
+
+ #normalize
+ if x0 < 0: x0 = x0 + self._ncols
+ if x1 < 0: x1 = x1 + self._ncols
+ if y0 < 0: y0 = y0 + self._nrows
+ if y1 < 0: y1 = y1 + self._nrows
+ if x0 > x1: x0, x1 = x1, x0
+ if y0 > y1: y0, y1 = y1, y0
+
+ if x0!=x1 or y0!=y1:
#column span
if x0!=x1:
for y in xrange(y0, y1+1):
@@ -771,9 +821,9 @@
for y in xrange(y0, y1+1):
for x in xrange(x0,x1+1):
- spanRanges[x,y] = None
+ nosplitRanges[x,y] = None
# set the main entry
- spanRanges[x0,y0] = (x0, y0, x1, y1)
+ nosplitRanges[x0,y0] = (x0, y0, x1, y1)
def _calcSpanRects(self):
"""Work out rects for tables which do row and column spanning.
@@ -830,6 +880,9 @@
self._bkgrndcmds.append(cmd)
elif cmd[0] == 'SPAN':
self._spanCmds.append(cmd)
+ elif cmd[0] == 'NOSPLIT':
+ # we expect op, start, stop
+ self._nosplitCmds.append(cmd)
elif _isLineCommand(cmd):
# we expect op, start, stop, weight, colour, cap, dashes, join
cmd = list(cmd)
@@ -876,8 +929,8 @@
if ec < 0: ec = ec + self._ncols
if sr < 0: sr = sr + self._nrows
if er < 0: er = er + self._nrows
- for i in range(sr, er+1):
- for j in range(sc, ec+1):
+ for i in xrange(sr, er+1):
+ for j in xrange(sc, ec+1):
_setCellStyle(self._cellStyles, i, j, op, values)
def _drawLines(self):
@@ -1088,6 +1141,7 @@
R0._cr_0(n,A)
R0._cr_0(n,self._bkgrndcmds)
R0._cr_0(n,self._spanCmds)
+ R0._cr_0(n,self._nosplitCmds)
if repeatRows:
#R1 = slelf.__class__(data[:repeatRows]+data[n:],self._argW,
@@ -1099,6 +1153,7 @@
R1._cr_1_1(n,repeatRows,A)
R1._cr_1_1(n,repeatRows,self._bkgrndcmds)
R1._cr_1_1(n,repeatRows,self._spanCmds)
+ R1._cr_1_1(n,repeatRows,self._nosplitCmds)
else:
#R1 = slelf.__class__(data[n:], self._argW, self._argH[n:],
R1 = self.__class__(data[n:], self._colWidths, self._argH[n:],
@@ -1108,6 +1163,7 @@
R1._cr_1_0(n,A)
R1._cr_1_0(n,self._bkgrndcmds)
R1._cr_1_0(n,self._spanCmds)
+ R1._cr_1_0(n,self._nosplitCmds)
R0.hAlign = R1.hAlign = self.hAlign
R0.vAlign = R1.vAlign = self.vAlign
@@ -1115,23 +1171,27 @@
self.onSplit(R1)
return [R0,R1]
+ def _getRowImpossible(impossible,cells,ranges):
+ for xy in cells:
+ r=ranges[xy]
+ if r!=None:
+ y1,y2=r[1],r[3]
+ if y1!=y2:
+ ymin=min(y1,y2) #normalize
+ ymax=max(y1,y2) #normalize
+ y=ymin+1
+ while 1:
+ if y>ymax: break
+ impossible[y]=None #split at position y is impossible because of overlapping rowspan
+ y+=1
+ _getRowImpossible=staticmethod(_getRowImpossible)
+
def _getFirstPossibleSplitRowPosition(self,availHeight):
+ impossible={}
if self._spanCmds:
- impossible={}
- for xy in self._rowSpanCells:
- r=self._spanRanges[xy]
- if r!=None:
- y1,y2=r[1],r[3]
- if y1!=y2:
- ymin=min(y1,y2) #normalize
- ymax=max(y1,y2) #normalize
- y=ymin+1
- while 1:
- if y>ymax: break
- impossible[y]=None #split at position y is impossible because of overlapping rowspan
- y=y+1
- else:
- impossible={} # any split possible because table does *not* have rowspans
+ self._getRowImpossible(impossible,self._rowSpanCells,self._spanRanges)
+ if self._nosplitCmds:
+ self._getRowImpossible(impossible,self._rowNoSplitCells,self._nosplitRanges)
h = 0
n = 1
split_at = 0 # from this point of view 0 is the first position where the table may *always* be splitted
@@ -1155,7 +1215,7 @@
def draw(self):
self._curweight = self._curcolor = self._curcellstyle = None
self._drawBkgrnd()
- if self._spanCmds == []:
+ if not self._spanCmds:
# old fashioned case, no spanning, steam on and do each cell
for row, rowstyle, rowpos, rowheight in map(None, self._cellvalues, self._cellStyles, self._rowpositions[1:], self._rowHeights):
for cellval, cellstyle, colpos, colwidth in map(None, row, rowstyle, self._colpositions[:-1], self._colWidths):
@@ -1163,8 +1223,8 @@
else:
# we have some row or col spans, need a more complex algorithm
# to find the rect for each
- for rowNo in range(self._nrows):
- for colNo in range(self._ncols):
+ for rowNo in xrange(self._nrows):
+ for colNo in xrange(self._ncols):
cellRect = self._spanRects[colNo, rowNo]
if cellRect is not None:
(x, y, width, height) = cellRect
@@ -1176,19 +1236,28 @@
def _drawBkgrnd(self):
nrows = self._nrows
ncols = self._ncols
+ canv = self.canv
+ colpositions = self._colpositions
+ rowpositions = self._rowpositions
+ rowHeights = self._rowHeights
+ colWidths = self._colWidths
+ spanRects = getattr(self,'_spanRects',None)
+ def bg(x0,y0,w,h,color):
+ canv.setFillColor(color)
+ canv.rect(x0, y0, w, h, stroke=0,fill=1)
+ A = [].append
for cmd, (sc, sr), (ec, er), arg in self._bkgrndcmds:
if sc < 0: sc = sc + ncols
if ec < 0: ec = ec + ncols
if sr < 0: sr = sr + nrows
if er < 0: er = er + nrows
- x0 = self._colpositions[sc]
- y0 = self._rowpositions[sr]
- x1 = self._colpositions[min(ec+1,ncols)]
- y1 = self._rowpositions[min(er+1,nrows)]
+ x0 = colpositions[sc]
+ y0 = rowpositions[sr]
+ x1 = colpositions[min(ec+1,ncols)]
+ y1 = rowpositions[min(er+1,nrows)]
w, h = x1-x0, y1-y0
- canv = self.canv
if callable(arg):
- apply(arg,(self,canv, x0, y0, w, h))
+ A((0x7ffffff,arg,(self,canv, x0, y0, w, h)))
elif cmd == 'ROWBACKGROUNDS':
#Need a list of colors to cycle through. The arguments
#might be already colours, or convertible to colors, or
@@ -1197,29 +1266,38 @@
colorCycle = map(colors.toColorOrNone, arg)
count = len(colorCycle)
rowCount = er - sr + 1
- for i in range(rowCount):
+ for i in xrange(rowCount):
color = colorCycle[i%count]
- h = self._rowHeights[sr + i]
+ h = rowHeights[sr + i]
if color:
- canv.setFillColor(color)
- canv.rect(x0, y0, w, -h, stroke=0,fill=1)
+ A((0,bg,(x0, y0, w, -h, color)))
y0 = y0 - h
-
elif cmd == 'COLBACKGROUNDS':
#cycle through colours columnwise
colorCycle = map(colors.toColorOrNone, arg)
count = len(colorCycle)
colCount = ec - sc + 1
- for i in range(colCount):
+ for i in xrange(colCount):
color = colorCycle[i%count]
- w = self._colWidths[sc + i]
+ w = colWidths[sc + i]
if color:
- canv.setFillColor(color)
- canv.rect(x0, y0, w, h, stroke=0,fill=1)
+ A((1,bg,(x0, y0, w, h, color)))
x0 = x0 +w
else: #cmd=='BACKGROUND'
- canv.setFillColor(colors.toColor(arg))
- canv.rect(x0, y0, w, h, stroke=0,fill=1)
+ color = colors.toColorOrNone(arg)
+ if color:
+ if ec-sc or er-sr:
+ A((2,bg,(x0, y0, w, h, color)))
+ elif spanRects:
+ xywh = spanRects.get((sc,sr))
+ if xywh:
+ #it's a single cell
+ x0, y0, w, h = xywh
+ A((3,bg,(x0, y0, w, h, color)))
+ A = A.__self__
+ A.sort()
+ for z,func,args in A:
+ func(*args)
def _drawCell(self, cellval, cellstyle, (colpos, rowpos), (colwidth, rowheight)):
if self._curcellstyle is not cellstyle: