1#!/bin/env python
2#Copyright ReportLab Europe Ltd. 2000-2017
3#see license.txt for license details
4__version__='3.3.0'
5__doc__='Test script for reportlab.tables'
6from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, printLocation
7setOutDir(__name__)
8import os,unittest
9from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, FrameBG
10from reportlab.platypus.paragraph import Paragraph
11from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
12from reportlab.lib.units import inch, cm
13from reportlab.lib import colors
14from reportlab.graphics.charts.linecharts import HorizontalLineChart
15from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin
16from reportlab.graphics.charts.barcharts import VerticalBarChart
17
18styleSheet = getSampleStyleSheet()
19
20def getTable():
21    t = Table((('','North','South','East','West'),
22             ('Quarter 1',100,200,300,400),
23             ('Quarter 2',100,400,600,800),
24             ('Total',300,600,900,'1,200')),
25             (72,36,36,36,36),
26             (24, 16,16,18)
27            )
28    return t
29
30def makeStyles():
31    styles = []
32    for i in range(5):
33        styles.append(TableStyle([('ALIGN', (1,1), (-1,-1), 'RIGHT'),
34                                  ('ALIGN', (0,0), (-1,0), 'CENTRE'),
35                                  ('HREF', (0,0), (0,0), 'www.google.com'),
36                                  ]))
37    for style in styles[1:]:
38        style.add('GRID', (0,0), (-1,-1), 0.25, colors.black)
39    for style in styles[2:]:
40        style.add('LINEBELOW', (0,0), (-1,0), 2, colors.black)
41    for style in styles[3:]:
42        style.add('LINEABOVE', (0, -1), (-1,-1), 2, colors.black)
43    styles[-1].add('LINEBELOW',(1,-1), (-1, -1), 2, (0.5, 0.5, 0.5))
44    return styles
45
46def run():
47    doc = SimpleDocTemplate(outputfile('test_platypus_tables.pdf'), pagesize=(8.5*inch, 11*inch), showBoundary=1)
48    lst = []
49    from reportlab import Version
50    styNormal = styleSheet['Normal']
51    styBackground = ParagraphStyle('background', parent=styNormal, backColor=colors.pink)
52    styH1 = styleSheet['Heading1']
53    lst.append(FrameBG(color=colors.red))
54    lst.append(Paragraph("First, a test of how tables align their content...", styH1))
55    lst.append(Paragraph("""Generated with version %s""" % Version,
56                        styNormal))
57    lst.append(Paragraph("""In release 2.3, cells with plain text positioned their
58                         text differently to cells with Paragraphs using the
59                         same font.  Hopefully now they are back on the same baseline""",
60                        styNormal))
61    lst.append(FrameBG(color=colors.blue))
62    ts1 = TableStyle([
63                ('ALIGN', (0,0), (-1,0), 'RIGHT'),
64                ('BACKGROUND', (0,0), (-1,0), colors.lightgrey),
65                ('VALIGN', (0,0), (-1,-1), 'TOP'),
66                ('GRID', (0,0), (-1,-1), 0.25, colors.black),
67                    ])
68    t1 = Table([
69        ('plain text','plain text','shortpara','plain text', 'long para'),
70        ('Text','more text', Paragraph('Is this para level?', styBackground), 'Back to text', Paragraph('Short para again', styBackground)),
71        ('Text',
72            'more text',
73            Paragraph('Is this level?', styBackground),
74            'This is plain\ntext with line breaks\nto compare against\nthe para on right',
75            Paragraph('Long paragraph we expect to wrap over several lines accurately', styBackground)),
76
77        ])
78    t1.setStyle(ts1)
79    lst.append(t1)
80    lst.append(FrameBG(start=False))
81    lst.append(Spacer(0,10))
82    lst.append(Paragraph("Now we make a table with just one cell containing a string...note how the text sits low", styNormal))
83    lst.append(FrameBG(start=False))
84
85    tsGrid = TableStyle([
86                ('GRID', (0,0), (-1,-1), 0.25, colors.black),
87                    ])
88    lst.append(Table([['One cell of plain text']], style=tsGrid, colWidths=[200]))
89
90    lst.append(Spacer(0,10))
91    lst.append(Paragraph("Now we make a table with just one cell containing a para...should be same position.  Note that the overall bounding box is an approximation and lies - it always did.", styNormal))
92    lst.append(Table([[Paragraph('One cell containing a paragraph.  ÄÉ∫', styBackground)]], style=tsGrid, colWidths=[200]))
93
94    lst.append(Spacer(0,10))
95    lst.append(Paragraph("Paragraphs jumped up post 2.1.  Ideally they should align the same.", styNormal))
96
97
98    lst.append(Spacer(0,30))
99    lst.append(Paragraph("Now for all the tests we had before.  See also the much longer test_platypus_tables_2.pdf, which for reasons unknown was split into a separate file generated by the same script", styNormal))
100
101    styles = makeStyles()
102    for style in styles:
103        t = getTable()
104        t.setStyle(style)
105##        print '--------------'
106##        for rowstyle in t._cellstyles:
107##            for s in rowstyle:
108##                print s.alignment
109        lst.append(t)
110        lst.append(Spacer(0,12))
111
112    t=Table([['VERTICAL Gradient Red top, grey bottom','Horizontal Gradient Blue left, green right'],
113             ['HORIZONTAL Gradient Span grey left red right', ''],
114             ['VERTICAL Gradiant Span Blue top green bottom',''],
115             ['','CLEAR']],[3.5*inch, 2.7*inch])
116    style=TableStyle([
117    ('SPAN', (0,1),(1,1)),
118    ('SPAN', (0,2),(0,3)),
119    ('BACKGROUND',(0,0), (0,0),['VERTICAL', colors.grey, colors.red]),
120    ('BACKGROUND',(1,0), (1,0),['HORIZONTAL', colors.blue, colors.green]),
121    ('BACKGROUND',(0,1), (1,1),['HORIZONTAL', colors.grey, colors.red]),
122    ('BACKGROUND',(0,2), (0,3),['VERTICAL', colors.blue, colors.green])
123    ])
124    t.setStyle(style)
125    lst.append(t)
126
127    #illustrate usage of minRowHeights idea from Jon Hinton inivatajon @ bitbucket.org
128    t=Table([['VERTICAL Red --> grey  minRowHeights[0]=30','Horizontal Gradient Blue left, green right'],
129             ['HORIZONTAL Gradient Span grey left red right', ''],
130             ['VERTICAL Gradiant Span Blue top green bottom',''],
131             ['','CLEAR']],[3.5*inch, 2.7*inch],minRowHeights=(30,), spaceBefore=15)
132    style=TableStyle([
133    ('SPAN', (0,1),(1,1)),
134    ('SPAN', (0,2),(0,3)),
135    ('VALIGN', (0,0),(-1,0),'MIDDLE'),
136    ('BACKGROUND',(0,0), (0,0),['VERTICAL', colors.grey, colors.red]),
137    ('BACKGROUND',(1,0), (1,0),['HORIZONTAL', colors.blue, colors.green]),
138    ('BACKGROUND',(0,1), (1,1),['HORIZONTAL', colors.grey, colors.red]),
139    ('BACKGROUND',(0,2), (0,3),['VERTICAL', colors.blue, colors.green])
140    ])
141    t.setStyle(style)
142
143    t=Table([],[3.5*inch, 2.7*inch],minRowHeights=(30,), spaceBefore=15, style=style, emptyTableAction='ignore')
144    lst.append(t)
145    doc.build(lst)
146
147class TableBarChart(_DrawingEditorMixin,Drawing):
148    def __init__(self,width=400,height=200,*args,**kw):
149        Drawing.__init__(self,width,height,*args,**kw)
150        self.width = 136
151        self.height = 140
152        self._add(self,VerticalBarChart(),name='chart',validate=None,desc=None)
153        self.chart.y = 20
154        self.chart.width = self.width - 21
155        self.chart.height = self.height - 24
156        self.chart.categoryAxis.categoryNames = ['Spring','Summer','Autumn','Winter']
157        self.chart.categoryAxis.labels.fontSize = 7
158
159def old_tables_test():
160    from reportlab.lib.units import inch, cm
161    from reportlab.platypus.flowables import Image, PageBreak, Spacer, XBox
162    from reportlab.platypus.paragraph import Paragraph
163    from reportlab.platypus.xpreformatted import XPreformatted
164    from reportlab.platypus.flowables import Preformatted
165    from reportlab.platypus.doctemplate import SimpleDocTemplate
166    from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
167    from reportlab.platypus.tables import GRID_STYLE, BOX_STYLE, LABELED_GRID_STYLE, COLORED_GRID_STYLE, LIST_STYLE, LongTable
168    rowheights = (24, 16, 16, 16, 16)
169    rowheights2 = (24, 16, 16, 16, 30)
170    colwidths = (50, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32)
171    data = (
172        ('', 'Jan', 'Feb', 'Mar','Apr','May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
173        ('Mugs', 0, 4, 17, 3, 21, 47, 12, 33, 2, -2, 44, 89),
174        ('T-Shirts', 0, 42, 9, -3, 16, 4, 72, 89, 3, 19, 32, 119),
175        ('Key Ring', 0,0,0,0,0,0,1,0,0,0,2,13),
176        ('Hats', 893, 912, '1,212', 643, 789, 159, 888, '1,298', 832, 453, '1,344','2,843')
177        )
178    data2 = (
179        ('', 'Jan', 'Feb', 'Mar','Apr','May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
180        ('Mugs', 0, 4, 17, 3, 21, 47, 12, 33, 2, -2, 44, 89),
181        ('T-Shirts', 0, 42, 9, -3, 16, 4, 72, 89, 3, 19, 32, 119),
182        ('Key Ring', 0,0,0,0,0,0,1,0,0,0,2,13),
183        ('Hats\nLarge', 893, 912, '1,212', 643, 789, 159, 888, '1,298', 832, 453, '1,344','2,843')
184        )
185    lst = []
186    lst_add = lst.append
187    lst_add(Paragraph("Tables", styleSheet['Heading1']))
188    lst_add(Paragraph(__doc__, styleSheet['BodyText']))
189    lst_add(Paragraph("The Tables (shown in different styles below) were created using the following code:", styleSheet['BodyText']))
190    lst_add(Preformatted("""
191    colwidths = (50, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32)
192    rowheights = (24, 16, 16, 16, 16)
193    data = (
194        ('', 'Jan', 'Feb', 'Mar','Apr','May', 'Jun',
195           'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
196        ('Mugs', 0, 4, 17, 3, 21, 47, 12, 33, 2, -2, 44, 89),
197        ('T-Shirts', 0, 42, 9, -3, 16, 4, 72, 89, 3, 19, 32, 119),
198        ('Key Ring', 0,0,0,0,0,0,1,0,0,0,2,13),
199        ('Hats', 893, 912, '1,212', 643, 789, 159,
200             888, '1,298', 832, 453, '1,344','2,843')
201        )
202    t = Table(data, colwidths, rowheights)
203    """, styleSheet['Code'], dedent=4))
204    lst_add(Paragraph("""
205    You can then give the Table a TableStyle object to control its format. The first TableStyle used was
206    created as follows:
207    """, styleSheet['BodyText']))
208    lst_add(Preformatted("""
209GRID_STYLE = TableStyle(
210    [('GRID', (0,0), (-1,-1), 0.25, colors.black),
211     ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
212    )
213    """, styleSheet['Code']))
214    lst_add(Paragraph("""
215    TableStyles are created by passing in a list of commands. There are two types of commands - line commands
216    and cell formatting commands. In all cases, the first three elements of a command are the command name,
217    the starting cell and the ending cell.
218    """, styleSheet['BodyText']))
219    lst_add(Paragraph("""
220    Line commands always follow this with the weight and color of the desired lines. Colors can be names,
221    or they can be specified as a (R,G,B) tuple, where R, G and B are floats and (0,0,0) is black. The line
222    command names are: GRID, BOX, OUTLINE, INNERGRID, LINEBELOW, LINEABOVE, LINEBEFORE
223    and LINEAFTER. BOX and OUTLINE are equivalent, and GRID is the equivalent of applying both BOX and
224    INNERGRID.
225    """, styleSheet['BodyText']))
226    lst_add(Paragraph("""
227    Cell formatting commands are:
228    """, styleSheet['BodyText']))
229    lst_add(Paragraph("""
230    FONT - takes fontname, fontsize and (optional) leading.
231    """, styleSheet['Definition']))
232    lst_add(Paragraph("""
233    TEXTCOLOR - takes a color name or (R,G,B) tuple.
234    """, styleSheet['Definition']))
235    lst_add(Paragraph("""
236    ALIGNMENT (or ALIGN) - takes one of LEFT, RIGHT, CENTRE (or CENTER) or DECIMAL.
237    """, styleSheet['Definition']))
238    lst_add(Paragraph("""
239    LEFTPADDING - defaults to 6.
240    """, styleSheet['Definition']))
241    lst_add(Paragraph("""
242    RIGHTPADDING - defaults to 6.
243    """, styleSheet['Definition']))
244    lst_add(Paragraph("""
245    BOTTOMPADDING - defaults to 3.
246    """, styleSheet['Definition']))
247    lst_add(Paragraph("""
248    A tablestyle is applied to a table by calling Table.setStyle(tablestyle).
249    """, styleSheet['BodyText']))
250    t = Table(data, colwidths, rowheights)
251    t.setStyle(GRID_STYLE)
252    lst_add(PageBreak())
253    lst_add(Paragraph("This is GRID_STYLE\n", styleSheet['BodyText']))
254    lst_add(t)
255
256    t = Table(data, colwidths, rowheights)
257    t.setStyle(BOX_STYLE)
258    lst_add(Paragraph("This is BOX_STYLE\n", styleSheet['BodyText']))
259    lst_add(t)
260    lst_add(Paragraph("""
261    It was created as follows:
262    """, styleSheet['BodyText']))
263    lst_add(Preformatted("""
264BOX_STYLE = TableStyle(
265    [('BOX', (0,0), (-1,-1), 0.50, colors.black),
266     ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
267    )
268    """, styleSheet['Code']))
269
270    t = Table(data, colwidths, rowheights)
271    t.setStyle(LABELED_GRID_STYLE)
272    lst_add(Paragraph("This is LABELED_GRID_STYLE\n", styleSheet['BodyText']))
273    lst_add(t)
274    t = Table(data2, colwidths, rowheights2)
275    t.setStyle(LABELED_GRID_STYLE)
276    lst_add(Paragraph("This is LABELED_GRID_STYLE ILLUSTRATES EXPLICIT LINE SPLITTING WITH NEWLINE (different heights and data)\n", styleSheet['BodyText']))
277    lst_add(t)
278    lst_add(Paragraph("""
279    It was created as follows:
280    """, styleSheet['BodyText']))
281    lst_add(Preformatted("""
282LABELED_GRID_STYLE = TableStyle(
283    [('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
284     ('BOX', (0,0), (-1,-1), 2, colors.black),
285     ('LINEBELOW', (0,0), (-1,0), 2, colors.black),
286     ('LINEAFTER', (0,0), (0,-1), 2, colors.black),
287     ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
288    )
289    """, styleSheet['Code']))
290    lst_add(PageBreak())
291
292    t = Table(data, colwidths, rowheights)
293    t.setStyle(COLORED_GRID_STYLE)
294    lst_add(Paragraph("This is COLORED_GRID_STYLE\n", styleSheet['BodyText']))
295    lst_add(t)
296    lst_add(Paragraph("""
297    It was created as follows:
298    """, styleSheet['BodyText']))
299    lst_add(Preformatted("""
300COLORED_GRID_STYLE = TableStyle(
301    [('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
302     ('BOX', (0,0), (-1,-1), 2, colors.red),
303     ('LINEBELOW', (0,0), (-1,0), 2, colors.black),
304     ('LINEAFTER', (0,0), (0,-1), 2, colors.black),
305     ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
306    )
307    """, styleSheet['Code']))
308
309    t = Table(data, colwidths, rowheights)
310    t.setStyle(LIST_STYLE)
311    lst_add(Paragraph("This is LIST_STYLE\n", styleSheet['BodyText']))
312    lst_add(t)
313    lst_add(Paragraph("""
314    It was created as follows:
315    """, styleSheet['BodyText']))
316    lst_add(Preformatted("""
317LIST_STYLE = TableStyle(
318    [('LINEABOVE', (0,0), (-1,0), 2, colors.green),
319     ('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
320     ('LINEBELOW', (0,-1), (-1,-1), 2, colors.green),
321     ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
322    )
323    """, styleSheet['Code']))
324
325    t = Table(data, colwidths, rowheights)
326    ts = TableStyle(
327    [('LINEABOVE', (0,0), (-1,0), 2, colors.green),
328     ('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
329     ('LINEBELOW', (0,-1), (-1,-1), 3, colors.green,'butt'),
330     ('LINEBELOW', (0,-1), (-1,-1), 1, colors.white,'butt'),
331     ('ALIGN', (1,1), (-1,-1), 'RIGHT'),
332     ('TEXTCOLOR', (0,1), (0,-1), colors.red),
333     ('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))]
334    )
335    t.setStyle(ts)
336    lst_add(Paragraph("This is a custom style\n", styleSheet['BodyText']))
337    lst_add(t)
338    lst_add(Paragraph("""
339    It was created as follows:
340    """, styleSheet['BodyText']))
341    lst_add(Preformatted("""
342   ts = TableStyle(
343    [('LINEABOVE', (0,0), (-1,0), 2, colors.green),
344     ('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
345     ('LINEBELOW', (0,-1), (-1,-1), 3, colors.green,'butt'),
346     ('LINEBELOW', (0,-1), (-1,-1), 1, colors.white,'butt'),
347     ('ALIGN', (1,1), (-1,-1), 'RIGHT'),
348     ('TEXTCOLOR', (0,1), (0,-1), colors.red),
349     ('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))]
350    )
351    """, styleSheet['Code']))
352    data = (
353        ('', 'Jan\nCold', 'Feb\n', 'Mar\n','Apr\n','May\n', 'Jun\nHot', 'Jul\n', 'Aug\nThunder', 'Sep\n', 'Oct\n', 'Nov\n', 'Dec\n'),
354        ('Mugs', 0, 4, 17, 3, 21, 47, 12, 33, 2, -2, 44, 89),
355        ('T-Shirts', 0, 42, 9, -3, 16, 4, 72, 89, 3, 19, 32, 119),
356        ('Key Ring', 0,0,0,0,0,0,1,0,0,0,2,13),
357        ('Hats', 893, 912, '1,212', 643, 789, 159, 888, '1,298', 832, 453, '1,344','2,843')
358        )
359    c = list(colwidths)
360    c[0] = None
361    c[8] = None
362    t = Table(data, c, [None]+list(rowheights[1:]))
363    t.setStyle(LIST_STYLE)
364    lst_add(Paragraph("""
365        This is a LIST_STYLE table with the first rowheight set to None ie automatic.
366        The top row cells are split at a newline '\\n' character. The first and August
367        column widths were also set to None.
368    """, styleSheet['BodyText']))
369    lst_add(t)
370
371    lst_add(Paragraph("""
372        This demonstrates a number of features useful in financial statements. The first is decimal alignment;
373        with ALIGN=DECIMAL the numbers align on the points; and the points are aligned based on
374        the RIGHTPADDING, which is usually 3 points so you should set it higher.  The second is multiple lines;
375        one can specify double or triple lines and control the separation if desired. Finally, the coloured
376        negative numbers were (we regret to say) done in the style; we don't have a way to conditionally
377        format numbers based on value yet.
378    """, styleSheet['BodyText']))
379
380
381    t = Table([['Corporate Assets','Amount'],
382               ['Fixed Assets','1,234,567.89'],
383               ['Company Vehicle','1,234.8901'],
384               ['Petty Cash','42'],
385               [u'Intellectual Property\u00ae','(42,078,231.56)'],
386               ['Overdraft','(12,345)'],
387               ['Boardroom Flat Screen','60 inches'],
388               ['Net Position','Deep Sh*t.Really']
389               ],
390              [144,72])
391
392    ts = TableStyle(
393        [#first the top row
394         ('ALIGN', (1,1), (-1,-1), 'CENTER'),
395         ('LINEABOVE', (0,0), (-1,0), 1, colors.purple),
396         ('LINEBELOW', (0,0), (-1,0), 1, colors.purple),
397         ('FONT', (0,0), (-1,0), 'Times-Bold'),
398
399        #bottom row has a line above, and two lines below
400         ('LINEABOVE', (0,-1), (-1,-1), 1, colors.purple),  #last 2 are count, sep
401         ('LINEBELOW', (0,-1), (-1,-1), 0.5, colors.purple, 1, None, None, 4,1),
402         ('LINEBELOW', (0,-1), (-1,-1), 1, colors.red),
403         ('FONT', (0,-1), (-1,-1), 'Times-Bold'),
404
405        #numbers column
406         ('ALIGN', (1,1), (-1,-1), 'DECIMAL'),
407         ('RIGHTPADDING', (1,1), (-1,-1), 36),
408         ('TEXTCOLOR', (1,4), (1,4), colors.red),
409
410        #red cell
411        ]
412        )
413
414    t.setStyle(ts)
415    lst_add(t)
416    lst_add(Spacer(36,36))
417    lst_add(Paragraph("""
418        The red numbers should be aligned LEFT & BOTTOM, the blue RIGHT & TOP
419        and the green CENTER & MIDDLE.
420    """, styleSheet['BodyText']))
421    XY  =   [['X00y', 'X01y', 'X02y', 'X03y', 'X04y'],
422            ['X10y', 'X11y', 'X12y', 'X13y', 'X14y'],
423            ['X20y', 'X21y', 'X22y', 'X23y', 'X24y'],
424            ['X30y', 'X31y', 'X32y', 'X33y', 'X34y']]
425    t=Table(XY, 5*[0.6*inch], 4*[0.6*inch])
426    t.setStyle([('ALIGN',(1,1),(-2,-2),'LEFT'),
427                ('TEXTCOLOR',(1,1),(-2,-2),colors.red),
428
429                ('VALIGN',(0,0),(1,-1),'TOP'),
430                ('ALIGN',(0,0),(1,-1),'RIGHT'),
431                ('TEXTCOLOR',(0,0),(1,-1),colors.blue),
432
433                ('ALIGN',(0,-1),(-1,-1),'CENTER'),
434                ('VALIGN',(0,-1),(-1,-1),'MIDDLE'),
435                ('TEXTCOLOR',(0,-1),(-1,-1),colors.green),
436                ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
437                ('BOX', (0,0), (-1,-1), 0.25, colors.black),
438                ])
439    lst_add(t)
440    data = [('alignment', 'align\012alignment'),
441            ('bulletColor', 'bulletcolor\012bcolor'),
442            ('bulletFontName', 'bfont\012bulletfontname'),
443            ('bulletFontSize', 'bfontsize\012bulletfontsize'),
444            ('bulletIndent', 'bindent\012bulletindent'),
445            ('firstLineIndent', 'findent\012firstlineindent'),
446            ('fontName', 'face\012fontname\012font'),
447            ('fontSize', 'size\012fontsize'),
448            ('leading', 'leading'),
449            ('leftIndent', 'leftindent\012lindent'),
450            ('rightIndent', 'rightindent\012rindent'),
451            ('spaceAfter', 'spaceafter\012spacea'),
452            ('spaceBefore', 'spacebefore\012spaceb'),
453            ('textColor', 'fg\012textcolor\012color')]
454    t = Table(data)
455    t.setStyle([
456            ('VALIGN',(0,0),(-1,-1),'TOP'),
457            ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
458            ('BOX', (0,0), (-1,-1), 0.25, colors.black),
459            ])
460    lst_add(t)
461    t = Table([ ('Attribute', 'Synonyms'),
462                ('alignment', 'align, alignment'),
463                ('bulletColor', 'bulletcolor, bcolor'),
464                ('bulletFontName', 'bfont, bulletfontname'),
465                ('bulletFontSize', 'bfontsize, bulletfontsize'),
466                ('bulletIndent', 'bindent, bulletindent'),
467                ('firstLineIndent', 'findent, firstlineindent'),
468                ('fontName', 'face, fontname, font'),
469                ('fontSize', 'size, fontsize'),
470                ('leading', 'leading'),
471                ('leftIndent', 'leftindent, lindent'),
472                ('rightIndent', 'rightindent, rindent'),
473                ('spaceAfter', 'spaceafter, spacea'),
474                ('spaceBefore', 'spacebefore, spaceb'),
475                ('textColor', 'fg, textcolor, color')])
476    t.repeatRows = 1
477    t.setStyle([
478                ('FONT',(0,0),(-1,1),'Times-Bold',10,12),
479                ('FONT',(0,1),(-1,-1),'Courier',8,8),
480                ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
481                ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
482                ('BOX', (0,0), (-1,-1), 0.25, colors.black),
483                ('BACKGROUND', (0, 0), (-1, 0), colors.green),
484                ('BACKGROUND', (0, 1), (-1, -1), colors.pink),
485                ('ALIGN', (0, 0), (-1, 0), 'CENTER'),
486                ('ALIGN', (0, 1), (0, -1), 'LEFT'),
487                ('ALIGN', (-1, 1), (-1, -1), 'RIGHT'),
488                ('FONT', (0, 0), (-1, 0), 'Times-Bold', 12),
489                ('ALIGN', (1, 1), (1, -1), 'CENTER'),
490                ])
491    lst_add(t)
492    lst_add(Table(XY,
493            style=[ ('FONT',(0,0),(-1,-1),'Times-Roman', 5,6),
494                    ('GRID', (0,0), (-1,-1), 0.25, colors.blue),]))
495    lst_add(Table(XY,
496            style=[ ('FONT',(0,0),(-1,-1),'Times-Roman', 10,12),
497                    ('GRID', (0,0), (-1,-1), 0.25, colors.black),]))
498    lst_add(Table(XY,
499            style=[ ('FONT',(0,0),(-1,-1),'Times-Roman', 20,24),
500                    ('GRID', (0,0), (-1,-1), 0.25, colors.red),]))
501    lst_add(PageBreak())
502    data=  [['00', '01', '02', '03', '04'],
503            ['10', '11', '12', '13', '14'],
504            ['20', '21', '22', '23', '24'],
505            ['30', '31', '32', '33', '34']]
506    t=Table(data,style=[
507                    ('GRID',(0,0),(-1,-1),0.5,colors.grey),
508                    ('GRID',(1,1),(-2,-2),1,colors.green),
509                    ('BOX',(0,0),(1,-1),2,colors.red),
510                    ('BOX',(0,0),(-1,-1),2,colors.black),
511                    ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
512                    ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
513                    ('BACKGROUND', (0, 0), (0, 1), colors.pink),
514                    ('BACKGROUND', (1, 1), (1, 2), colors.lavender),
515                    ('BACKGROUND', (2, 2), (2, 3), colors.orange),
516                    ('TEXTCOLOR',(0,-1),(-2,-1),colors.green),
517                    ])
518    lst_add(Paragraph("Illustrating splits: nosplit", styleSheet['BodyText']))
519    lst_add(t)
520    lst_add(Spacer(0,6))
521    lst_add(Paragraph("Illustrating splits: split(4in,30)", styleSheet['BodyText']))
522    for s in t.split(4*inch,30):
523        lst_add(s)
524        lst_add(Spacer(0,6))
525    lst_add(Spacer(0,6))
526    lst_add(Paragraph("Illustrating splits: split(4in,36)", styleSheet['BodyText']))
527    for s in t.split(4*inch,36):
528        lst_add(s)
529        lst_add(Spacer(0,6))
530    lst_add(Paragraph("Illustrating splits: split(4in,56)", styleSheet['BodyText']))
531    lst_add(Spacer(0,6))
532    for s in t.split(4*inch,56):
533        lst_add(s)
534        lst_add(Spacer(0,6))
535
536    lst_add(Paragraph("Illustrating splits: repeated split(4in,30)", styleSheet['BodyText']))
537    lst_add(Spacer(0,6))
538    S = t.split(4*inch,30)
539    s = S.pop(-1)
540    S.extend(s.split(4*inch,30))
541    s = S.pop(-1)
542    S.extend(s.split(4*inch,30))
543
544    for s in S:
545        lst_add(s)
546        lst_add(Spacer(0,6))
547
548    lst_add(PageBreak())
549    data=  [['00', '01', '02', '03', '04'],
550            ['', '11', '12', '13', '14'],
551            ['20', '21', '22', '23', '24'],
552            ['30', '31', '', '33', '34']]
553    sty=[
554                    ('GRID',(0,0),(-1,-1),0.5,colors.grey),
555                    ('GRID',(1,1),(-2,-2),1,colors.green),
556                    ('BOX',(0,0),(1,-1),2,colors.red),
557                    ('BOX',(0,0),(-1,-1),2,colors.black),
558                    ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
559                    ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
560                    ('BACKGROUND', (0, 0), (0, 1), colors.pink),
561                    ('SPAN',(0,0),(0,1)),
562                    ('BACKGROUND', (2, 2), (2, 3), colors.orange),
563                    ('SPAN',(2,2),(2,3)),
564                    ]
565    t=Table(data,style=sty)
566    lst_add(Paragraph("Illustrating splits with spans: nosplit", styleSheet['BodyText']))
567    lst_add(t)
568    lst_add(Spacer(0,6))
569    lst_add(Paragraph("Illustrating splits with spans: split(4in,30)", styleSheet['BodyText']))
570    for s in t.split(4*inch,30):
571        lst_add(s)
572        lst_add(Spacer(0,6))
573    lst_add(Spacer(0,6))
574    lst_add(Paragraph("Illustrating splits with spans: split(4in,36)", styleSheet['BodyText']))
575    for s in t.split(4*inch,36):
576        lst_add(s)
577        lst_add(Spacer(0,6))
578    lst_add(Paragraph("Illustrating splits with spans: split(4in,56)", styleSheet['BodyText']))
579    lst_add(Spacer(0,6))
580    for s in t.split(4*inch,56):
581        lst_add(s)
582        lst_add(Spacer(0,6))
583
584    data=  [['00', '01', '02', '03', '04'],
585            ['', '11', '12', '13', ''],
586            ['20', '21', '22', '23', '24'],
587            ['30', '31', '', '33', ''],
588            ['40', '41', '', '43', '44']]
589    sty=[
590        ('GRID',(0,0),(-1,-1),0.5,colors.grey),
591        ('GRID',(1,1),(-2,-2),1,colors.green),
592        ('BOX',(0,0),(1,-1),2,colors.red),
593        ('BOX',(0,0),(-1,-1),2,colors.black),
594        ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
595        ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
596        ('BACKGROUND', (0, 0), (0, 1), colors.pink),
597        ('SPAN',(0,0),(0,1)),
598        ('BACKGROUND',(-2,1),(-1,1),colors.palegreen),
599        ('SPAN',(-2,1),(-1,1)),
600        ('BACKGROUND',(-2,3),(-1,3),colors.yellow),
601        ('SPAN',(-2,3),(-1,3)),
602        ('BACKGROUND', (2, 3), (2, 4), colors.orange),
603        ('SPAN',(2,3),(2,4)),
604        ]
605
606    t=Table(data,style=sty,repeatRows=2)
607    lst_add(Paragraph("Illustrating splits with spans and repeatRows: nosplit", styleSheet['BodyText']))
608    lst_add(t)
609    lst_add(Spacer(0,6))
610    if  1:
611        lst_add(Paragraph("Illustrating splits with spans and repeatRows: split(4in,30)", styleSheet['BodyText']))
612        for s in t.split(4*inch,30):
613            lst_add(s)
614            lst_add(Spacer(0,6))
615        lst_add(Spacer(0,6))
616        lst_add(Paragraph("Illustrating splits with spans and repeatRows: split(4in,36)", styleSheet['BodyText']))
617        for s in t.split(4*inch,36):
618            lst_add(s)
619            lst_add(Spacer(0,6))
620    lst_add(Paragraph("Illustrating splits with spans and repeatRows: split(4in,56)", styleSheet['BodyText']))
621    lst_add(Spacer(0,6))
622    for s in t.split(4*inch,56):
623        lst_add(s)
624        lst_add(Spacer(0,6))
625
626    lst_add(PageBreak())
627    from reportlab.lib.testutils import testsFolder
628    I = Image(os.path.join(os.path.dirname(testsFolder),'tools','pythonpoint','demos','leftlogo.gif'))
629    I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth
630    I.drawWidth = 1.25*inch
631    #I.drawWidth = 9.25*inch #uncomment to see better messaging
632    P = Paragraph("<para align=center spaceb=3>The <b>ReportLab Left <font color=red>Logo</font></b> Image</para>", styleSheet["BodyText"])
633    B = TableBarChart()
634    BP = Paragraph("<para align=center spaceb=3>A bar chart in a cell.</para>", styleSheet["BodyText"])
635
636    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'],
637            ['00', '01', '02', [I,P], '04'],
638            ['10', '11', '12', [I,P], '14'],
639            ['20', '21', '22', '23', '24'],
640            ['30', '31', '32', '33', '34'],
641            ['40', '41', '42', [B,BP], '44']]
642
643    t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
644                    ('BOX',(0,0),(1,-1),2,colors.red),
645                    ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
646                    ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
647                    ('BACKGROUND', (0, 0), (0, 1), colors.pink),
648                    ('BACKGROUND', (1, 1), (1, 2), colors.lavender),
649                    ('BACKGROUND', (2, 2), (2, 3), colors.orange),
650                    ('BOX',(0,0),(-1,-1),2,colors.black),
651                    ('GRID',(0,0),(-1,-1),0.5,colors.black),
652                    ('VALIGN',(3,0),(3,0),'BOTTOM'),
653                    ('BACKGROUND',(3,0),(3,0),colors.limegreen),
654                    ('BACKGROUND',(3,1),(3,1),colors.khaki),
655                    ('ALIGN',(3,1),(3,1),'CENTER'),
656                    ('BACKGROUND',(3,2),(3,2),colors.beige),
657                    ('ALIGN',(3,2),(3,2),'LEFT'),
658                    ])
659
660    t._argW[3]=1.5*inch
661    lst_add(t)
662
663    # now for an attempt at column spanning.
664    lst_add(PageBreak())
665    data=  [['A', 'BBBBB', 'C', 'D', 'E'],
666            ['00', '01', '02', '03', '04'],
667            ['10', '11', '12', '13', '14'],
668            ['20', '21', '22', '23', '24'],
669            ['30', '31', '32', '33', '34']]
670    sty = [
671            ('ALIGN',(0,0),(-1,-1),'CENTER'),
672            ('VALIGN',(0,0),(-1,-1),'TOP'),
673            ('GRID',(0,0),(-1,-1),1,colors.green),
674            ('BOX',(0,0),(-1,-1),2,colors.red),
675
676            #span 'BBBB' across middle 3 cells in top row
677            ('SPAN',(1,0),(3,0)),
678            #now color the first cell in this range only,
679            #i.e. the one we want to have spanned.  Hopefuly
680            #the range of 3 will come out khaki.
681            ('BACKGROUND',(1,0),(1,0),colors.khaki),
682
683            ('SPAN',(0,2),(-1,2)),
684
685
686            #span 'AAA'down entire left column
687            ('SPAN',(0,0), (0, 1)),
688            ('BACKGROUND',(0,0),(0,0),colors.cyan),
689            ('TEXTCOLOR', (0,'splitfirst'), (-1,'splitfirst'), colors.cyan),
690            ('TEXTCOLOR', (0,'splitlast'), (-1,'splitlast'), colors.red),
691            ('BACKGROUND', (0,'splitlast'), (-1,'splitlast'), colors.pink),
692            ('LINEBELOW', (0,'splitlast'), (-1,'splitlast'), 1, colors.grey,'butt'),
693           ]
694    t=Table(data,style=sty, colWidths = [20] * 5, rowHeights = [20]*5)
695    lst_add(t)
696    lst_add(Spacer(18,18))
697
698    t=Table(data,style=sty, colWidths = [20] * 5, rowHeights = [20]*5)
699    for s in t.split(4*inch,72):
700        lst_add(s)
701        lst_add(Spacer(0,6))
702
703    # now for an attempt at percentage widths
704    lst_add(Spacer(18,18))
705    lst_add(Paragraph("This table has colWidths=5*['14%']!", styleSheet['BodyText']))
706    t=Table(data,style=sty, colWidths = ['14%'] * 5, rowHeights = [20]*5)
707    lst_add(t)
708
709    lst_add(Spacer(18,18))
710    lst_add(Paragraph("This table has colWidths=['14%','10%','19%','22%','*']!", styleSheet['BodyText']))
711    t=Table(data,style=sty, colWidths = ['14%','10%','19%','22%','*'], rowHeights = [20]*5)
712    lst_add(t)
713
714    # Mike's test example
715    lst_add(Spacer(18,18))
716    lst_add(Paragraph('Mike\'s Spanning Example', styleSheet['Heading1']))
717    data=  [[Paragraph('World Domination: The First Five Years', styleSheet['BodyText']), ''],
718            [Paragraph('World <font color="green">Domination</font>: The First Five Years', styleSheet['BodyText']),''],
719            [Paragraph('World Domination: The First Five Years', styleSheet['BodyText']), ''],
720            ]
721    t=Table(data, style=[('SPAN',(0,0),(1,0)),('SPAN',(0,1),(1,1)),('SPAN',(0,2),(1,2)),], colWidths = [3*cm,8*cm], rowHeights = [None]*3)
722    lst_add(t)
723
724    lst_add(Spacer(18,18))
725    lst_add(Paragraph('Mike\'s Non-spanning Example', styleSheet['Heading1']))
726    data=  [[Paragraph('World Domination: The First Five Years', styleSheet['BodyText'])],
727            [Paragraph('World <font color="magenta">Domination</font>: The First Five Years', styleSheet['BodyText'])],
728            [Paragraph('World Domination: The First Five Years', styleSheet['BodyText'])],
729            ]
730    t=Table(data, style=[], colWidths = [11*cm], rowHeights = [None]*3)
731    lst_add(t)
732
733    lst_add(Spacer(18,18))
734    lst_add(Paragraph('xpre example', styleSheet['Heading1']))
735    data=  [    [
736                XPreformatted('Account Details', styleSheet['Heading3']),
737                '', XPreformatted('Client Details', styleSheet['Heading3']),
738                ],  #end of row 0
739            ]
740    t=Table(data, style=[], colWidths = [80,230.0,80], rowHeights = [None]*1)
741    lst_add(t)
742
743    lst_add(PageBreak())
744
745    lst_add(Paragraph('Trying colour cycling in background', styleSheet['Heading1']))
746    lst_add(Paragraph("This should alternate pale blue and uncolored by row", styleSheet['BodyText']))
747    data=  [['001', '01', '02', '03', '04', '05'],
748            ['002', '01', '02', '03', '04', '05'],
749            ['003', '01', '02', '03', '04', '05'],
750            ['004', '01', '02', '03', '04', '05'],
751            ['005', '01', '02', '03', '04', '05'],
752            ['006', '01', '02', '03', '04', '05'],
753            ['007', '01', '02', '03', '04', '05'],
754            ['008', '01', '02', '03', '04', '05'],
755            ['009', '01', '02', '03', '04', '05'],
756            ['010', '01', '02', '03', '04', '05'],
757
758            ]
759    t=Table(data,style=[
760                    ('GRID',(0,0),(-1,-1),0.5,colors.grey),
761                    ('ROWBACKGROUNDS', (0, 0), (-1, -1), (0xD0D0FF, None)),
762                    ])
763    lst_add(t)
764    lst_add(Spacer(0,6))
765    lst_add(Paragraph("And this should pale blue, pale pink and None by column", styleSheet['BodyText']))
766    t=Table(data,style=[
767                    ('GRID',(0,0),(-1,-1),0.5,colors.grey),
768                    ('COLBACKGROUNDS', (0, 0), (-1, -1), (0xD0D0FF, 0xFFD0D0, None)),
769                    ])
770    lst_add(t)
771
772    lst_add(PageBreak())
773    lst_add(Paragraph("This spanning example illustrates automatic removal of grids and lines in spanned cells!", styleSheet['BodyText']))
774    lst_add(Spacer(0,6))
775    data=  [['Top\nLeft', '', '02', '03', '04', '05', '06', '07'],
776            ['', '', '12', 'Span (3,1) (6,2)', '','','','17'],
777            ['20', '21', '22', '', '','','','27'],
778            ['30', '31', '32', '33', '34','35','36','37'],
779            ['40', 'In The\nMiddle', '', '', '44','45','46','47'],
780            ['50', '', '', '', '54','55','56','57'],
781            ['60', '', '', '','64', '65', 'Bottom\nRight', ''],
782            ['70', '71', '72', '73','74', '75', '', '']]
783    t=Table(data,style=[
784            ('GRID',(0,0),(-1,-1),0.5,colors.grey),
785            ('BACKGROUND',(0,0),(1,1),colors.palegreen),
786            ('SPAN',(0,0),(1,1)),
787            ('BACKGROUND',(-2,-2),(-1,-1), colors.pink),
788            ('SPAN',(-2,-2),(-1,-1)),
789            ('SPAN',(1,4),(3,6)),
790            ('BACKGROUND',(1,4),(3,6), colors.lightblue),
791            ('SPAN',(3,1),(6,2)),
792            ('BACKGROUND',(3,1),(6,2), colors.peachpuff),
793            ('VALIGN',(3,1),(6,2),'TOP'),
794            ('LINEABOVE', (0,2),(-1,2), 1, colors.black, 0, None, None, 2, 2),
795            ('LINEBEFORE', (3,0),(3,-1), 1, colors.black, 0, None, None, 2, 2),
796            ])
797    lst_add(t)
798
799    lst_add(PageBreak())
800
801    lst_add(Paragraph("und jetzt noch eine Tabelle mit 5000 Zeilen:", styleSheet['BodyText']))
802    sty = [ ('GRID',(0,0),(-1,-1),1,colors.green),
803            ('BOX',(0,0),(-1,-1),2,colors.red),
804           ]
805    data = [[str(i), Paragraph("xx "* (i%10), styleSheet["BodyText"]), Paragraph("blah "*(i%40), styleSheet["BodyText"])] for i in range(500)]
806    t=LongTable(data, style=sty, colWidths = [50,100,200])
807    lst_add(t)
808
809    #Yuan Hong's bug tester
810    lst_add(PageBreak())
811    lst_add(Paragraph('Yian Hong\'s Bug Case (should not blow up)', styleSheet['Heading2']))
812    data = ([['Col1', 'Col2', 'Col3', 'Col4', 'Col5']]+
813                [['01', Paragraph('This is cell one that contains a paragraph.', styleSheet['Normal']), '02', '03', '04']
814                    for i in range(50)])
815
816    t = Table(data, ['20%']*5, repeatRows=1)
817    t.setStyle(TableStyle([
818        ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
819        ('BOX', (0,0), (-1,-1), 0.25, colors.black),
820        ('SPAN', (0,50), (-2,50)),
821        ]))
822
823    lst_add(t)
824    lst_add(PageBreak())
825
826    #Volker Haas' example extended
827    #the optimal row heights are the solution of an LP similar to
828    #
829    #Objective function
830    #   min: 3*h0+3*h1+3*h2+2*h3;
831    #
832    #constraints
833    #   h0>=12;
834    #   h1>=12;
835    #   h2>=12;
836    #   h3>=12;
837    #   h0+h1+h2>=48;
838    #   h0+h1>=12;
839    #   h2+h3>=60;
840    #
841    #the solution H=[12,12,24,36]
842    def makeTable(x,y):
843        return Table([
844                ['00', '01', '02', '03', '04', '05\nline2\nline3\nline4'],
845                ['', '11', '12', x, '',''],
846                ['20', '21', y, '23', '24',''],
847                ['30', '31', '', '33', '34','35'],
848                ],
849                style=[
850                    ('TOPPADDING',(0,0),(-1,-1),0),
851                    ('BOTTOMPADDING',(0,0),(-1,-1),0),
852                    ('RIGHTPADDING',(0,0),(-1,-1),0),
853                    ('LEFTPADDING',(0,0),(-1,-1),0),
854                    ('GRID',(0,0),(-1,-1),0.5,colors.grey),
855                    ('BACKGROUND', (0, 0), (0, 1), colors.pink),
856                    ('SPAN',(0,0),(0,1)),
857                    ('BACKGROUND', (2, 2), (2, 3), colors.orange),
858                    ('SPAN',(2,2),(2,3)),
859                    ('SPAN',(3,1),(4,1)),
860                    ('SPAN',(5,0),(5,2)),
861                ])
862    p_style= ParagraphStyle('Normal')
863    lst_add(makeTable(
864            Paragraph('This is a string',p_style),
865            Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs', p_style)
866            ))
867
868    lst_add(Spacer(10,10))
869    lst_add(makeTable(
870            XPreformatted('This is a string',p_style),
871            Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs', p_style)
872            ))
873    lst_add(Spacer(10,10))
874    lst_add(makeTable(
875            'This is a string',
876            '22\nblub\nasfd\nafd\nasdfs',
877            ))
878    lst_add(Spacer(10,10))
879    lst_add(makeTable(
880            'This is a string',
881            Paragraph('22<br/>blub<br/>asfd<br/>afd<br/>asdfs', p_style)
882            ))
883    SimpleDocTemplate(outputfile('test_platypus_tables_2.pdf'), showBoundary=1).build(lst)
884
885class TablesTestCase(unittest.TestCase):
886    "Make documents with tables"
887
888    def test0(self):
889        "Make a document full of tables 0"
890        run()
891
892    def test1(self):
893        "Make a document full of tables 1"
894        old_tables_test()
895
896    def test2(self):
897        '''buggy table example from Lele Gaifax https://bitbucket.org/lele/
898        should split to two pages with the blue box on page 1 complete
899        '''
900        from reportlab.lib.pagesizes import A4, landscape
901
902        data = [
903            ['Date', '08 AM', '', '', '', '09 AM', '', '', '', '10 AM', '', '', '', '11 AM', '', '', '', '12 PM', '', '', '', '01 PM', '', '', '', '02 PM', '', '', '', '03 PM', '', '', '', '04 PM', '', '', '', '05 PM', '', '', '', '06 PM', '', '', '', '07 PM', '', '', '', '08 PM', '', '', '', '09 PM', '', '', '', '10 PM', '', '', '', '11 PM', '', '', ''],
904            ['04-30-2015', '', '', '', '', '09:00 AM\n:\n01:00 PM\nSupervision\nReception', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
905            ['05-01-2015', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '01:00 PM\n:\n04:00 PM\nSupervision\nInfo point 1', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
906            ['05-03-2015', '', '', '', '', '09:00 AM\n:\n01:00 PM\nSupervision\nReception', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
907            ['05-04-2015', '', '', '', '', '', '', '', '', '10:00 AM\n:\n01:00 PM\nSupervision\nInfo point 2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '03:00 PM\n:\n05:30 PM\nSupervision\nInfo point 3', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
908            ['05-05-2015', '', '', '', '', '09:00 AM\n:\n01:00 PM\nSupervision\nReception', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
909            ['05-08-2015', '', '', '', '', '', '', '', '', '10:00 AM\n:\n01:00 PM\nSupervision\nInfo point 2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '02:30 PM\n:\n05:30 PM\nSupervision\nInfo point 3', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
910            ['05-10-2015', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '04:00 PM\n:\n08:00 PM\nSupervision\nInfo point 2', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''],
911         ]
912
913        style = [
914            ('SPAN', (1, 0), (4, 0)),
915            ('SPAN', (5, 0), (8, 0)),
916            ('SPAN', (9, 0), (12, 0)),
917            ('SPAN', (13, 0), (16, 0)),
918            ('SPAN', (17, 0), (20, 0)),
919            ('SPAN', (21, 0), (24, 0)),
920            ('SPAN', (25, 0), (28, 0)),
921            ('SPAN', (29, 0), (32, 0)),
922            ('SPAN', (33, 0), (36, 0)),
923            ('SPAN', (37, 0), (40, 0)),
924            ('SPAN', (41, 0), (44, 0)),
925            ('SPAN', (45, 0), (48, 0)),
926            ('SPAN', (49, 0), (52, 0)),
927            ('SPAN', (53, 0), (56, 0)),
928            ('SPAN', (57, 0), (60, 0)),
929            ('SPAN', (61, 0), (64, 0)),
930            ('SPAN', (1, -1), (4, -1)),
931            ('SPAN', (5, -1), (8, -1)),
932            ('SPAN', (9, -1), (12, -1)),
933            ('SPAN', (13, -1), (16, -1)),
934            ('SPAN', (17, -1), (20, -1)),
935            ('SPAN', (21, -1), (24, -1)),
936            ('SPAN', (25, -1), (28, -1)),
937            ('SPAN', (29, -1), (32, -1)),
938            ('SPAN', (33, -1), (36, -1)),
939            ('SPAN', (37, -1), (40, -1)),
940            ('SPAN', (41, -1), (44, -1)),
941            ('SPAN', (45, -1), (48, -1)),
942            ('SPAN', (49, -1), (52, -1)),
943            ('SPAN', (53, -1), (56, -1)),
944            ('SPAN', (57, -1), (60, -1)),
945            ('SPAN', (61, -1), (64, -1)),
946            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
947            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
948            ('SIZE', (0, 1), (0, -1), 8),
949            ('SIZE', (1, 1), (-1, -1), 6),
950            ('BOX', (5, 1), (20, 1), 1, colors.black), ('SPAN', (5, 1), (20, 1)),
951            ('BOX', (21, 2), (32, 2), 1, colors.black), ('SPAN', (21, 2), (32, 2)),
952            ('BOX', (5, 3), (20, 3), 1, colors.black), ('SPAN', (5, 3), (20, 3)),
953            ('BOX', (9, 4), (20, 4), 1, colors.black), ('SPAN', (9, 4), (20, 4)),
954            ('BOX', (29, 4), (38, 4), 1, colors.black), ('SPAN', (29, 4), (38, 4)),
955            ('BOX', (5, 5), (20, 5), 1, colors.green), ('SPAN', (5, 5), (20, 5)),
956            ('BOX', (9, 6), (20, 6), 1, colors.red), ('SPAN', (9, 6), (20, 6)),
957            ('BOX', (27, 6), (38, 6), 1, colors.blue),('SPAN', (27, 6), (38, 6)),
958            ('BOX', (33, 7), (48, 7), 1, colors.black),('SPAN', (33, 7), (48, 7)),
959            ]
960        t = Table(data, colWidths=None, rowHeights=None, style=style, repeatRows=1)
961        doc = SimpleDocTemplate(outputfile('test_platypus_tables_issue74.pdf'), showBoundary=0, pagesize=landscape(A4))
962        doc.build([t])
963
964    data34 = [
965            ['001', '01', '02', '03', '04', '05'],
966            ['002', '01', '02', '03', '04', '05'],
967            ['003', '01', '02', '03', '04', '05'],
968            ['004', '01', '02', '03', '04', '05'],
969            ['005', '01', '02', '03', '04', '05'],
970            ['006', '01', '02', '03', '04', '05'],
971            ['007', '01', '02', '03', '04', '05'],
972            ['008', '01', '02', '03', '04', '05'],
973            ['009', '01', '02', '03', '04', '05'],
974            ['010', '01', '02', '03', '04', '05'],
975            ['011', '01', '02', '03', '04', '05'],
976            ['012', '01', '02', '03', '04', '05'],
977            ]
978    def test3(self):
979        '''bug reported by David VanEe <david.vanee@convergent.ca>'''
980        story = []
981        story_add = story.append
982        ts_tables = [
983                 ('BACKGROUND',(0,0),(-1,0),colors.pink),
984                 ('BACKGROUND',(0,1),(-1,1),colors.lightblue),
985                 ('BACKGROUND',(0,3),(-1,3),colors.grey),
986                 ('TEXTCOLOR',(0,0),(-1,0),colors.green),
987                 ('TEXTCOLOR',(0,1),(-1,1),colors.red),
988                 ('LINEABOVE', (0,0), (-1,0), 1, colors.purple),
989                 ('LINEBELOW', (0,0), (-1,0), 2, colors.purple),
990                 ('LINEABOVE', (0,1), (-1,1), 1, colors.orange),
991                 ('LINEBELOW', (0,1), (-1,1), 2, colors.orange),
992                 ('FONT', (2,2), (5,8), 'Times-Bold'),
993                 ]
994        data = self.data34
995        from reportlab.platypus import Paragraph, Table, SimpleDocTemplate, PageBreak
996        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
997        styleSheet = getSampleStyleSheet()
998        bodyText = styleSheet['BodyText']
999
1000        story_add(Paragraph('The whole table',bodyText))
1001        t = Table(data, style=ts_tables, repeatRows=(1,3))
1002        story_add(t)
1003        t = Table(data, style=ts_tables, repeatRows=(1,3))
1004        T = t.split(4*72,90)
1005        story_add(Paragraph('The split table part 0',bodyText))
1006        story_add(T[0])
1007        story_add(Paragraph('The split table part 1',bodyText))
1008        story_add(T[1])
1009        self.assertIn(('BACKGROUND', (0, 0), (-1, 0), colors.lightblue),T[1]._bkgrndcmds)
1010        self.assertIn(('BACKGROUND', (0, 1), (-1, 1), colors.grey),T[1]._bkgrndcmds)
1011        self.assertEqual(len(T[1]._bkgrndcmds),2)
1012
1013        # do the same again with repeatRows=1
1014        story_add(PageBreak())
1015        story_add(Paragraph('The whole table repeatRows=1',bodyText))
1016        t = Table(data, style=ts_tables, repeatRows=1)
1017        story_add(t)
1018        t = Table(data, style=ts_tables, repeatRows=1)
1019        T = t.split(4*72,60)
1020        story_add(Paragraph('The split table (repeatRows=1) part 0',bodyText))
1021        story_add(T[0])
1022        story_add(Paragraph('The split table (repeatRows=1) part 1',bodyText))
1023        story_add(T[1])
1024        self.assertIn(('BACKGROUND', (0, 0), (-1, 0), colors.pink),  T[1]._bkgrndcmds)
1025        self.assertIn(('BACKGROUND', (0, 1), (-1, 1), colors.grey), T[1]._bkgrndcmds)
1026        self.assertEqual(len(T[1]._bkgrndcmds),2)
1027        doc = SimpleDocTemplate(outputfile('test_platypus_tables_repeatrows_bgsplit.pdf'), showBoundary=0)
1028        doc.build(story)
1029
1030    def test4(self):
1031        '''test splitting row colour cycles'''
1032        story = []
1033        story_add = story.append
1034        ts_tables = [
1035                 ('BACKGROUND',(0,0),(-1,0),colors.pink),
1036                 ('BACKGROUND',(0,1),(-1,1),colors.lightblue),
1037                 ('ROWBACKGROUNDS',(0,2),(-1,-1),(colors.lightgrey,None)),
1038                 ('TEXTCOLOR',(0,0),(-1,0),colors.green),
1039                 ('TEXTCOLOR',(0,1),(-1,1),colors.red),
1040                 ('LINEABOVE', (0,0), (-1,0), 1, colors.purple),
1041                 ('LINEBELOW', (0,0), (-1,0), 2, colors.purple),
1042                 ('LINEABOVE', (0,1), (-1,1), 1, colors.orange),
1043                 ('LINEBELOW', (0,1), (-1,1), 2, colors.orange),
1044                 ('FONT', (2,2), (5,8), 'Times-Bold'),
1045                 ]
1046        data = self.data34
1047        from reportlab.platypus import Paragraph, Table, SimpleDocTemplate, PageBreak
1048        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
1049        styleSheet = getSampleStyleSheet()
1050        bodyText = styleSheet['BodyText']
1051
1052        story_add(Paragraph('The whole table',bodyText))
1053        t = Table(data, style=ts_tables, repeatRows=2)
1054        story_add(t)
1055        t = Table(data, style=ts_tables, repeatRows=2)
1056        T = t.split(4*72,90)
1057        story_add(Paragraph('The split table part 0',bodyText))
1058        story_add(T[0])
1059        story_add(Paragraph('The split table part 1',bodyText))
1060        story_add(T[1])
1061        self.assertIn(('BACKGROUND', (0, 0), (-1, 0), colors.pink),T[1]._bkgrndcmds)
1062        self.assertIn(('BACKGROUND', (0, 1), (-1, 1), colors.lightblue),T[1]._bkgrndcmds)
1063        self.assertIn(('ROWBACKGROUNDS', (0, 2), (-1, 8), (colors.lightgrey,None)),T[1]._bkgrndcmds)
1064        self.assertEqual(len(T[1]._bkgrndcmds),3)
1065        doc = SimpleDocTemplate(outputfile('test_platypus_tables_repeatrows_bgsplit_1.pdf'), showBoundary=0)
1066        self.assertEqual(len(T[1]._bkgrndcmds),3)
1067        doc.build(story)
1068
1069    def test5(self):
1070        '''test rounded corners'''
1071        story = []
1072        story_add = story.append
1073        ts_tables = [
1074                 ('BACKGROUND',(0,0),(-1,0),colors.pink),
1075                 ('BACKGROUND',(0,1),(-1,1),colors.lightblue),
1076                 ('ROWBACKGROUNDS',(0,2),(-1,-1),(colors.lightgrey,None)),
1077                 ('TEXTCOLOR',(0,0),(-1,0),colors.green),
1078                 ('TEXTCOLOR',(0,1),(-1,1),colors.red),
1079                 ('LINEABOVE', (0,0), (-1,0), 1, colors.purple),
1080                 ('LINEBELOW', (0,0), (-1,0), 2, colors.purple),
1081                 ('LINEABOVE', (0,1), (-1,1), 1, colors.orange),
1082                 ('LINEBELOW', (0,1), (-1,1), 2, colors.orange),
1083                 ('LINEBEFORE', (0,0), (0,-1), 1, colors.red),
1084                 ('LINEAFTER', (-1,0), (-1,-1), 1, colors.blue),
1085                 ('LINEBELOW', (0,-1), (-1,-1), 1, colors.green),
1086                 ('FONT', (2,2), (5,8), 'Times-Bold'),
1087                 ]
1088        data = self.data34
1089        from reportlab.platypus import Paragraph, Table, SimpleDocTemplate, PageBreak
1090        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
1091        styleSheet = getSampleStyleSheet()
1092        bodyText = styleSheet['BodyText']
1093
1094        story_add(Paragraph('The whole table',bodyText))
1095        t = Table(data[:], style=ts_tables, repeatRows=2, cornerRadii=[5,6,4,3])
1096        story_add(t)
1097        t = Table(data[:], style=ts_tables, repeatRows=2, cornerRadii=[5,6,4,5])
1098        T = t.split(4*72,90)
1099        story_add(Paragraph('The split table part 0',bodyText))
1100        story_add(T[0])
1101        story_add(Paragraph('The split table part 1',bodyText))
1102        story_add(T[1])
1103        story_add(PageBreak())
1104        ts2 = ts_tables+[('ROUNDEDCORNERS',[5,6,4,3])]
1105        story_add(Paragraph('Rounded corners via style',bodyText))
1106        t = Table(data[:], style=ts2, repeatRows=2)
1107        story_add(t)
1108        t = Table(data[:], style=ts2, repeatRows=2)
1109        T = t.split(4*72,90)
1110        story_add(Paragraph('The split table part 0',bodyText))
1111        story_add(T[0])
1112        story_add(Paragraph('The split table part 1',bodyText))
1113        story_add(T[1])
1114        story_add(PageBreak())
1115        story_add(Paragraph('Rounded corners via style overridden by instance argument',bodyText))
1116        t = Table(data[:], style=ts2, repeatRows=2, cornerRadii=(0,3,5,0))
1117        story_add(t)
1118        t = Table(data[:], style=ts2, repeatRows=2, cornerRadii=t._cornerRadii)
1119        T = t.split(4*72,90)
1120        story_add(Paragraph('The split table part 0',bodyText))
1121        story_add(T[0])
1122        story_add(Paragraph('The split table part 1',bodyText))
1123        story_add(T[1])
1124        story_add(Paragraph('Rounded corners double linebelow',bodyText))
1125        ts3 = ts_tables[:]
1126        ts3.remove(('LINEBELOW', (0,-1), (-1,-1), 1, colors.green))
1127        ts3.append(('LINEBELOW', (0,-1), (-1,-1), 1, colors.green, 1, None, None, 3,1))
1128        t = Table(data[:], style=ts3, repeatRows=2, cornerRadii=[0,0,6,7])#[4,5,6,7])
1129        story_add(t)
1130        doc = SimpleDocTemplate(outputfile('test_platypus_tables_rounded_corners.pdf'), showBoundary=0)
1131        doc.build(story)
1132        assert(T[0]._cornerRadii==[0,3,0,0])
1133        assert(T[1]._cornerRadii==[0,3,5,0])
1134
1135def makeSuite():
1136    return makeSuiteForClasses(TablesTestCase)
1137
1138
1139#noruntests
1140if __name__ == "__main__":
1141    unittest.TextTestRunner().run(makeSuite())
1142    printLocation()
1143