Added identity method to Flowables
authorrgbecker
Wed, 01 Aug 2001 13:01:44 +0000
changeset 1103 857af510186d
parent 1102 6fb285f5f382
child 1104 1c9c01e2a7b1
Added identity method to Flowables
reportlab/platypus/doctemplate.py
reportlab/platypus/flowables.py
reportlab/platypus/tables.py
--- a/reportlab/platypus/doctemplate.py	Wed Aug 01 10:22:10 2001 +0000
+++ b/reportlab/platypus/doctemplate.py	Wed Aug 01 13:01:44 2001 +0000
@@ -1,9 +1,9 @@
 #copyright ReportLab Inc. 2000
 #see license.txt for license details
 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/doctemplate.py?cvsroot=reportlab
-#$Header: /tmp/reportlab/reportlab/platypus/doctemplate.py,v 1.40 2001/05/11 15:00:52 rgbecker Exp $
+#$Header: /tmp/reportlab/reportlab/platypus/doctemplate.py,v 1.41 2001/08/01 13:01:44 rgbecker Exp $
 
-__version__=''' $Id: doctemplate.py,v 1.40 2001/05/11 15:00:52 rgbecker Exp $ '''
+__version__=''' $Id: doctemplate.py,v 1.41 2001/08/01 13:01:44 rgbecker Exp $ '''
 
 __doc__="""
 This module contains the core structure of platypus.
@@ -408,15 +408,7 @@
 					if self.frame.add(S[0], self.canv, trySplit=0):
 						self.afterFlowable(S[0])
 					else:
-						if hasattr(f,'text'):
-							print 'Offending text:'
-							print "'''"+f.text+"'''"
-							print f.style.fontName, f.style.fontSize, f.style.leading, f.style.firstLineIndent, f.style.leftIndent, f.style.rightIndent
-							print S[0].style.fontName, S[0].style.fontSize, S[0].style.leading, S[0].style.firstLineIndent, S[0].style.leftIndent, S[0].style.rightIndent
-						elif hasattr(f, 'getPlainText'):
-							print 'Offending Paragraph:'
-							print f.getPlainText()
-						raise "LayoutError", "splitting error type=%s" % type(f)
+						raise "LayoutError", "splitting error on page %d in\n%s" % (self.page,f.identity(30))
 					del S[0]
 					for f in xrange(n-1):
 						flowables.insert(f,S[f])	# put split flowables back on the list
@@ -424,14 +416,11 @@
 					# this must be cleared when they are finally drawn!
 ##					if hasattr(f,'postponed'):
 					if hasattr(f,'_postponed'):
-						message = "Flowable %s too large on page %d" % (f, self.page)
+						message = "Flowable %s too large on page %d" % (f.identity(30), self.page)
 						#show us, it might be handy
 						#HACK = it seems within tables we sometimes
 						#get an empty paragraph that won't fit and this
 						#causes it to fall over.  FIXME FIXME FIXME
-						if hasattr(f, 'getPlainText'):
-							print 'Offending Paragraph:'
-							print f.getPlainText()
 						raise "LayoutError", message
 ##					f.postponed = 1
 					f._postponed = 1
--- a/reportlab/platypus/flowables.py	Wed Aug 01 10:22:10 2001 +0000
+++ b/reportlab/platypus/flowables.py	Wed Aug 01 13:01:44 2001 +0000
@@ -1,8 +1,8 @@
 #copyright ReportLab Inc. 2000
 #see license.txt for license details
 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/flowables.py?cvsroot=reportlab
-#$Header: /tmp/reportlab/reportlab/platypus/flowables.py,v 1.20 2001/06/22 11:23:48 rgbecker Exp $
-__version__=''' $Id: flowables.py,v 1.20 2001/06/22 11:23:48 rgbecker Exp $ '''
+#$Header: /tmp/reportlab/reportlab/platypus/flowables.py,v 1.21 2001/08/01 13:01:44 rgbecker Exp $
+__version__=''' $Id: flowables.py,v 1.21 2001/08/01 13:01:44 rgbecker Exp $ '''
 __doc__="""
 A flowable is a "floating element" in a document whose exact position is determined by the
 other elements that precede it, such as a paragraph, a diagram interspersed between paragraphs,
@@ -108,6 +108,22 @@
 		"""Hook for IndexingFlowables - things which have cross references"""
 		return 0
 
+	def identity(self, maxLen=None):
+		'''
+		This method should attempt to return a string that can be used to identify
+		a particular flowable uniquely. The result can then be used for debugging
+		and or error printouts
+		'''
+		if hasattr(self, 'getPlainText'):
+			r = self.getPlainText()
+		elif hasattr(self, 'text'):
+			r = self.text
+		else:
+			r = '...'
+		if r and maxLen:
+			r = r[:maxLen]
+		return "<%s at %d>%s" % (self.__class__.__name__, id(self), r)
+
 class XBox(Flowable):
 	"""Example flowable - a box with an x through it and a caption.
 	This has a known size, so does not need to respond to wrap()."""
