reportlab/platypus/flowables.py
author rgbecker
Sun, 03 Nov 2002 14:51:09 +0000
changeset 1768 ea95b92748cc
parent 1683 7fa753e4420a
child 1879 c1dc90e2f470
permissions -rw-r--r--
Added ParagraphAndImage
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
494
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     1
#copyright ReportLab Inc. 2000
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     2
#see license.txt for license details
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     3
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/flowables.py?cvsroot=reportlab
1768
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
     4
#$Header: /tmp/reportlab/reportlab/platypus/flowables.py,v 1.32 2002/11/03 14:51:09 rgbecker Exp $
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
     5
__version__=''' $Id: flowables.py,v 1.32 2002/11/03 14:51:09 rgbecker Exp $ '''
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
     6
__doc__="""
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     7
A flowable is a "floating element" in a document whose exact position is determined by the
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     8
other elements that precede it, such as a paragraph, a diagram interspersed between paragraphs,
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     9
a section header, etcetera.  Examples of non-flowables include page numbering annotations,
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    10
headers, footers, fixed diagrams or logos, among others.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    11
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    12
Flowables are defined here as objects which know how to determine their size and which
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    13
can draw themselves onto a page with respect to a relative "origin" position determined
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    14
at a higher level. The object's draw() method should assume that (0,0) corresponds to the
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    15
bottom left corner of the enclosing rectangle that will contain the object. The attributes
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    16
vAlign and hAlign may be used by 'packers' as hints as to how the object should be placed.
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    17
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    18
Some Flowables also know how to "split themselves".  For example a
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    19
long paragraph might split itself between one page and the next.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    20
1490
d6d958390ff0 Added api instructions
rgbecker
parents: 1486
diff changeset
    21
Packers should set the canv attribute during wrap, split & draw operations to allow
d6d958390ff0 Added api instructions
rgbecker
parents: 1486
diff changeset
    22
the flowable to work out sizes etc in the proper context.
d6d958390ff0 Added api instructions
rgbecker
parents: 1486
diff changeset
    23
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    24
The "text" of a document usually consists mainly of a sequence of flowables which
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    25
flow into a document from top to bottom (with column and page breaks controlled by
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    26
higher level components).
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    27
"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    28
import os
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    29
import string
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    30
from copy import deepcopy
557
0ed50942f243 Allow for non string file names in Image.__init__
rgbecker
parents: 541
diff changeset
    31
from types import ListType, TupleType, StringType
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    32
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    33
from reportlab.pdfgen import canvas
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    34
from reportlab.lib.units import inch
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    35
from reportlab.lib.colors import red
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    36
from reportlab.pdfbase import pdfutils
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    37
724
0b10945bd324 Renamed config.py to rl_config.py
rgbecker
parents: 684
diff changeset
    38
from reportlab.rl_config import defaultPageSize
684
2a43c747527a Changed things to use config.py for defaults
rgbecker
parents: 558
diff changeset
    39
PAGE_HEIGHT = defaultPageSize[1]
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    40
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    41
#############################################################
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    42
#   Flowable Objects - a base class and a few examples.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    43
#   One is just a box to get some metrics.  We also have
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    44
#   a paragraph, an image and a special 'page break'
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    45
#   object which fills the space.
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    46
#############################################################
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    47
class Flowable:
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    48
    """Abstract base class for things to be drawn.  Key concepts:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    49
    1. It knows its size
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    50
    2. It draws in its own coordinate system (this requires the
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    51
        base API to provide a translate() function.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    52
    """
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    53
    def __init__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    54
        self.width = 0
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    55
        self.height = 0
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    56
        self.wrapped = 0
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    57
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    58
        #these are hints to packers/frames as to how the floable should be positioned
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    59
        self.hAlign = 'LEFT'    #CENTER/CENTRE or RIGHT
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    60
        self.vAlign = 'BOTTOM'  #MIDDLE or TOP
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    61
1494
b0707e45102e Added _drawOn method
rgbecker
parents: 1491
diff changeset
    62
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    63
    def _drawOn(self,canv):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    64
        '''ensure canv is set on and then draw'''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    65
        self.canv = canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    66
        self.draw()#this is the bit you overload
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    67
        del self.canv
1494
b0707e45102e Added _drawOn method
rgbecker
parents: 1491
diff changeset
    68
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    69
    def drawOn(self, canvas, x, y, _sW=0):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    70
        "Tell it to draw itself on the canvas.  Do not override"
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    71
        if _sW and hasattr(self,'hAlign'):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    72
            a = self.hAlign
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    73
            if a in ['CENTER','CENTRE']:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    74
                x = x + 0.5*_sW
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    75
            elif a == 'RIGHT':
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    76
                x = x + _sW
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    77
            elif a != 'LEFT':
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    78
                raise ValueError, "Bad hAlign value "+str(a)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    79
        canvas.saveState()
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    80
        canvas.translate(x, y)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    81
        self._drawOn(canvas)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    82
        canvas.restoreState()
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    83
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    84
    def wrapOn(self, canv, aW, aH):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    85
        '''intended for use by packers allows setting the canvas on
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    86
        during the actual wrap'''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    87
        self.canv = canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    88
        w, h = self.wrap(aW,aH)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    89
        del self.canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    90
        return w, h
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    91
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    92
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    93
        """This will be called by the enclosing frame before objects
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    94
        are asked their size, drawn or whatever.  It returns the
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    95
        size actually used."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    96
        return (self.width, self.height)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    97
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    98
    def minWidth(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
    99
        """This should return the minimum required width"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   100
        return getattr(self,'_minWidth',self.width)
954
bf9f434cb08a added minWidth method to Flowable, Paragraph
rgbecker
parents: 760
diff changeset
   101
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   102
    def splitOn(self, canv, aW, aH):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   103
        '''intended for use by packers allows setting the canvas on
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   104
        during the actual split'''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   105
        self.canv = canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   106
        S = self.split(aW,aH)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   107
        del self.canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   108
        return S
1491
8cb77f6ac40d Introduce wrapOn & splitOn
rgbecker
parents: 1490
diff changeset
   109
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   110
    def split(self, availWidth, availheight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   111
        """This will be called by more sophisticated frames when
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   112
        wrap fails. Stupid flowables should return []. Clever flowables
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   113
        should split themselves and return a list of flowables"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   114
        return []
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   115
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   116
    def getKeepWithNext(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   117
        """returns boolean determining whether the next flowabel should stay with this one"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   118
        if hasattr(self,'keepWithNext'): return self.keepWithNext
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   119
        elif hasattr(self,'style') and hasattr(self.style,'keepWithNext'): return self.style.keepWithNext
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   120
        else: return 0
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   121
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   122
    def getSpaceAfter(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   123
        """returns how much space should follow this item if another item follows on the same page."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   124
        if hasattr(self,'spaceAfter'): return self.spaceAfter
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   125
        elif hasattr(self,'style') and hasattr(self.style,'spaceAfter'): return self.style.spaceAfter
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   126
        else: return 0
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   127
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   128
    def getSpaceBefore(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   129
        """returns how much space should precede this item if another item precedess on the same page."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   130
        if hasattr(self,'spaceBefore'): return self.spaceBefore
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   131
        elif hasattr(self,'style') and hasattr(self.style,'spaceBefore'): return self.style.spaceBefore
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   132
        else: return 0
1426
377351bbe539 Add getKeepWithNext to Flowable
rgbecker
parents: 1360
diff changeset
   133
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   134
    def isIndexing(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   135
        """Hook for IndexingFlowables - things which have cross references"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   136
        return 0
512
c12ae96634d5 Added working table of contents framework
andy_robinson
parents: 496
diff changeset
   137
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   138
    def identity(self, maxLen=None):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   139
        '''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   140
        This method should attempt to return a string that can be used to identify
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   141
        a particular flowable uniquely. The result can then be used for debugging
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   142
        and or error printouts
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   143
        '''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   144
        if hasattr(self, 'getPlainText'):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   145
            r = self.getPlainText()
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   146
        elif hasattr(self, 'text'):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   147
            r = self.text
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   148
        else:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   149
            r = '...'
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   150
        if r and maxLen:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   151
            r = r[:maxLen]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   152
        return "<%s at %d>%s" % (self.__class__.__name__, id(self), r)
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   153
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   154
class XBox(Flowable):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   155
    """Example flowable - a box with an x through it and a caption.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   156
    This has a known size, so does not need to respond to wrap()."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   157
    def __init__(self, width, height, text = 'A Box'):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   158
        Flowable.__init__(self)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   159
        self.width = width
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   160
        self.height = height
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   161
        self.text = text
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   162
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   163
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   164
        return "XBox(w=%s, h=%s, t=%s)" % (self.width, self.height, self.text)
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   165
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   166
    def draw(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   167
        self.canv.rect(0, 0, self.width, self.height)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   168
        self.canv.line(0, 0, self.width, self.height)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   169
        self.canv.line(0, self.height, self.width, 0)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   170
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   171
        #centre the text
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   172
        self.canv.setFont('Times-Roman',12)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   173
        self.canv.drawCentredString(0.5*self.width, 0.5*self.height, self.text)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   174
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   175
def _trimEmptyLines(lines):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   176
    #don't want the first or last to be empty
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   177
    while len(lines) and string.strip(lines[0]) == '':
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   178
        lines = lines[1:]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   179
    while len(lines) and string.strip(lines[-1]) == '':
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   180
        lines = lines[:-1]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   181
    return lines
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   182
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   183
def _dedenter(text,dedent=0):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   184
    '''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   185
    tidy up text - carefully, it is probably code.  If people want to
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   186
    indent code within a source script, you can supply an arg to dedent
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   187
    and it will chop off that many character, otherwise it leaves
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   188
    left edge intact.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   189
    '''
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   190
    lines = string.split(text, '\n')
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   191
    if dedent>0:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   192
        templines = _trimEmptyLines(lines)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   193
        lines = []
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   194
        for line in templines:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   195
            line = string.rstrip(line[dedent:])
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   196
            lines.append(line)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   197
    else:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   198
        lines = _trimEmptyLines(lines)
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   199
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   200
    return lines
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   201
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   202
class Preformatted(Flowable):
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   203
    """This is like the HTML <PRE> tag.
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   204
    It attempts to display text exactly as you typed it in a fixed width "typewriter" font.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   205
    The line breaks are exactly where you put
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   206
    them, and it will not be wrapped."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   207
    def __init__(self, text, style, bulletText = None, dedent=0):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   208
        """text is the text to display. If dedent is set then common leading space
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   209
        will be chopped off the front (for example if the entire text is indented
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   210
        6 spaces or more then each line will have 6 spaces removed from the front).
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   211
        """
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   212
        self.style = style
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   213
        self.bulletText = bulletText
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   214
        self.lines = _dedenter(text,dedent)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   215
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   216
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   217
        bT = self.bulletText
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   218
        H = "Preformatted("
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   219
        if bT is not None:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   220
            H = "Preformatted(bulletText=%s," % repr(bT)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   221
        import string
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   222
        text = join(self.lines, "\n")
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   223
        return "%s'''\\ \n%s''')" % (H, text)
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   224
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   225
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   226
        self.width = availWidth
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   227
        self.height = self.style.leading*len(self.lines)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   228
        return (self.width, self.height)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   229
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   230
    def split(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   231
        #returns two Preformatted objects
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   232
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   233
        #not sure why they can be called with a negative height
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   234
        if availHeight < self.style.leading:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   235
            return []
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   236
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   237
        linesThatFit = int(availHeight * 1.0 / self.style.leading)
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   238
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   239
        text1 = string.join(self.lines[0:linesThatFit], '\n')
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   240
        text2 = string.join(self.lines[linesThatFit:], '\n')
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   241
        style = self.style
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   242
        if style.firstLineIndent != 0:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   243
            style = deepcopy(style)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   244
            style.firstLineIndent = 0
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   245
        return [Preformatted(text1, self.style), Preformatted(text2, style)]
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   246
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   247
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   248
    def draw(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   249
        #call another method for historical reasons.  Besides, I
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   250
        #suspect I will be playing with alternate drawing routines
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   251
        #so not doing it here makes it easier to switch.
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   252
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   253
        cur_x = self.style.leftIndent
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   254
        cur_y = self.height - self.style.fontSize
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   255
        self.canv.addLiteral('%PreformattedPara')
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   256
        if self.style.textColor:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   257
            self.canv.setFillColor(self.style.textColor)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   258
        tx = self.canv.beginText(cur_x, cur_y)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   259
        #set up the font etc.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   260
        tx.setFont( self.style.fontName,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   261
                    self.style.fontSize,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   262
                    self.style.leading)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   263
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   264
        for text in self.lines:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   265
            tx.textLine(text)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   266
        self.canv.drawText(tx)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   267
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   268
class Image(Flowable):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   269
    """an image (digital picture).  Formats supported by PIL (the Python Imaging Library
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   270
       are supported.  At the present time images as flowables are always centered horozontally
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   271
       in the frame.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   272
    """
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   273
    def __init__(self, filename, width=None, height=None, kind='direct'):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   274
        """If size to draw at not specified, get it from the image."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   275
        from reportlab.lib.utils import PIL_Image  #this will raise an error if they do not have PIL.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   276
        self._filename = self.filename = filename
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   277
        self.hAlign = 'CENTER'
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   278
        # if it is a JPEG, will be inlined within the file -
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   279
        # but we still need to know its size now
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   280
        if type(filename) is StringType and os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   281
            info = pdfutils.readJPEGInfo(open(filename, 'rb'))
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   282
            self.imageWidth = info[0]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   283
            self.imageHeight = info[1]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   284
        else:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   285
            # we have to assume this is a file like object
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   286
            self.filename = img = PIL_Image.open(filename)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   287
            (self.imageWidth, self.imageHeight) = img.size
1477
dc5c2ba1005a Allow for various Image kinds
rgbecker
parents: 1426
diff changeset
   288
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   289
        if kind in ['direct','absolute']:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   290
            self.drawWidth = width or self.imageWidth
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   291
            self.drawHeight = height or self.imageHeight
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   292
        elif kind in ['percentage','%']:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   293
            self.drawWidth = self.imageWidth*width*0.01
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   294
            self.drawHeight = self.imageHeight*height*0.01
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   295
        elif kind in ['bound','proportional']:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   296
            factor = min(float(width)/self.imageWidth,float(height)/self.imageHeight)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   297
            self.drawWidth = self.imageWidth*factor
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   298
            self.drawHeight = self.imageHeight*factor
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   299
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   300
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   301
        #the caller may decide it does not fit.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   302
        return (self.drawWidth, self.drawHeight)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   303
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   304
    def draw(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   305
        #center it
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   306
        self.canv.drawImage(self.filename,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   307
                                0,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   308
                                0,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   309
                                self.drawWidth,
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   310
                                self.drawHeight
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   311
                                )
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   312
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   313
    def identity(self,maxLen):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   314
        r = Flowable.identity(self,maxLen)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   315
        if r[-4:]=='>...' and type(self._filename) is StringType:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   316
            r = "%s filename=%s>" % (r[:-4],self._filename)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   317
        return r
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   318
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   319
class Spacer(Flowable):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   320
    """A spacer just takes up space and doesn't draw anything - it guarantees
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   321
       a gap between objects."""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   322
    def __init__(self, width, height):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   323
        self.width = width
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   324
        self.height = height
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   325
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   326
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   327
        return "Spacer(%s, %s)" % (self.width, self.height)
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   328
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   329
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   330
        return (self.width, self.height)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   331
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   332
    def draw(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   333
        pass
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   334
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   335
class PageBreak(Spacer):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   336
    """Move on to the next page in the document.
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   337
       This works by consuming all remaining space in the frame!"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   338
    def __init__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   339
        pass
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   340
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   341
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   342
        return "PageBreak()"
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   343
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   344
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   345
        self.width = availWidth
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   346
        self.height = availHeight
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   347
        return (availWidth,availHeight)  #step back a point
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   348
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   349
class CondPageBreak(Spacer):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   350
    """Throw a page if not enough vertical space"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   351
    def __init__(self, height):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   352
        self.height = height
1683
7fa753e4420a Removed all trailing whitespace
andy_robinson
parents: 1677
diff changeset
   353
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   354
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   355
        return "CondPageBreak(%s)" %(self.height,)
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   356
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   357
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   358
        if availHeight<self.height:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   359
            return (availWidth, availHeight)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   360
        return (0, 0)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   361
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   362
_SeqTypes = (ListType, TupleType)
558
f9013e25af9d Added a random text module
andy_robinson
parents: 557
diff changeset
   363
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   364
class KeepTogether(Flowable):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   365
    def __init__(self,flowables):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   366
        if type(flowables) not in _SeqTypes:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   367
            self._flowables = [flowables]
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   368
        else:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   369
            self._flowables = flowables
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   370
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   371
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   372
        f = self._flowables
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   373
        L = map(repr,f)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   374
        import string
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   375
        L = "\n"+string.join(L, "\n")
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   376
        L = string.replace(L, "\n", "\n  ")
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   377
        return "KeepTogether(%s) # end KeepTogether" % L
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   378
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   379
    def wrap(self, aW, aH):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   380
        W = 0
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   381
        H = 0
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   382
        F = self._flowables
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   383
        canv = self.canv
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   384
        for f in F:
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   385
            w,h = f.wrapOn(canv,aW,0xfffffff)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   386
            if f is not F[0]: h = h + f.getSpaceBefore()
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   387
            if f is not F[-1]: h = h + f.getSpaceAfter()
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   388
            W = max(W,w)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   389
            H = H+h
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   390
        self._CPage = H>aH
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   391
        return W, 0xffffff  # force a split
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   392
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   393
    def split(self, aW, aH):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   394
        S = getattr(self,'_CPage',1) and [CondPageBreak(aH+1)] or []
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   395
        for f in self._flowables: S.append(f)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   396
        return S
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   397
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   398
class Macro(Flowable):
1677
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   399
    """This is not actually drawn (i.e. it has zero height)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   400
    but is executed when it would fit in the frame.  Allows direct
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   401
    access to the canvas through the object 'canvas'"""
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   402
    def __init__(self, command):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   403
        self.command = command
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   404
    def __repr__(self):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   405
        return "Macro(%s)" % repr(self.command)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   406
    def wrap(self, availWidth, availHeight):
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   407
        return (0,0)
1450177dd19e Exterminated all tab characters and added a test to make sure
andy_robinson
parents: 1554
diff changeset
   408
    def draw(self):
1768
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   409
        exec self.command in globals(), {'canvas':self.canv}
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   410
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   411
class ParagraphAndImage(Flowable):
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   412
    '''combine a Paragraph and an Image'''
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   413
    def __init__(self,P,I,xpad=3,ypad=3):
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   414
        self.P, self.style, self.I, self.xpad, self.ypad = P,P.style,I,xpad,ypad
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   415
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   416
    def wrap(self,availWidth,availHeight):
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   417
        wI, hI = self.I.wrap(availWidth,availHeight)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   418
        self.wI, self.hI = wI, hI
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   419
        # work out widths array for breaking
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   420
        self.width = availWidth
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   421
        P, style, xpad, ypad = self.P, self.style, self.xpad, self.ypad
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   422
        leading = style.leading
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   423
        leftIndent = style.leftIndent
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   424
        later_widths = availWidth - leftIndent - style.rightIndent
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   425
        intermediate_widths = later_widths - xpad - wI
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   426
        first_line_width = intermediate_widths - style.firstLineIndent
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   427
        P.width = 0
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   428
        P.blPara = P.breakLines([first_line_width] + int((hI+ypad)/leading)*[intermediate_widths]+[later_widths])
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   429
        P.height = len(P.blPara.lines)*leading
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   430
        self.height = max(hI,P.height)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   431
        return (self.width, self.height)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   432
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   433
    def split(self,availWidth, availHeight):
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   434
        P, wI, hI, ypad = self.P, self.wI, self.hI, self.ypad
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   435
        if hI+ypad>availHeight or len(P.frags)<=0: return []
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   436
        S = P.split(availWidth,availHeight)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   437
        if not S: return S
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   438
        P = self.P = S[0]
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   439
        del S[0]
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   440
        style = self.style = P.style
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   441
        P.height = len(self.P.blPara.lines)*style.leading
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   442
        self.height = max(hI,P.height)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   443
        return [self]+S
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   444
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   445
    def draw(self):
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   446
        canv = self.canv
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   447
        self.I.drawOn(canv,self.width-self.wI-self.xpad,self.height-self.hI)
ea95b92748cc Added ParagraphAndImage
rgbecker
parents: 1683
diff changeset
   448
        self.P.drawOn(canv,0,0)