reportlab/platypus/tables.py
changeset 350 0916ae478b25
parent 342 a6982189331d
child 354 807513dd52b7
--- a/reportlab/platypus/tables.py	Tue Jul 11 12:37:20 2000 +0000
+++ b/reportlab/platypus/tables.py	Tue Jul 11 14:29:45 2000 +0000
@@ -31,9 +31,12 @@
 #
 ###############################################################################
 #	$Log: tables.py,v $
+#	Revision 1.20  2000/07/11 14:29:45  rgbecker
+#	Table splitting start
+#
 #	Revision 1.19  2000/07/10 15:25:47  andy_robinson
 #	Added tables to PythonPoint
-#
+#	
 #	Revision 1.18  2000/07/08 15:30:04  rgbecker
 #	Cosmetics and error testing
 #	
@@ -86,7 +89,7 @@
 #	Revision 1.2  2000/02/15 15:47:09  rgbecker
 #	Added license, __version__ and Logi comment
 #	
-__version__=''' $Id: tables.py,v 1.19 2000/07/10 15:25:47 andy_robinson Exp $ '''
+__version__=''' $Id: tables.py,v 1.20 2000/07/11 14:29:45 rgbecker Exp $ '''
 __doc__="""
 Tables are created by passing the constructor a tuple of column widths, a tuple of row heights and the data in
 row order. Drawing of the table can be controlled by using a TableStyle instance. This allows control of the
@@ -138,7 +141,8 @@
 TableStyleType = type(TableStyle())
 		
 class Table(Flowable):
-	def __init__(self, colWidths, rowHeights, data, style=None):
+	def __init__(self, colWidths, rowHeights, data, style=None,
+				repeatRows=0, repeatCols=0, splitByRow=1):
 		if not colWidths:
 			raise ValueError, "Table must have at least 1 column"
 		if not rowHeights:
@@ -150,40 +154,37 @@
 		for i in range(nrows):
 			if len(data[i]) != ncols:
 				raise ValueError, "Not enough data points in row %d!" % i
-		self._rowHeights = rowHeights
-		self._colWidths = colWidths
+		self._rowHeights = self._argH = rowHeights
+		self._colWidths = self._argW = colWidths
 		self._cellvalues = data
 		dflt = CellStyle('<default>')
-		self._cellstyles = [None]*nrows
+
+		self._cellStyles = [None]*nrows
 		for i in range(nrows):
-			self._cellstyles[i] = [dflt]*ncols
+			self._cellStyles[i] = [dflt]*ncols
+
 		self._bkgrndcmds = []
 		self._linecmds = []
 		self._curweight = self._curcolor = self._curcellstyle = None
+		self.repeatRows = repeatRows
+		self.repeatCols = repeatCols
+		self.splitByRow = splitByRow
 
 		if style:
 			self.setStyle(style)
 
 	def _calc(self):
-		if hasattr(self,'_argH'):
-			self._rowHeights = self._argH
-			del self._argH
 
-		if hasattr(self,'_argW'):
-			self._colWidths = self._argW
-			del self._argW
-
-		H = self._rowHeights
-		W = self._colWidths
+		H = self._argH
+		W = self._argW
 
 		if None in H:
-			self._argH = H
 			H = H[:]	#make a copy as we'll change it
 			self._rowHeights = H
 			while None in H:
 				i = H.index(None)
 				V = self._cellvalues[i]
-				S = self._cellstyles[i]
+				S = self._cellStyles[i]
 				h = 0
 				for v, s in map(None, V, S):
 					if type(v) is not _stringtype: v = str(v)
@@ -193,14 +194,13 @@
 				H[i] = h
 
 		if None in W:
-			self._argW = H
 			W = W[:]
 			self._colWidths = W
 			while None in W:
 				i = W.index(None)
 				f = lambda x,i=i: operator.getitem(x,i)
 				V = map(f,self._cellvalues)
-				S = map(f,self._cellstyles)
+				S = map(f,self._cellStyles)
 				w = 0
 				for v, s in map(None, V, S):
 					if type(v) is not _stringtype: v = str(v)
@@ -228,19 +228,22 @@
 		if type(tblstyle) is not TableStyleType:
 			tblstyle = TableStyle(tblstyle)
 		for cmd in tblstyle.getCommands():
-			if cmd[0] == 'BACKGROUND':
-				self._bkgrndcmds.append(cmd)
-			elif _isLineCommand(cmd):
-				self._linecmds.append(cmd)
-			else:
-				(op, (sc, sr), (ec, er)), values = cmd[:3] , cmd[3:]
-				if sc < 0: sc = sc + self._ncols
-				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):
-						_setCellStyle(self._cellstyles, i, j, op, values)
+			self._addCommand(cmd)
+
+	def _addCommand(self,cmd):
+		if cmd[0] == 'BACKGROUND':
+			self._bkgrndcmds.append(cmd)
+		elif _isLineCommand(cmd):
+			self._linecmds.append(cmd)
+		else:
+			(op, (sc, sr), (ec, er)), values = cmd[:3] , cmd[3:]
+			if sc < 0: sc = sc + self._ncols
+			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):
+					_setCellStyle(self._cellStyles, i, j, op, values)
 
 	def _drawLines(self):
 		for op, (sc, sr), (ec, er), weight, color in self._linecmds:
@@ -272,9 +275,11 @@
 		self._drawHLines((sc, er+1), (ec, er+1), weight, color)
 		self._drawVLines((sc, sr), (sc, er), weight, color)
 		self._drawVLines((ec+1, sr), (ec+1, er), weight, color)
+
 	def _drawInnerGrid(self, (sc, sr), (ec, er), weight, color):
 		self._drawHLines((sc, sr+1), (ec, er), weight, color)
 		self._drawVLines((sc+1, sr), (ec, er), weight, color)
+
 	def _prepLine(self, weight, color):
 		if color != self._curcolor:
 			self.canv.setStrokeColor(color)
@@ -282,12 +287,14 @@
 		if weight != self._curweight:
 			self.canv.setLineWidth(weight)
 			self._curweight = weight
+
 	def _drawHLines(self, (sc, sr), (ec, er), weight, color):
 		self._prepLine(weight, color)
 		scp = self._colpositions[sc]
 		ecp = self._colpositions[ec+1]
 		for rowpos in self._rowpositions[sr:er+1]:
 			self.canv.line(scp, rowpos, ecp, rowpos)
+
 	def _drawVLines(self, (sc, sr), (ec, er), weight, color):
 		self._prepLine(weight, color)
 		srp = self._rowpositions[sr]
@@ -300,13 +307,93 @@
 		#nice and easy, since they are predetermined size
 		self.availWidth = availWidth
 		return (self._width, self._height)
+
+	def _cr_0(self,n,cmds):
+		for op, (sc, sr), (ec, er), weight, color in cmds:
+			if sr>=n: continue
+			if er>=n: er = n-1
+			self._addCommand((op, (sc, sr), (ec, er), weight, color))
+
+	def _cr_1_1(self,n,repeatRows, cmds):
+		for op, (sc, sr), (ec, er), weight, color in cmds:
+			if sr>=0 and sr>=repeatRows and sr<n and er>=0 and er<n: continue
+			if sr>=repeatRows and sr<n: sr=repeatRows
+			elif sr>=repeatRows and sr>=n: sr=sr+repeatRows-n
+			if er>=repeatRows and er<n: er=repeatRows
+			elif er>=repeatRows and er>=n: er=er+repeatRows-n
+			self._addCommand((op, (sc, sr), (ec, er), weight, color))
+
+	def _cr_1_0(self,n,cmds):
+		for op, (sc, sr), (ec, er), weight, color in cmds:
+			if er>=0 and er<n: continue
+			if sr>=0 and sr<n: sr=0
+			if sr>=n: sr = sr-n
+			if er>=n: er = er-n
+			self._addCommand((op, (sc, sr), (ec, er), weight, color))
+
+	def _splitRows(self,availHeight):
+		self._calc()
+		h = 0
+		n = 0
+		lim = len(self._rowHeights)
+		while n<lim:
+			hn = h + self._rowHeights[n]
+			if hn>availHeight: break
+			h = hn
+			n = n + 1
+
+		if n<=self.repeatRows:
+			return []
+
+		if n==lim: return [self]
+
+		repeatRows = self.repeatRows
+		repeatCols = self.repeatCols
+		splitByRow = self.splitByRow
+		data = self._cellvalues
+
+		#we're going to split into two superRows
+		R0 = Table( self._argW, self._argH[:n], data[:n],
+				repeatRows=repeatRows, repeatCols=repeatCols,
+				splitByRow=splitByRow)
+
+		#copy the styles and commands
+		R0._cellStyles = self._cellStyles[:n]
+		R0._cr_0(n,self._linecmds)
+		R0._cr_0(n,self._bkgrndcmds)
+
+		if repeatRows:
+			R1 = Table(self._argW, self._argH[:repeatRows]+self._argH[n:],
+					data[:repeatRows]+data[n:],
+					repeatRows=repeatRows, repeatCols=repeatCols,
+					splitByRow=splitByRow)
+			R1._cellStyles = self._cellStyles[:repeatRows]+self._cellStyles[n:]
+			R1._cr_1_1(n,repeatRows,self._linecmds)
+			R1._cr_1_1(n,repeatRows,self._bkgrndcmds)
+		else:
+			R1 = Table(self._argW, self._argH[n:],data[n:],
+					repeatRows=repeatRows, repeatCols=repeatCols,
+					splitByRow=splitByRow)
+			R1._cellStyles = self._cellStyles[n:]
+			R1._cr_1_0(n,self._linecmds)
+			R1._cr_1_0(n,self._bkgrndcmds)
+
+		return [R0,R1]
+
+	def split(self, availWidth, availHeight):
+		if self.splitByRow:
+			if self._width>availWidth: return []
+			return self._splitRows(availHeight)
+		else:
+			raise NotImplementedError
+		
 				
 	def draw(self):
 		nudge = 0.5 * (self.availWidth - self._width)
 		self.canv.translate(nudge, 0)
 		self._drawBkgrnd()
 		self._drawLines()
-		for row, rowstyle, rowpos, rowheight in map(None, self._cellvalues, self._cellstyles, self._rowpositions[1:], self._rowHeights):
+		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):
 				self._drawCell(cellval, cellstyle, (colpos, rowpos), (colwidth, rowheight))
 
@@ -383,9 +470,9 @@
 def _isLineCommand(cmd):
 	return cmd[0] in LINECOMMANDS
 
-def _setCellStyle(cellstyles, i, j, op, values):
-	new = CellStyle('<%d, %d>' % (i,j), cellstyles[i][j])
-	cellstyles[i][j] = new
+def _setCellStyle(cellStyles, i, j, op, values):
+	new = CellStyle('<%d, %d>' % (i,j), cellStyles[i][j])
+	cellStyles[i][j] = new
 	if op == 'FONT':
 		new.fontname = values[0]
 		new.fontsize = values[1]
@@ -680,6 +767,16 @@
             ('BOX', (0,0), (-1,-1), 0.25, colors.black),
             ])
 	lst.append(t)
+	t=apply(Table,([None, None], [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None], [('Attribute', 'Synonyms'), ('alignment', 'align, alignment'), ('bulletColor', 'bulletcolor, bcolor'), ('bulletFontName', 'bfont, bulletfontname'), ('bulletFontSize', 'bfontsize, bulletfontsize'), ('bulletIndent', 'bindent, bulletindent'), ('firstLineIndent', 'findent, firstlineindent'), ('fontName', 'face, fontname, font'), ('fontSize', 'size, fontsize'), ('leading', 'leading'), ('leftIndent', 'leftindent, lindent'), ('rightIndent', 'rightindent, rindent'), ('spaceAfter', 'spaceafter, spacea'), ('spaceBefore', 'spacebefore, spaceb'), ('textColor', 'fg, textcolor, color')]))
+	t.repeatRows = 1
+	t.setStyle([
+				('FONT',(0,0),(-1,1),'Times-Bold',10,12),
+				('FONT',(0,1),(-1,-1),'Courier',8,8),
+				('VALIGN',(0,0),(-1,-1),'MIDDLE'),
+				('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
+				('BOX', (0,0), (-1,-1), 0.25, colors.black),
+				])
+	lst.append(t)
 	SimpleDocTemplate('testtables.pdf', showBoundary=1).build(lst)
 
 if __name__ == '__main__':