@@ -230,7 +246,7 @@
 	def __init__(self, filename, width=None, height=None):
 		"""If size to draw at not specified, get it from the image."""
 		from reportlab.lib.utils import PIL_Image  #this will raise an error if they do not have PIL.
-		self.filename = filename
+		self._filename = self.filename = filename
 		self.hAlign = 'CENTER'
 		# if it is a JPEG, will be inlined within the file -
 		# but we still need to know its size now
@@ -240,7 +256,7 @@
 			self.imageHeight = info[1]
 		else:
 			# we have to assume this is a file like object
-			self. filename = img = PIL_Image.open(filename)
+			self.filename = img = PIL_Image.open(filename)
 			(self.imageWidth, self.imageHeight) = img.size
 		if width:
 			self.drawWidth = width
@@ -263,6 +279,13 @@
 								self.drawWidth,
 								self.drawHeight
 								)
+
+	def identity(self,maxLen):
+		r = Flowable.identity(self,maxLen)
+		if r[-4:]=='>...' and type(self._filename) is StringType:
+			r = "%s filename=%s>" % (r[:-4],self._filename)
+		return r
+
 class Spacer(Flowable):
 	"""A spacer just takes up space and doesn't draw anything - it guarantees
 	   a gap between objects."""
@@ -353,5 +376,3 @@
 		return (0,0)
 	def draw(self):
 		exec self.command in globals(), {'canvas':self.canv}
-
-	
--- a/reportlab/platypus/tables.py	Wed Aug 01 10:22:10 2001 +0000
+++ b/reportlab/platypus/tables.py	Wed Aug 01 13:01:44 2001 +0000
@@ -1,8 +1,8 @@
 #copyright ReportLab Inc. 2000
 #see license.txt for license details
 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/tables.py?cvsroot=reportlab
