[reportlab-users] Flexible table layout

Dirk Holtwick reportlab-users@reportlab.com
Thu, 13 Feb 2003 10:32:50 +0100


Hi,

here is a drop in suggestion for a more flexible table layout. for the 
colWidths just pass a list of _width() objects and for totalWidth one 
_width() object. Width can be
	
	- an absolute value 		(_width("1.2cm"))
	- a percentage 			(_width("33%"))
	- a space consuming "spanner" 	(_width(None))

Attention, I added "align" to the init values! Was quite unhandy formerly.

Enjoy,
Dirk

-----

class MyTable(Table):

     def __init__(self, data, align, colWidths=None,
	totalWidth=None, rowHeights=None, style=None,
         repeatRows=0, repeatCols=0, splitByRow=1, 			
	emptyTableAction=None):

         self._data = data
         self._align = align
         self._colwidths = colWidths
         self._rowheights = rowHeights
         self._style = style
         self._repeatrows = repeatRows
         self._repeatcols = repeatCols
         self._splitbyrow = splitByRow
         self._emptytableaction = emptyTableAction
         self._notset = 1
         self._totalwidth = totalWidth

     def wrap(self, aw, ah):
         if self._notset:
             self._notset = 0

             cw = self._colwidths
             tw = self._totalwidth.calc(aw)

             ws = []
             sc = 0
             sp = 0

             # calculate known
             for c in cw:
                 if c.span():
                     ws.append(None)
                     sc = sc + 1
                 else:
                     v = c.calc(tw)
                     sp = sp + v
                     ws.append(v)

             # donate space to the rest
             cw = []
             if sc:
                 rest = (tw - sp) / sc
                 for c in ws:
                     if c==None:
                         cw.append(rest)
                     else:
                         cw.append(c)
             else:
                 cw = ws

             Table.__init__(self,
                 self._data,
                 cw,
                 self._rowheights,
                 self._style,
                 self._repeatrows,
                 self._repeatcols,
                 self._splitbyrow,
                 self._emptytableaction)
             self.hAlign = self._align

         return Table.wrap(self, aw, ah)

def get_length(s):
     try:
         s = str(s)
         # for us germans, we like comma ;-)
         s = string.replace(s,",",".")
         if s[-2:]=='cm': return float(s[:-2])*cm
         if s[-2:]=='in': return float(s[:-2])*inch
         if s[-2:]=='pt': return float(s[:-2])
         if s[-1:]=='i': return float(s[:-1])*inch
         return float(s)
     except:
         raise ValueError, "Can't convert '%s' to length" % s

class _width:

     def __init__(self, value=None):
         self.value = None
         self.fix  = None
         if value!=None:
             self.set(value)

     def set(self, value):
         if string.find(value,"%")>=0:
             self.value = float(
		string.strip(string.replace(value, "%", "")))
             self.fix = 0
         else:
             self.value = get_length(value)
             self.fix = 1

     def calc(self, avail):
         if self.value==None:
             return avail
         if self.fix:
             return self.value
         else:
             return ((avail/100.0)*self.value)

     def span(self):
         return not self.value