--- a/reportlab/platypus/tables.py Wed Oct 24 12:34:59 2007 +0000
+++ b/reportlab/platypus/tables.py Fri Oct 26 16:16:38 2007 +0000
@@ -203,6 +203,12 @@
except:
return 0
+def _spanConsCmp(a,b):
+ r = cmp(b[1]-b[0],a[1]-a[0])
+ if not r:
+ r = cmp(a,b)
+ return r
+
class Table(Flowable):
def __init__(self, data, colWidths=None, rowHeights=None, style=None,
repeatRows=0, repeatCols=0, splitByRow=1, emptyTableAction=None, ident=None,
@@ -371,8 +377,19 @@
if None in W: #some column widths are not given
canv = getattr(self,'canv',None)
saved = None
- colSpanCells = self._spanCmds and self._colSpanCells or ()
- if W is self._argW: W = W[:]
+ if self._spanCmds:
+ colSpanCells = self._colSpanCells
+ spanRanges = self._spanRanges
+ else:
+ colSpanCells = ()
+ spanRanges = {}
+ spanCons = {}
+ FUZZ = rl_config._FUZZ
+ if W is self._argW:
+ W0 = W
+ W = W[:]
+ else:
+ W0 = W[:]
while None in W:
j = W.index(None) #find first unspecified column
f = lambda x,j=j: operator.getitem(x,j)
@@ -382,20 +399,41 @@
i = 0
for v, s in map(None, V, S):
- #if the current cell is part of a spanned region,
- #assume a zero size.
- if (j, i) in colSpanCells:
- t = 0.0
+ ji = j,i
+ span = spanRanges.get(ji,None)
+ if ji in colSpanCells and not span: #if the current cell is part of a spanned region,
+ t = 0.0 #assume a zero size.
else:#work out size
t = self._elementWidth(v,s)
if t is None:
raise ValueError, "Flowable %s in cell(%d,%d) can't have auto width\n%s" % (v.identity(30),i,j,self.identity(30))
- t = t + s.leftPadding+s.rightPadding
+ t += s.leftPadding+s.rightPadding
+ if span:
+ c0 = span[0]
+ c1 = span[2]
+ if c0!=c1:
+ x = c0,c1
+ spanCons[x] = max(spanCons.get(x,t),t)
+ t = 0
if t>w: w = t #record a new maximum
- i = i + 1
+ i += 1
W[j] = w
+ if spanCons:
+ spanConsX = spanCons.keys() #try to ensure span constraints are satisfied
+ spanConsX.sort(_spanConsCmp) #assign required space to variable rows
+ for c0,c1 in spanConsX: #equally to existing calculated values
+ w = spanCons[c0,c1]
+ t = sum(W[c0:c1+1])
+ if t>=w-FUZZ: continue #already good enough
+ X = [x for x in xrange(c0,c1+1) if W0[x] is None] #variable candidates
+ if not X: continue #something wrong here mate
+ w -= t
+ w /= float(len(X))
+ for x in X:
+ W[x] += w
+
self._colWidths = W
width = 0
self._colpositions = [0] #index -1 is right side boundary; we skip when processing cells
@@ -407,8 +445,7 @@
self._width_calculated_once = 1
def _elementWidth(self,v,s):
- t = type(v)
- if t in _SeqTypes:
+ if isinstance(v,(list,tuple)):
w = 0
for e in v:
ew = self._elementWidth(e,s)
@@ -451,9 +488,13 @@
colpositions = self._colpositions
else:
rowSpanCells = colSpanCells = ()
+ spanRanges = {}
if canv: saved = canv._fontname, canv._fontsize, canv._leading
+ H0 = H
H = H[:] #make a copy as we'll change it
self._rowHeights = H
+ spanCons = {}
+ FUZZ = rl_config._FUZZ
while None in H:
i = H.index(None)
if longTable:
@@ -467,7 +508,8 @@
j = 0
for j,(v, s, w) in enumerate(map(None, V, S, W)): # value, style, width (lengths must match)
ji = j,i
- if ji in rowSpanCells:
+ span = spanRanges.get(ji,None)
+ if ji in rowSpanCells and not span:
continue # don't count it, it's either occluded or unreliable
else:
if isinstance(v,(tuple,list,Flowable)):
@@ -476,9 +518,8 @@
raise ValueError, "Flowable %s in cell(%d,%d) can't have auto width in\n%s" % (v[0].identity(30),i,j,self.identity(30))
if canv: canv._fontname, canv._fontsize, canv._leading = s.fontname, s.fontsize, s.leading or 1.2*s.fontsize
if ji in colSpanCells:
- t = spanRanges[ji]
- if not t: continue
- w = max(colpositions[t[2]+1]-colpositions[t[0]],w)
+ if not span: continue
+ w = max(colpositions[span[2]+1]-colpositions[span[0]],w)
dW,t = self._listCellGeom(v,w or self._listValueWidth(v),s)
if canv: canv._fontname, canv._fontsize, canv._leading = saved
dW = dW + s.leftPadding + s.rightPadding
@@ -488,10 +529,31 @@
v = (v is not None and str(v) or '').split("\n")
t = (s.leading or 1.2*s.fontSize)*len(v)
t += s.bottomPadding+s.topPadding
+ if span:
+ r0 = span[1]
+ r1 = span[3]
+ if r0!=r1:
+ x = r0,r1
+ spanCons[x] = max(spanCons.get(x,t),t)
+ t = 0
if t>h: h = t #record a new maximum
H[i] = h
if None not in H: hmax = lim
+ if spanCons:
+ spanConsX = spanCons.keys() #try to ensure span constraints are satisfied
+ spanConsX.sort(_spanConsCmp) #assign required space to variable rows
+ for r0,r1 in spanConsX: #equally to existing calculated values
+ h = spanCons[r0,r1]
+ t = sum(H[r0:r1+1])
+ if t>=h-FUZZ: continue #already good enough
+ X = [x for x in xrange(r0,r1+1) if H0[x] is None] #variable candidates
+ if not X: continue #something wrong here mate
+ h -= t
+ h /= float(len(X))
+ for x in X:
+ H[x] += h
+
height = self._height = reduce(operator.add, H[:hmax], 0)
self._rowpositions = [height] # index 0 is actually topline; we skip when processing cells
for h in H[:hmax]:
--- a/reportlab/test/test_platypus_tables.py Wed Oct 24 12:34:59 2007 +0000
+++ b/reportlab/test/test_platypus_tables.py Fri Oct 26 16:16:38 2007 +0000
@@ -22,7 +22,6 @@
)
return t
-
def makeStyles():
styles = []
for i in range(5):
@@ -39,7 +38,6 @@
styles[-1].add('LINEBELOW',(1,-1), (-1, -1), 2, (0.5, 0.5, 0.5))
return styles
-
def run():
doc = SimpleDocTemplate(outputfile('test_platypus_tables.pdf'), pagesize=(8.5*inch, 11*inch), showBoundary=1)
styles = makeStyles()
@@ -708,9 +706,45 @@
lst.append(t)
+ #Volker Haas' example
+ sty=[
+ ('TOPPADDING',(0,0),(-1,-1),0),
+ ('BOTTOMPADDING',(0,0),(-1,-1),0),
+ ('RIGHTPADDING',(0,0),(-1,-1),0),
+ ('LEFTPADDING',(0,0),(-1,-1),0),
+ ('GRID',(0,0),(-1,-1),0.5,colors.grey),
+ ('BACKGROUND', (0, 0), (0, 1), colors.pink),
+ ('SPAN',(0,0),(0,1)),
+ ('BACKGROUND', (2, 2), (2, 3), colors.orange),
+ ('SPAN',(2,2),(2,3)),
+ ('SPAN',(3,1),(4,1)),
+ ]
+
+ p_style= ParagraphStyle('Normal')
+ data= [['00', '01', '02', '03', '04'],
+ ['', '11', '12', Paragraph('This is a string',p_style), ''],
+ ['20', '21', Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs', p_style), '23', '24'],
+ ['30', '31', '', '33', '34']]
+ lst.append(Table(data,style=sty))
+ lst.append(Spacer(10,10))
+ data1= [['00', '01', '02', '03', '04'],
+ ['', '11', '12', XPreformatted('This is a string',p_style), ''],
+ ['20', '21', Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs',p_style), '23', '24'],
+ ['30', '31', '', '33', '34']]
+ lst.append(Table(data1,style=sty))
+ lst.append(Spacer(10,10))
+ data2= [['00', '01', '02', '03', '04'],
+ ['', '11', '12', 'This is a string', ''],
+ ['20', '21','22\nblub\nasfd\nafd\nasdfs', '23', '24'],
+ ['30', '31', '', '33', '34']]
+ lst.append(Table(data2,style=sty))
+ data3= [['00', '01', '02', '03', '04'],
+ ['', '11', '12', 'This is a string', ''],
+ ['20', '21', Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs',p_style), '23', '24'],
+ ['30', '31', '', '33', '34']]
+ lst.append(Table(data3,style=sty))
SimpleDocTemplate(outputfile('tables.pdf'), showBoundary=1).build(lst)
-
class TablesTestCase(unittest.TestCase):
"Make documents with tables"