-#$Header: /tmp/reportlab/reportlab/platypus/tables.py,v 1.39 2001/05/05 13:37:10 aaron_watters Exp $
-__version__=''' $Id: tables.py,v 1.39 2001/05/05 13:37:10 aaron_watters Exp $ '''
+#$Header: /tmp/reportlab/reportlab/platypus/tables.py,v 1.40 2001/08/01 13:01:44 rgbecker Exp $
+__version__=''' $Id: tables.py,v 1.40 2001/08/01 13:01:44 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
@@ -25,6 +25,7 @@
 from reportlab.platypus import *
 from reportlab.lib.styles import PropertySet, getSampleStyleSheet
 from reportlab.lib import colors
+from reportlab.lib.utils import fp_str
 from reportlab.pdfbase import pdfmetrics
 import operator, string
 
@@ -110,23 +111,23 @@
 	def __init__(self, data, colWidths=None, rowHeights=None, style=None,
 				repeatRows=0, repeatCols=0, splitByRow=1):
 		#print "colWidths", colWidths
-		nrows = len(data)
+		self._nrows = nrows = len(data)
 		if len(data)==0 or type(data) not in _SeqTypes:
-			raise ValueError, "Table must have at least 1 row"
+			raise ValueError, "%s must have at least 1 row" % self.identity()
 		ncols = max(map(_rowLen,data))
 		if not ncols:
-			raise ValueError, "Table must have at least 1 column"
+			raise ValueError, "%s must have at least 1 column" % self.identity()
 		if colWidths is None: colWidths = ncols*[None]
 		elif len(colWidths) != ncols:
-			raise ValueError, "Data error - %d columns in data but %d in grid" % (ncols, len(colWidths))
+			raise ValueError, "%s data error - %d columns in data but %d in grid" % (self.identity(),ncols, len(colWidths))
 		if rowHeights is None: rowHeights = nrows*[None]
 		elif len(rowHeights) != nrows:
-			raise ValueError, "Data error - %d rows in data but %d in grid" % (nrows, len(rowHeights))
-		self._nrows = nrows
-		ncols = self._ncols = len(colWidths)
+			raise ValueError, "%s data error - %d rows in data but %d in grid" % (self.identity(),nrows, len(rowHeights))
+		ncols = len(colWidths)
 		for i in range(nrows):
 			if len(data[i]) != ncols:
-				raise ValueError, "Not enough data points in row %d!" % i
+				raise ValueError, "%s not enough data points in row %d!" % (self.identity(),i)
+		self._ncols = ncols
 		self._rowHeights = self._argH = rowHeights
 		self._colWidths = self._argW = colWidths
 		self._cellvalues = data
@@ -163,6 +164,43 @@
 		cv = string.replace(cv, "\n", "\n  ")
 		return "Table(\n rowHeights=%s,\n colWidths=%s,\n%s\n) # end table" % (r,c,cv)
 
+	def identity(self, maxLen):
+		'''Identify our selves as well as possible'''
+		vx = None
+		nr = self._nrows
+		if not hasattr(self,'_ncols'):
+			nc = 'unknown'
+		else:
+			nc = self._ncols
+			cv = self._cellvalues
+			b = 0
+			for i in xrange(nr):
+				for j in xrange(nc):
+					v = cv[i][j]
+					t = type(v)
+					if t in _SeqTypes or isinstance(v,Flowable):
+						if not t in _SeqTypes: v = (v,)
+						r = ''
+						for vij in v:
+							r = vij.identity(maxLen)
+							if r and r[-4:]!='>...':
+								break
+						if r and r[-4:]!='>...':
+							ix, jx, vx, b = i, j, r, 1
+					else:
+						v = v is None and '' or str(v)
+						ix, jx, vx = i, j, v
+						b = (vx and t is StringType) and 1 or 0
+						if maxLen: vx = vx[:maxLen]
+					if b: break
+				if b: break
+		if vx:
+			vx = ' with cell(%d,%d) containing\n%s' % (ix,jx,repr(vx))
+		else:
+			vx = '...'
+
+		return "<%s at %d %d rows x %s cols>%s" % (self.__class__.__name__, id(self), nr, nc, vx)
+
 	def _calc(self):
 		if hasattr(self,'_width'): return
 
@@ -179,18 +217,19 @@
 				V = self._cellvalues[i] # values for row i
 				S = self._cellStyles[i] # styles for row i
 				h = 0
+				j = 0
 				for v, s, w in map(None, V, S, W): # value, style, width (lengths must match)
-					#print "v,s,w", v,s,w
+					j = j + 1
 					t = type(v)
 					if t in _SeqTypes or isinstance(v,Flowable):
 						if not t in _SeqTypes: v = (v,)
 						if w is None:
-							raise ValueError, "Flowables cell can't have auto width"
+							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))
 						dW,t = _listCellGeom(v,w,s)
 						#print "leftpadding, rightpadding", s.leftPadding, s.rightPadding
 						dW = dW + s.leftPadding + s.rightPadding
 						if dW>w:
-							raise "LayoutError", "Flowable %s (%sx%s points) too wide for cell (%sx* points)." % (v,dW,t,w)
+							raise "LayoutError", "Flowable %s (%sx%s points) too wide for cell(%d,%d) (%sx* points) in\n%s" % (v[0].identity(30),fp_str(dW),fp_str(t),i,j, fp_str(w), self.identity(30))
 					else:
 						if t is not StringType:
 							v = v is None and '' or str(v)
@@ -205,22 +244,24 @@
 			W = W[:]
 			self._colWidths = W
 			while None in W:
-				i = W.index(None)
-				f = lambda x,i=i: operator.getitem(x,i)
+				j = W.index(None)
+				f = lambda x,j=j: operator.getitem(x,j)
 				V = map(f,self._cellvalues)
 				S = map(f,self._cellStyles)
 				w = 0
+				i = 0
 				d = hasattr(self,'canv') and self.canv or pdfmetrics
 				for v, s in map(None, V, S):
+					i = i + 1
 					t = type(v)
 					if t in _SeqTypes or isinstance(v,Flowable):
-						raise ValueError, "Flowables cell can't have auto width"
+						raise ValueError, "Flowable %s in cell(%d,%d) can't have auto width\n%s" % (v.identity(30),i,j,self.identity(30))
 					elif t is not StringType: v = v is None and '' or str(v)
 					v = string.split(v, "\n")
 					t = s.leftPadding+s.rightPadding + max(map(lambda a, b=s.fontname,
 								c=s.fontsize,d=d.stringWidth: d(a,b,c), v))
 					if t>w: w = t	#record a new maximum
-				W[i] = w
+				W[j] = w
 
 		height = self._height = reduce(operator.add, H, 0)
 		#print "height, H", height, H
@@ -954,6 +995,7 @@
 	I = Image(os.path.join(os.path.dirname(reportlab.platypus.__file__),'..','demos','pythonpoint','leftlogo.gif'))
 	I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth
 	I.drawWidth = 1.25*inch
+	I.drawWidth = 9.25*inch #uncomment to see better messaging
 	P = Paragraph("<para align=center spaceb=3>The <b>ReportLab Left <font color=red>Logo</font></b> Image</para>", styleSheet["BodyText"])
 	data=  [['A', 'B', 'C', Paragraph("<b>A pa<font color=red>r</font>a<i>graph</i></b><super><font color=yellow>1</font></super>",styleSheet["BodyText"]), 'D'],
 			['00', '01', '02', [I,P], '04'],