"Fossies" - the Fresh Open Source Software Archive

Member "reportlab-3.5.32/docs/userguide/ch6_tables.py" (1 Oct 2019, 33746 Bytes) of package /linux/privat/reportlab-3.5.32.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "ch6_tables.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.5.26_vs_3.5.28.

    1 #Copyright ReportLab Europe Ltd. 2000-2017
    2 #see license.txt for license details
    3 #history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch6_tables.py
    4 from tools.docco.rl_doc_utils import *
    5 from reportlab.platypus import Image,ListFlowable, ListItem
    6 import reportlab
    7 
    8 heading1("Tables and TableStyles")
    9 disc("""
   10 The $Table$  and $LongTable$ classes derive from the $Flowable$ class and are intended
   11 as a simple textual gridding mechanisms. The $longTable$ class uses a greedy algorithm
   12 when calculating column widths and is intended for long tables where speed counts.
   13 $Table$ cells can hold anything which can be converted to
   14 a <b>Python</b> $string$ or $Flowables$ (or lists of $Flowables$).
   15 """)
   16 
   17 disc("""
   18 Our present tables are a trade-off between efficient drawing and specification
   19 and functionality.  We assume the reader has some familiarity with HTML tables.
   20 In brief, they have the following characteristics:
   21 """)
   22 
   23 bullet("""They can contain anything convertible to a string; flowable
   24 objects such as other tables; or entire sub-stories""")
   25 
   26 bullet("""They can work out the row heights to fit the data if you don't supply
   27 the row height.  (They can also work out the widths, but generally it is better
   28 for a designer to set the width manually, and it draws faster).""")
   29 
   30 bullet("""They can split across pages if needed (see the canSplit attribute).
   31 You can specify that a number of rows at the top and bottom should be
   32 repeated after the split (e.g. show the headers again on page 2,3,4...)""")
   33 
   34 bullet("""They have a simple and powerful notation for specifying shading and
   35 gridlines which works well with financial or database tables, where you
   36 don't know the number of rows up front.  You can easily say 'make the last row
   37 bold and put a line above it'""")
   38 
   39 bullet("""The style and data are separated, so you can declare a handful of table
   40 styles and use them for a family of reports.  Styes can also 'inherit', as with
   41 paragraphs.""")
   42 
   43 disc("""There is however one main limitation compared to an HTML table.
   44 They define a simple rectangular grid.  There is no simple row or column
   45 spanning; if you need to span cells, you must nest tables inside table cells instead or use a more
   46 complex scheme in which the lead cell of a span contains the actual contents.""")
   47 
   48 disc("""
   49 $Tables$ are created by passing the constructor an optional sequence of column widths,
   50 an optional sequence of row heights, and the data in row order.
   51 Drawing of the table can be controlled by using a $TableStyle$ instance. This allows control of the
   52 color and weight of the lines (if any), and the font, alignment and padding of the text.
   53 A primitive automatic row height and or column width calculation mechanism is provided for.
   54 """)
   55 
   56 heading2('$Table$ User Methods')
   57 disc("""These are the main methods which are of interest to the client programmer.""")
   58 
   59 heading4("""$Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,
   60 repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None, spaceAfter=None)$""")
   61 
   62 disc("""The $data$ argument is a sequence of sequences of cell values each of which
   63 should be convertible to a string value using the $str$ function or should be a Flowable instance (such as a $Paragraph$) or a list (or tuple) of such instances.
   64 If a cell value is a $Flowable$ or list of $Flowables$ these must either have a determined width
   65 or the containing column must have a fixed width.
   66 The first row of cell values
   67 is in $data[0]$ i.e. the values are in row order. The $i$, $j$<sup>th.</sup> cell value is in
   68 $data[i][j]$. Newline characters $'\\n'$ in cell values are treated as line split characters and
   69 are used at <i>draw</i> time to format the cell into lines.
   70 """)
   71 disc("""The other arguments are fairly obvious, the $colWidths$ argument is a sequence
   72 of numbers or possibly $None$, representing the widths of the columns. The number of elements
   73 in $colWidths$ determines the number of columns in the table.
   74 A value of $None$ means that the corresponding column width should be calculated automatically.""")
   75 
   76 disc("""The $rowHeights$ argument is a sequence
   77 of numbers or possibly $None$, representing the heights of the rows. The number of elements
   78 in $rowHeights$ determines the number of rows in the table.
   79 A value of $None$ means that the corresponding row height should be calculated automatically.""")
   80 
   81 disc("""The $style$ argument can be an initial style for the table.""")
   82 disc("""The $splitByRow$ argument is only needed for tables both too tall and too wide
   83 to fit in the current context.  In this case you must decide whether to 'tile'
   84 down and across, or across and then down.  This parameter is a Boolean indicating that the
   85 $Table$ should split itself
   86 by row before attempting to split itself by column when too little space is available in
   87 the current drawing area and the caller wants the $Table$ to split.
   88 Splitting a $Table$ by column is currently not implemented, so setting $splitByRow$ to $False$ will result in a $NotImplementedError$.""")
   89 
   90 disc("""The $repeatRows$ argument specifies the number or a tuple of leading rows
   91 that should be repeated when the $Table$ is asked to split itself. If it is a tuple it should specify which of the leading rows should be repeated; this allows
   92 for cases where the first appearance of the table hsa more leading rows than later split parts.
   93 The $repeatCols$ argument is currently ignored as a $Table$ cannot be split by column.""")
   94 disc("""The $spaceBefore$ &amp; $spaceAfter$ arguments may be used to put extra space before or after the table when renedered in a $platypus$ story.""")
   95 disc("""The $rowSplitRange$ argument may be used to control the splitting of the table to a subset of its rows; that can be to prevent splitting too close to the beginning or end of the table.""")
   96 heading4('$Table.setStyle(tblStyle)$')
   97 disc("""
   98 This method applies a particular instance of class $TableStyle$ (discussed below)
   99 to the $Table$ instance. This is the only way to get $tables$ to appear
  100 in a nicely formatted way.
  101 """)
  102 disc("""
  103 Successive uses of the $setStyle$ method apply the styles in an additive fashion.
  104 That is, later applications override earlier ones where they overlap.
  105 """)
  106 
  107 heading2('$TableStyle$')
  108 disc("""
  109 This class is created by passing it a sequence of <i>commands</i>, each command
  110 is a tuple identified by its first element which is a string; the remaining
  111 elements of the command tuple represent the start and stop cell coordinates
  112 of the command and possibly thickness and colors, etc.
  113 """)
  114 heading2("$TableStyle$ User Methods")
  115 heading3("$TableStyle(commandSequence)$")
  116 disc("""The creation method initializes the $TableStyle$ with the argument
  117 command sequence as an example:""")
  118 eg("""
  119     LIST_STYLE = TableStyle(
  120         [('LINEABOVE', (0,0), (-1,0), 2, colors.green),
  121         ('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
  122         ('LINEBELOW', (0,-1), (-1,-1), 2, colors.green),
  123         ('ALIGN', (1,1), (-1,-1), 'RIGHT')]
  124         )
  125 """)
  126 heading3("$TableStyle.add(commandSequence)$")
  127 disc("""This method allows you to add commands to an existing
  128 $TableStyle$, i.e. you can build up $TableStyles$ in multiple statements.
  129 """)
  130 eg("""
  131     LIST_STYLE.add('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))
  132 """)
  133 heading3("$TableStyle.getCommands()$")
  134 disc("""This method returns the sequence of commands of the instance.""")
  135 eg("""
  136     cmds = LIST_STYLE.getCommands()
  137 """)
  138 heading2("$TableStyle$ Commands")
  139 disc("""The commands passed to $TableStyles$ come in three main groups
  140 which affect the table background, draw lines, or set cell styles.
  141 """)
  142 disc("""The first element of each command is its identifier,
  143 the second and third arguments determine the cell coordinates of
  144 the box of cells which are affected with negative coordinates
  145 counting backwards from the limit values as in <b>Python</b>
  146 indexing. The coordinates are given as
  147 (column, row) which follows the spreadsheet 'A1' model, but not
  148 the more natural (for mathematicians) 'RC' ordering.
  149 The top left cell is (0, 0) the bottom right is (-1, -1). Depending on
  150 the command various extra (???) occur at indices beginning at 3 on.
  151 """)
  152 heading3("""$TableStyle$ Cell Formatting Commands""")
  153 disc("""The cell formatting commands all begin with an identifier, followed by
  154 the start and stop cell definitions and the perhaps other arguments.
  155 the cell formatting commands are:""")
  156 npeg("""
  157 FONT                    - takes fontname, optional fontsize and optional leading.
  158 FONTNAME (or FACE)      - takes fontname.
  159 FONTSIZE (or SIZE)      - takes fontsize in points; leading may get out of sync.
  160 LEADING                 - takes leading in points.
  161 TEXTCOLOR               - takes a color name or (R,G,B) tuple.
  162 ALIGNMENT (or ALIGN)    - takes one of LEFT, RIGHT and CENTRE (or CENTER) or DECIMAL.
  163 LEFTPADDING             - takes an integer, defaults to 6.
  164 RIGHTPADDING            - takes an integer, defaults to 6.
  165 BOTTOMPADDING           - takes an integer, defaults to 3.
  166 TOPPADDING              - takes an integer, defaults to 3.
  167 BACKGROUND              - takes a color defined by an object, string name or numeric tuple/list,
  168                           or takes a list/tuple describing a desired gradient fill which should
  169                           contain three elements of the form [DIRECTION, startColor, endColor]
  170                           where DIRECTION is either VERTICAL or HORIZONTAL.
  171 ROWBACKGROUNDS          - takes a list of colors to be used cyclically.
  172 COLBACKGROUNDS          - takes a list of colors to be used cyclically.
  173 VALIGN                  - takes one of TOP, MIDDLE or the default BOTTOM
  174 """)
  175 disc("""This sets the background cell color in the relevant cells.
  176 The following example shows the $BACKGROUND$, and $TEXTCOLOR$ commands in action:""")
  177 EmbeddedCode("""
  178 data=  [['00', '01', '02', '03', '04'],
  179         ['10', '11', '12', '13', '14'],
  180         ['20', '21', '22', '23', '24'],
  181         ['30', '31', '32', '33', '34']]
  182 t=Table(data)
  183 t.setStyle(TableStyle([('BACKGROUND',(1,1),(-2,-2),colors.green),
  184                         ('TEXTCOLOR',(0,0),(1,-1),colors.red)]))
  185 """)
  186 disc("""To see the effects of the alignment styles we need  some widths
  187 and a grid, but it should be easy to see where the styles come from.""")
  188 EmbeddedCode("""
  189 data=  [['00', '01', '02', '03', '04'],
  190         ['10', '11', '12', '13', '14'],
  191         ['20', '21', '22', '23', '24'],
  192         ['30', '31', '32', '33', '34']]
  193 t=Table(data,5*[0.4*inch], 4*[0.4*inch])
  194 t.setStyle(TableStyle([('ALIGN',(1,1),(-2,-2),'RIGHT'),
  195                         ('TEXTCOLOR',(1,1),(-2,-2),colors.red),
  196                         ('VALIGN',(0,0),(0,-1),'TOP'),
  197                         ('TEXTCOLOR',(0,0),(0,-1),colors.blue),
  198                         ('ALIGN',(0,-1),(-1,-1),'CENTER'),
  199                         ('VALIGN',(0,-1),(-1,-1),'MIDDLE'),
  200                         ('TEXTCOLOR',(0,-1),(-1,-1),colors.green),
  201                         ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
  202                         ('BOX', (0,0), (-1,-1), 0.25, colors.black),
  203                         ]))
  204 """)
  205 heading3("""$TableStyle$ Line Commands""")
  206 disc("""
  207     Line commands begin with the identifier, the start and stop cell coordinates
  208     and always follow this with the thickness (in points) and color of the desired lines. Colors can be names,
  209     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
  210     command names are: GRID, BOX, OUTLINE, INNERGRID, LINEBELOW, LINEABOVE, LINEBEFORE
  211     and LINEAFTER. BOX and OUTLINE are equivalent, and GRID is the equivalent of applying both BOX and
  212     INNERGRID.
  213 """)
  214 CPage(4.0)
  215 disc("""We can see some line commands in action with the following example.
  216 """)
  217 EmbeddedCode("""
  218 data=  [['00', '01', '02', '03', '04'],
  219         ['10', '11', '12', '13', '14'],
  220         ['20', '21', '22', '23', '24'],
  221         ['30', '31', '32', '33', '34']]
  222 t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
  223                     ('BOX',(0,0),(1,-1),2,colors.red),
  224                     ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
  225                     ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
  226                     ])
  227 """)
  228 disc("""Line commands cause problems for tables when they split; the following example
  229 shows a table being split in various positions""")
  230 EmbeddedCode("""
  231 data=  [['00', '01', '02', '03', '04'],
  232         ['10', '11', '12', '13', '14'],
  233         ['20', '21', '22', '23', '24'],
  234         ['30', '31', '32', '33', '34']]
  235 t=Table(data,style=[
  236                 ('GRID',(0,0),(-1,-1),0.5,colors.grey),
  237                 ('GRID',(1,1),(-2,-2),1,colors.green),
  238                 ('BOX',(0,0),(1,-1),2,colors.red),
  239                 ('BOX',(0,0),(-1,-1),2,colors.black),
  240                 ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
  241                 ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
  242                 ('BACKGROUND', (0, 0), (0, 1), colors.pink),
  243                 ('BACKGROUND', (1, 1), (1, 2), colors.lavender),
  244                 ('BACKGROUND', (2, 2), (2, 3), colors.orange),
  245                 ])
  246 """)
  247 t=getStory()[-1]
  248 getStory().append(Spacer(0,6))
  249 for s in t.split(4*inch,30):
  250     getStory().append(s)
  251     getStory().append(Spacer(0,6))
  252 getStory().append(Spacer(0,6))
  253 for s in t.split(4*inch,36):
  254     getStory().append(s)
  255     getStory().append(Spacer(0,6))
  256 
  257 disc("""When unsplit and split at the first or second row.""")
  258 
  259 CPage(4.0)
  260 heading3("""Complex Cell Values""")
  261 disc("""
  262 As mentioned above we can have complicated cell values including $Paragraphs$, $Images$ and other $Flowables$
  263 or lists of the same. To see this in operation consider the following code and the table it produces.
  264 Note that the $Image$ has a white background which will obscure any background you choose for the cell.
  265 To get better results you should use a transparent background.
  266 """)
  267 import os, reportlab.platypus
  268 I = '../images/replogo.gif'
  269 EmbeddedCode("""
  270 I = Image('%s')
  271 I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth
  272 I.drawWidth = 1.25*inch
  273 P0 = Paragraph('''
  274                <b>A pa<font color=red>r</font>a<i>graph</i></b>
  275                <super><font color=yellow>1</font></super>''',
  276                styleSheet["BodyText"])
  277 P = Paragraph('''
  278        <para align=center spaceb=3>The <b>ReportLab Left
  279        <font color=red>Logo</font></b>
  280        Image</para>''',
  281        styleSheet["BodyText"])
  282 data=  [['A',   'B', 'C',     P0, 'D'],
  283         ['00', '01', '02', [I,P], '04'],
  284         ['10', '11', '12', [P,I], '14'],
  285         ['20', '21', '22',  '23', '24'],
  286         ['30', '31', '32',  '33', '34']]
  287 
  288 t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
  289                     ('BOX',(0,0),(1,-1),2,colors.red),
  290                     ('LINEABOVE',(1,2),(-2,2),1,colors.blue),
  291                     ('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
  292                     ('BACKGROUND', (0, 0), (0, 1), colors.pink),
  293                     ('BACKGROUND', (1, 1), (1, 2), colors.lavender),
  294                     ('BACKGROUND', (2, 2), (2, 3), colors.orange),
  295                     ('BOX',(0,0),(-1,-1),2,colors.black),
  296                     ('GRID',(0,0),(-1,-1),0.5,colors.black),
  297                     ('VALIGN',(3,0),(3,0),'BOTTOM'),
  298                     ('BACKGROUND',(3,0),(3,0),colors.limegreen),
  299                     ('BACKGROUND',(3,1),(3,1),colors.khaki),
  300                     ('ALIGN',(3,1),(3,1),'CENTER'),
  301                     ('BACKGROUND',(3,2),(3,2),colors.beige),
  302                     ('ALIGN',(3,2),(3,2),'LEFT'),
  303                     ])
  304 
  305 t._argW[3]=1.5*inch
  306 """%I)
  307 heading3("""$TableStyle$ Span Commands""")
  308 disc("""Our $Table$ classes support the concept of spanning, but it isn't specified in the same way
  309 as html. The style specification
  310 """)
  311 eg("""
  312 SPAN, (sc,sr), (ec,er)
  313 """)
  314 disc("""indicates that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ should be combined into a super cell
  315 with contents determined by the cell $(sc, sr)$. The other cells should be present, but should contain empty strings
  316 or you may get unexpected results.
  317 """)
  318 EmbeddedCode("""
  319 data=  [['Top\\nLeft', '', '02', '03', '04'],
  320         ['', '', '12', '13', '14'],
  321         ['20', '21', '22', 'Bottom\\nRight', ''],
  322         ['30', '31', '32', '', '']]
  323 t=Table(data,style=[
  324                 ('GRID',(0,0),(-1,-1),0.5,colors.grey),
  325                 ('BACKGROUND',(0,0),(1,1),colors.palegreen),
  326                 ('SPAN',(0,0),(1,1)),
  327                 ('BACKGROUND',(-2,-2),(-1,-1), colors.pink),
  328                 ('SPAN',(-2,-2),(-1,-1)),
  329                 ])
  330 """)
  331 
  332 disc("""notice that we don't need to be conservative with our $GRID$ command. The spanned cells are not drawn through.
  333 """)
  334 heading3("""$TableStyle$ Miscellaneous Commands""")
  335 disc("""To control $Table$ splitting the $NOSPLIT$ command may be used
  336 The style specification
  337 """)
  338 eg("""
  339 NOSPLIT, (sc,sr), (ec,er)
  340 """)
  341 disc("""demands that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ may not be split.""")
  342 
  343 heading3("""Special $TableStyle$ Indeces""")
  344 disc("""In any style command the first row index may be set to one of the special strings
  345 $'splitlast'$ or $'splitfirst'$ to indicate that the style should be used only for the last row of
  346 a split table, or the first row of a continuation. This allows splitting tables with nicer effects around the split.""")
  347 
  348 heading1("""Programming $Flowables$""")
  349 
  350 disc("""The following flowables let you conditionally evaluate and execute expressions and statements at wrap time:""")
  351 
  352 heading2("""$DocAssign(self, var, expr, life='forever')$""")
  353 
  354 disc("""Assigns a variable of name $var$ to the expression $expr$. E.g.:""")
  355 
  356 eg("""
  357 DocAssign('i',3)
  358 """)
  359 
  360 heading2("""$DocExec(self, stmt, lifetime='forever')$""")
  361 
  362 disc("""Executes the statement $stmt$. E.g.:""")
  363 
  364 eg("""
  365 DocExec('i-=1')
  366 """)
  367 
  368 heading2("""$DocPara(self, expr, format=None, style=None, klass=None, escape=True)$""")
  369 
  370 disc("""Creates a paragraph with the value of expr as text.
  371 If format is specified it should use %(__expr__)s for string interpolation
  372 of the expression expr (if any). It may also use %(name)s interpolations
  373 for other variables in the namespace. E.g.:""")
  374 
  375 eg("""
  376 DocPara('i',format='The value of i is %(__expr__)d',style=normal)
  377 """)
  378 
  379 heading2("""$DocAssert(self, cond, format=None)$""")
  380 
  381 disc("""Raises an $AssertionError$ containing the $format$ string if $cond$ evaluates as $False$.""")
  382 
  383 eg("""
  384 DocAssert(val, 'val is False')
  385 """)
  386 
  387 heading2("""$DocIf(self, cond, thenBlock, elseBlock=[])$""")
  388 
  389 disc("""If $cond$ evaluates as $True$, this flowable is replaced by the $thenBlock$ elsethe $elseBlock$.""")
  390 
  391 eg("""
  392 DocIf('i>3',Paragraph('The value of i is larger than 3',normal),\\
  393         Paragraph('The value of i is not larger than 3',normal))
  394 """)
  395 
  396 heading2("""$DocWhile(self, cond, whileBlock)$""")
  397 
  398 disc("""Runs the $whileBlock$ while $cond$ evaluates to $True$. E.g.:""")
  399 
  400 eg("""
  401 DocAssign('i',5)
  402 DocWhile('i',[DocPara('i',format='The value of i is %(__expr__)d',style=normal),DocExec('i-=1')])
  403 """)
  404 
  405 disc("""This example produces a set of paragraphs of the form:""")
  406 
  407 eg("""
  408 The value of i is 5
  409 The value of i is 4
  410 The value of i is 3
  411 The value of i is 2
  412 The value of i is 1
  413 """)
  414 
  415 heading1("""Other Useful $Flowables$""")
  416 heading2("""$Preformatted(text, style, bulletText=None, dedent=0, maxLineLength=None, splitChars=None, newLineChars=None)$""")
  417 disc("""
  418 Creates a preformatted paragraph which does no wrapping, line splitting or other manipulations.
  419 No $XML$ style tags are taken account of in the text.
  420 If dedent is non zero $dedent$ common leading
  421 spaces will be removed from the front of each line.
  422 """)
  423 heading3("Defining a maximum line length")
  424 disc("""
  425 You can use the property $maxLineLength$ to define a maximum line length. If a line length exceeds this maximum value, the line will be automatically splitted.
  426 """)
  427 disc("""
  428 The line will be split on any single character defined in $splitChars$. If no value is provided for this property, the line will be split on any of the following standard characters: space, colon, full stop, semi-colon, coma, hyphen, forward slash, back slash, left parenthesis, left square bracket and left curly brace
  429 """)
  430 disc("""
  431 Characters can be automatically inserted at the beginning of each line that has been created. You can set the property $newLineChars$ to the characters you want to use.
  432 """)
  433 EmbeddedCode("""
  434 from reportlab.lib.styles import getSampleStyleSheet
  435 stylesheet=getSampleStyleSheet()
  436 normalStyle = stylesheet['Code']
  437 text='''
  438 class XPreformatted(Paragraph):
  439     def __init__(self, text, style, bulletText = None, frags=None, caseSensitive=1):
  440         self.caseSensitive = caseSensitive
  441         if maximumLineLength and text:
  442             text = self.stopLine(text, maximumLineLength, splitCharacters)
  443         cleaner = lambda text, dedent=dedent: ''.join(_dedenter(text or '',dedent))
  444         self._setup(text, style, bulletText, frags, cleaner)
  445 '''
  446 t=Preformatted(text,normalStyle,maxLineLength=60, newLineChars='> ')
  447 """)
  448 heading2("""$XPreformatted(text, style, bulletText=None, dedent=0, frags=None)$""")
  449 disc("""
  450 This is a non rearranging form of the $Paragraph$ class; XML tags are allowed in
  451 $text$ and have the same meanings as for the $Paragraph$ class.
  452 As for $Preformatted$, if dedent is non zero $dedent$ common leading
  453 spaces will be removed from the front of each line.
  454 """)
  455 EmbeddedCode("""
  456 from reportlab.lib.styles import getSampleStyleSheet
  457 stylesheet=getSampleStyleSheet()
  458 normalStyle = stylesheet['Code']
  459 text='''
  460 
  461    This is a non rearranging form of the <b>Paragraph</b> class;
  462    <b><font color=red>XML</font></b> tags are allowed in <i>text</i> and have the same
  463 
  464       meanings as for the <b>Paragraph</b> class.
  465    As for <b>Preformatted</b>, if dedent is non zero <font color="red" size="+1">dedent</font>
  466        common leading spaces will be removed from the
  467    front of each line.
  468    You can have &amp;amp; style entities as well for &amp; &lt; &gt; and &quot;.
  469 
  470 '''
  471 t=XPreformatted(text,normalStyle,dedent=3)
  472 """)
  473 
  474 heading2("""$Image(filename, width=None, height=None)$""")
  475 disc("""Create a flowable which will contain the image defined by the data in file $filename$ which can be
  476 filepath, file like object or an instance of a $reportlab.graphics.shapes.Drawing$.
  477 The default <b>PDF</b> image type <i>jpeg</i> is supported and if the <b>PIL</b> extension to <b>Python</b>
  478 is installed the other image types can also be handled. If $width$ and or $height$ are specified
  479 then they determine the dimension of the displayed image in <i>points</i>. If either dimension is
  480 not specified (or specified as $None$) then the corresponding pixel dimension of the image is assumed
  481 to be in <i>points</i> and used.
  482 """)
  483 I="../images/lj8100.jpg"
  484 eg("""
  485 Image("lj8100.jpg")
  486 """,after=0.1)
  487 disc("""will display as""")
  488 try:
  489     getStory().append(Image(I))
  490 except:
  491     disc("""An image should have appeared here.""")
  492 disc("""whereas""")
  493 eg("""
  494 im = Image("lj8100.jpg", width=2*inch, height=2*inch)
  495 im.hAlign = 'CENTER'
  496 """, after=0.1)
  497 disc('produces')
  498 try:
  499     im = Image(I, width=2*inch, height=2*inch)
  500     im.hAlign = 'CENTER'
  501     getStory().append(Image(I, width=2*inch, height=2*inch))
  502 except:
  503     disc("""An image should have appeared here.""")
  504 heading2("""$Spacer(width, height)$""")
  505 disc("""This does exactly as would be expected; it adds a certain amount of space into the story.
  506 At present this only works for vertical space.
  507 """)
  508 CPage(1)
  509 heading2("""$PageBreak()$""")
  510 disc("""This $Flowable$ represents a page break. It works by effectively consuming all vertical
  511 space given to it. This is sufficient for a single $Frame$ document, but would only be a
  512 frame break for multiple frames so the $BaseDocTemplate$ mechanism
  513 detects $pageBreaks$ internally and handles them specially.
  514 """)
  515 CPage(1)
  516 heading2("""$CondPageBreak(height)$""")
  517 disc("""This $Flowable$ attempts to force a $Frame$ break if insufficient vertical space remains
  518 in the current $Frame$. It is thus probably wrongly named and should probably be renamed as
  519 $CondFrameBreak$.
  520 """)
  521 CPage(1)
  522 heading2("""$KeepTogether(flowables)$""")
  523 disc("""
  524 This compound $Flowable$ takes a list of $Flowables$ and attempts to keep them in the same $Frame$.
  525 If the total height of the $Flowables$ in the list $flowables$ exceeds the current frame's available
  526 space then all the space is used and a frame break is forced.
  527 """)
  528 CPage(1)
  529 heading2("""$TableOfContents()$""")
  530 disc("""
  531 A table of contents can be generated by using the $TableOfContents$ flowable.
  532 
  533 The following steps are needed to add a table of contents to your document:
  534 """)
  535 
  536 disc("""Create an instance of $TableOfContents$. Override the level styles (optional) and add the object to the story:""")
  537 
  538 eg("""
  539 toc = TableOfContents()
  540 PS = ParagraphStyle
  541 toc.levelStyles = [
  542     PS(fontName='Times-Bold', fontSize=14, name='TOCHeading1',
  543             leftIndent=20, firstLineIndent=-20, spaceBefore=5, leading=16),
  544     PS(fontSize=12, name='TOCHeading2',
  545             leftIndent=40, firstLineIndent=-20, spaceBefore=0, leading=12),
  546     PS(fontSize=10, name='TOCHeading3',
  547             leftIndent=60, firstLineIndent=-20, spaceBefore=0, leading=12),
  548     PS(fontSize=10, name='TOCHeading4',
  549             leftIndent=100, firstLineIndent=-20, spaceBefore=0, leading=12),
  550 ]
  551 story.append(toc)
  552 """)
  553 
  554 disc("""Entries to the table of contents can be done either manually by calling
  555 the $addEntry$ method on the $TableOfContents$ object or automatically by sending
  556 a $'TOCEntry'$ notification in the $afterFlowable$ method of the $DocTemplate$
  557 you are using.
  558 
  559 The data to be passed to $notify$ is a list of three or four items countaining
  560 a level number, the entry text, the page number and an optional destination key
  561 which the entry should point to.
  562 This list will usually be created in a document template's method
  563 like afterFlowable(), making notification calls using the notify()
  564 method with appropriate data like this:
  565 """)
  566 
  567 eg('''
  568 def afterFlowable(self, flowable):
  569     """Detect Level 1 and 2 headings, build outline,
  570     and track chapter title."""
  571     if isinstance(flowable, Paragraph):
  572         txt = flowable.getPlainText()
  573         if style == 'Heading1':
  574             # ...
  575             self.notify('TOCEntry', (0, txt, self.page))
  576         elif style == 'Heading2':
  577             # ...
  578             key = 'h2-%s' % self.seq.nextf('heading2')
  579             self.canv.bookmarkPage(key)
  580             self.notify('TOCEntry', (1, txt, self.page, key))
  581         # ...
  582 ''')
  583 
  584 disc("""This way, whenever a paragraph of style $'Heading1'$ or $'Heading2'$ is added to the story, it will appear in the table of contents.
  585 $Heading2$ entries will be clickable because a bookmarked key has been supplied.
  586 """)
  587 
  588 disc("""Finally you need to use the $multiBuild$ method of the DocTemplate because tables of contents need several passes to be generated:""")
  589 
  590 eg("""
  591 doc.multiBuild(story)
  592 """)
  593 
  594 disc("""Below is a simple but working example of a document with a table of contents:""")
  595 
  596 eg('''
  597 from reportlab.lib.styles import ParagraphStyle as PS
  598 from reportlab.platypus import PageBreak
  599 from reportlab.platypus.paragraph import Paragraph
  600 from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
  601 from reportlab.platypus.tableofcontents import TableOfContents
  602 from reportlab.platypus.frames import Frame
  603 from reportlab.lib.units import cm
  604 
  605 class MyDocTemplate(BaseDocTemplate):
  606 
  607     def __init__(self, filename, **kw):
  608         self.allowSplitting = 0
  609         BaseDocTemplate.__init__(self, filename, **kw)
  610         template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])
  611         self.addPageTemplates(template)
  612 
  613     def afterFlowable(self, flowable):
  614         "Registers TOC entries."
  615         if flowable.__class__.__name__ == 'Paragraph':
  616             text = flowable.getPlainText()
  617             style = flowable.style.name
  618             if style == 'Heading1':
  619                 self.notify('TOCEntry', (0, text, self.page))
  620             if style == 'Heading2':
  621                 self.notify('TOCEntry', (1, text, self.page))
  622 
  623 h1 = PS(name = 'Heading1',
  624        fontSize = 14,
  625        leading = 16)
  626 
  627 h2 = PS(name = 'Heading2',
  628        fontSize = 12,
  629        leading = 14,
  630        leftIndent = delta)
  631 
  632 # Build story.
  633 story = []
  634 toc = TableOfContents()
  635 # For conciseness we use the same styles for headings and TOC entries
  636 toc.levelStyles = [h1, h2]
  637 story.append(toc)
  638 story.append(PageBreak())
  639 story.append(Paragraph('First heading', h1))
  640 story.append(Paragraph('Text in first heading', PS('body')))
  641 story.append(Paragraph('First sub heading', h2))
  642 story.append(Paragraph('Text in first sub heading', PS('body')))
  643 story.append(PageBreak())
  644 story.append(Paragraph('Second sub heading', h2))
  645 story.append(Paragraph('Text in second sub heading', PS('body')))
  646 story.append(Paragraph('Last heading', h1))
  647 
  648 doc = MyDocTemplate('mintoc.pdf')
  649 doc.multiBuild(story)
  650 ''')
  651 
  652 CPage(1)
  653 heading2("""$SimpleIndex()$""")
  654 disc("""
  655 An index can be generated by using the $SimpleIndex$ flowable.
  656 
  657 The following steps are needed to add an index to your document:
  658 """)
  659 
  660 disc("""Use the index tag in paragraphs to index terms:""")
  661 
  662 eg('''
  663 story = []
  664 
  665 ...
  666 
  667 story.append('The third <index item="word" />word of this paragraph is indexed.')
  668 ''')
  669 
  670 disc("""Create an instance of $SimpleIndex$ and add it to the story where you want it to appear:""")
  671 
  672 eg('''
  673 index = SimpleIndex(dot=' . ', headers=headers)
  674 story.append(index)
  675 ''')
  676 
  677 disc("""The parameters which you can pass into the SimpleIndex constructor are explained in the reportlab reference. Now, build the document by using the canvas maker returned by SimpleIndex.getCanvasMaker():""")
  678 
  679 eg("""
  680 doc.build(story, canvasmaker=index.getCanvasMaker())
  681 """)
  682 
  683 disc("""To build an index with multiple levels, pass a comma-separated list of items to the item attribute of an index tag:""")
  684 
  685 eg("""
  686 <index item="terma,termb,termc" />
  687 <index item="terma,termd" />
  688 """)
  689 
  690 disc("""terma will respresent the top-most level and termc the most specific term. termd and termb will appear in the same level inside terma.""")
  691 
  692 disc("""If you need to index a term containing a comma, you will need to escape it by doubling it. To avoid the ambiguity of three consecutive commas (an escaped comma followed by a list separator or a list separator followed by an escaped comma?) introduce a space in the right position. Spaces at the beginning or end of terms will be removed.""")
  693 
  694 eg("""
  695 <index item="comma(,,), ,, ,...   " />
  696 """)
  697 
  698 disc("""
  699 This indexes the terms "comma (,)", "," and "...".
  700 """)
  701 
  702 heading2("""$ListFlowable(),ListItem()$""")
  703 disc("""
  704 Use these classes to make ordered and unordered lists.  Lists can be nested.
  705 """)
  706 
  707 disc("""
  708 $ListFlowable()$ will create an ordered list, which can contain any flowable.  The class has a number of parameters to change font, colour, size, style and position of list numbers, or of bullets in unordered lists.  The type of numbering can also be set to use lower or upper case letters ('A,B,C' etc.) or Roman numerals (capitals or lowercase) using the bulletType property.  To change the list to an unordered type, set bulletType='bullet'.
  709 """)
  710 
  711 disc("""
  712 Items within a $ListFlowable()$ list can be changed from their default appearance by wrapping them in a $ListItem()$ class and setting its properties.
  713 """)
  714 
  715 disc("""
  716 The following will create an ordered list, and set the third item to an unordered sublist.
  717 """)
  718 
  719 EmbeddedCode("""
  720 from reportlab.platypus import ListFlowable, ListItem
  721 from reportlab.lib.styles import getSampleStyleSheet
  722 styles = getSampleStyleSheet()
  723 style = styles["Normal"]
  724 t = ListFlowable(
  725 [
  726 Paragraph("Item no.1", style),
  727 ListItem(Paragraph("Item no. 2", style),bulletColor="green",value=7),
  728 ListFlowable(
  729                 [
  730                 Paragraph("sublist item 1", style),
  731                 ListItem(Paragraph('sublist item 2', style),bulletColor='red',value='square')
  732                 ],
  733                 bulletType='bullet',
  734                 start='square',
  735                 ),
  736 Paragraph("Item no.4", style),
  737 ],
  738 bulletType='i'
  739 )
  740              """)
  741 
  742 disc("""To cope with nesting the $start$ parameter can be set to a list of possible starts; for $ul$ acceptable starts are any unicode character or specific names known to flowables.py eg
  743 $bulletchar$, $circle$, $square$, $disc$, $diamond$, $diamondwx$, $rarrowhead$, $sparkle$, $squarelrs$ or  $blackstar$. For $ol$ the $start$ can be any character from $'1iaAI'$ to indicate different number styles.
  744 """)
  745 
  746 heading2("""$BalancedColumns()$""")
  747 disc("""Use the $BalancedColumns$ class to make a flowable that splits its content flowables into two or more roughly equal sized columns.
  748 Effectively $n$ frames are synthesized to take the content and the flowable tries to balance the content between them. The created frames
  749 will be split when the total height is too large and the split will maintain the balance. 
  750 """)
  751 eg("""
  752 from reportlab.platypus.flowables import BalancedColumns
  753 from reportlab.platypus.frames import ShowBoundaryValue
  754 F = [
  755     list of flowables........
  756     ]
  757 story.append(
  758     Balanced(
  759         F,          #the flowables we are balancing
  760         nCols = 2,  #the number of columns
  761         needed = 72,#the minimum space needed by the flowable
  762         spacBefore = 0,
  763         spaceAfter = 0,
  764         showBoundary = None,    #optional boundary showing
  765         leftPadding=None,       #these override the created frame
  766         rightPadding=None,      #paddings if specified else the
  767         topPadding=None,        #default frame paddings
  768         bottomPadding=None,     #are used
  769         innerPadding=None,      #the gap between frames if specified else
  770                                 #use max(leftPadding,rightPadding)
  771         name='',                #for identification purposes when stuff goes awry
  772         endSlack=0.1,           #height disparity allowance ie 10% of available height
  773         )
  774     )   
  775 """)