~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/reportlab/platypus/xpreformatted.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#Copyright ReportLab Europe Ltd. 2000-2004
 
2
#see license.txt for license details
 
3
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/xpreformatted.py
 
4
__version__=''' $Id$ '''
 
5
 
 
6
import string
 
7
from types import StringType, ListType
 
8
 
 
9
from reportlab.lib import PyFontify
 
10
from paragraph import Paragraph, cleanBlockQuotedText, _handleBulletWidth, \
 
11
     ParaLines, _getFragWords, stringWidth, _sameFrag
 
12
from flowables import _dedenter
 
13
 
 
14
 
 
15
def _getFragLines(frags):
 
16
    lines = []
 
17
    cline = []
 
18
    W = frags[:]
 
19
    while W != []:
 
20
        w = W[0]
 
21
        t = w.text
 
22
        del W[0]
 
23
        i = string.find(t,'\n')
 
24
        if i>=0:
 
25
            tleft = t[i+1:]
 
26
            cline.append(w.clone(text=t[:i]))
 
27
            lines.append(cline)
 
28
            cline = []
 
29
            if tleft!='':
 
30
                W.insert(0,w.clone(text=tleft))
 
31
        else:
 
32
            cline.append(w)
 
33
    if cline!=[]:
 
34
        lines.append(cline)
 
35
    return lines
 
36
 
 
37
def _split_blPara(blPara,start,stop):
 
38
    f = blPara.clone()
 
39
    for a in ('lines', 'text'):
 
40
        if hasattr(f,a): delattr(f,a)
 
41
    f.lines = blPara.lines[start:stop]
 
42
    return [f]
 
43
 
 
44
# Will be removed shortly.
 
45
def _countSpaces(text):
 
46
    return string.count(text, ' ')
 
47
##  i = 0
 
48
##  s = 0
 
49
##  while 1:
 
50
##      j = string.find(text,' ',i)
 
51
##      if j<0: return s
 
52
##      s = s + 1
 
53
##      i = j + 1
 
54
 
 
55
def _getFragWord(frags):
 
56
    ''' given a fragment list return a list of lists
 
57
        [size, spaces, (f00,w00), ..., (f0n,w0n)]
 
58
        each pair f,w represents a style and some string
 
59
    '''
 
60
    W = []
 
61
    n = 0
 
62
    s = 0
 
63
    for f in frags:
 
64
        text = f.text[:]
 
65
        W.append((f,text))
 
66
        n = n + stringWidth(text, f.fontName, f.fontSize)
 
67
 
 
68
        #s = s + _countSpaces(text)
 
69
        s = s + string.count(text, ' ') # much faster for many blanks
 
70
 
 
71
        #del f.text # we can't do this until we sort out splitting
 
72
                    # of paragraphs
 
73
    return n, s, W
 
74
 
 
75
 
 
76
class XPreformatted(Paragraph):
 
77
    def __init__(self, text, style, bulletText = None, frags=None, caseSensitive=1, dedent=0):
 
78
        self.caseSensitive = caseSensitive
 
79
        cleaner = lambda text, dedent=dedent: string.join(_dedenter(text or '',dedent),'\n')
 
80
        self._setup(text, style, bulletText, frags, cleaner)
 
81
 
 
82
    def breakLines(self, width):
 
83
        """
 
84
        Returns a broken line structure. There are two cases
 
85
 
 
86
        A) For the simple case of a single formatting input fragment the output is
 
87
            A fragment specifier with
 
88
                kind = 0
 
89
                fontName, fontSize, leading, textColor
 
90
                lines=  A list of lines
 
91
                        Each line has two items.
 
92
                        1) unused width in points
 
93
                        2) a list of words
 
94
 
 
95
        B) When there is more than one input formatting fragment the out put is
 
96
            A fragment specifier with
 
97
                kind = 1
 
98
                lines=  A list of fragments each having fields
 
99
                            extraspace (needed for justified)
 
100
                            fontSize
 
101
                            words=word list
 
102
                                each word is itself a fragment with
 
103
                                various settings
 
104
 
 
105
        This structure can be used to easily draw paragraphs with the various alignments.
 
106
        You can supply either a single width or a list of widths; the latter will have its
 
107
        last item repeated until necessary. A 2-element list is useful when there is a
 
108
        different first line indent; a longer list could be created to facilitate custom wraps
 
109
        around irregular objects."""
 
110
 
 
111
        if type(width) <> ListType: maxWidths = [width]
 
112
        else: maxWidths = width
 
113
        lines = []
 
114
        lineno = 0
 
115
        maxWidth = maxWidths[lineno]
 
116
        style = self.style
 
117
        fFontSize = float(style.fontSize)
 
118
        requiredWidth = 0
 
119
 
 
120
        #for bullets, work out width and ensure we wrap the right amount onto line one
 
121
        _handleBulletWidth(self.bulletText,style,maxWidths)
 
122
 
 
123
        self.height = 0
 
124
        frags = self.frags
 
125
        nFrags= len(frags)
 
126
        if nFrags==1:
 
127
            f = frags[0]
 
128
            if hasattr(f,'text'):
 
129
                fontSize = f.fontSize
 
130
                fontName = f.fontName
 
131
                kind = 0
 
132
                L=string.split(f.text, '\n')
 
133
                for l in L:
 
134
                    currentWidth = stringWidth(l,fontName,fontSize)
 
135
                    requiredWidth = max(currentWidth,requiredWidth)
 
136
                    extraSpace = maxWidth-currentWidth
 
137
                    lines.append((extraSpace,string.split(l,' '),currentWidth))
 
138
                    lineno = lineno+1
 
139
                    maxWidth = lineno<len(maxWidths) and maxWidths[lineno] or maxWidths[-1]
 
140
            else:
 
141
                kind = f.kind
 
142
                lines = f.lines
 
143
                for L in lines:
 
144
                    if kind==0:
 
145
                        currentWidth = L[2]
 
146
                    else:
 
147
                        currentWidth = L.currentWidth
 
148
                    requiredWidth = max(currentWidth,requiredWidth)
 
149
 
 
150
            self.width = max(self.width,requiredWidth)
 
151
            return f.clone(kind=kind, lines=lines)
 
152
        elif nFrags<=0:
 
153
            return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName,
 
154
                            textColor=style.textColor, lines=[])
 
155
        else:
 
156
            for L in _getFragLines(frags):
 
157
                maxSize = 0
 
158
                currentWidth, n, w = _getFragWord(L)
 
159
                f = w[0][0]
 
160
                maxSize = max(maxSize,f.fontSize)
 
161
                words = [f.clone()]
 
162
                words[-1].text = w[0][1]
 
163
                for i in w[1:]:
 
164
                    f = i[0].clone()
 
165
                    f.text=i[1]
 
166
                    words.append(f)
 
167
                    maxSize = max(maxSize,f.fontSize)
 
168
 
 
169
                lineno = lineno+1
 
170
                maxWidth = lineno<len(maxWidths) and maxWidths[lineno] or maxWidths[-1]
 
171
                requiredWidth = max(currentWidth,requiredWidth)
 
172
                extraSpace = maxWidth - currentWidth
 
173
                lines.append(ParaLines(extraSpace=extraSpace,wordCount=n, words=words, fontSize=maxSize, currentWidth=currentWidth))
 
174
 
 
175
            self.width = max(self.width,requiredWidth)
 
176
            return ParaLines(kind=1, lines=lines)
 
177
 
 
178
        return lines
 
179
 
 
180
    # we need this her to get the right splitter
 
181
    def _get_split_blParaFunc(self):
 
182
        return _split_blPara
 
183
 
 
184
 
 
185
class PythonPreformatted(XPreformatted):
 
186
    """Used for syntax-colored Python code, otherwise like XPreformatted.
 
187
    """
 
188
 
 
189
    formats = {
 
190
        'rest'       : ('', ''),
 
191
        'comment'    : ('<font color="green">', '</font>'),
 
192
        'keyword'    : ('<font color="blue"><b>', '</b></font>'),
 
193
        'parameter'  : ('<font color="black">', '</font>'),
 
194
        'identifier' : ('<font color="red">', '</font>'),
 
195
        'string'     : ('<font color="gray">', '</font>') }
 
196
 
 
197
    def __init__(self, text, style, bulletText = None, dedent=0, frags=None):
 
198
        if text:
 
199
            text = self.fontify(self.escapeHtml(text))
 
200
        apply(XPreformatted.__init__,
 
201
              (self, text, style),
 
202
              {'bulletText':bulletText, 'dedent':dedent, 'frags':frags})
 
203
 
 
204
    def escapeHtml(self, text):
 
205
        s = string.replace(text, '&', '&amp;')
 
206
        s = string.replace(s, '<', '&lt;')
 
207
        s = string.replace(s, '>', '&gt;')
 
208
        return s
 
209
 
 
210
    def fontify(self, code):
 
211
        "Return a fontified version of some Python code."
 
212
 
 
213
        if code[0] == '\n':
 
214
            code = code[1:]
 
215
 
 
216
        tags = PyFontify.fontify(code)
 
217
        fontifiedCode = ''
 
218
        pos = 0
 
219
        for k, i, j, dummy in tags:
 
220
            fontifiedCode = fontifiedCode + code[pos:i]
 
221
            s, e = self.formats[k]
 
222
            fontifiedCode = fontifiedCode + s + code[i:j] + e
 
223
            pos = j
 
224
 
 
225
        fontifiedCode = fontifiedCode + code[pos:]
 
226
 
 
227
        return fontifiedCode
 
228
 
 
229
 
 
230
if __name__=='__main__':    #NORUNTESTS
 
231
    def dumpXPreformattedLines(P):
 
232
        print '\n############dumpXPreforemattedLines(%s)' % str(P)
 
233
        lines = P.blPara.lines
 
234
        n =len(lines)
 
235
        for l in range(n):
 
236
            line = lines[l]
 
237
            words = line.words
 
238
            nwords = len(words)
 
239
            print 'line%d: %d(%d)\n  ' % (l,nwords,line.wordCount),
 
240
            for w in range(nwords):
 
241
                print "%d:'%s'"%(w,words[w].text),
 
242
            print
 
243
 
 
244
    def dumpXPreformattedFrags(P):
 
245
        print '\n############dumpXPreforemattedFrags(%s)' % str(P)
 
246
        frags = P.frags
 
247
        n =len(frags)
 
248
        for l in range(n):
 
249
            print "frag%d: '%s'" % (l, frags[l].text)
 
250
 
 
251
        l = 0
 
252
        for L in _getFragLines(frags):
 
253
            n=0
 
254
            for W in _getFragWords(L):
 
255
                print "frag%d.%d: size=%d" % (l, n, W[0]),
 
256
                n = n + 1
 
257
                for w in W[1:]:
 
258
                    print "'%s'" % w[1],
 
259
                print
 
260
            l = l + 1
 
261
 
 
262
    def try_it(text,style,dedent,aW,aH):
 
263
        P=XPreformatted(text,style,dedent=dedent)
 
264
        dumpXPreformattedFrags(P)
 
265
        w,h = P.wrap(aW, aH)
 
266
        dumpXPreformattedLines(P)
 
267
        S = P.split(aW,aH)
 
268
        dumpXPreformattedLines(P)
 
269
        for s in S:
 
270
            s.wrap(aW,aH)
 
271
            dumpXPreformattedLines(s)
 
272
            aH = 500
 
273
 
 
274
    from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
 
275
    styleSheet = getSampleStyleSheet()
 
276
    B = styleSheet['BodyText']
 
277
    DTstyle = ParagraphStyle("discussiontext", parent=B)
 
278
    DTstyle.fontName= 'Helvetica'
 
279
    for (text,dedent,style, aW, aH, active) in [('''
 
280
 
 
281
 
 
282
The <font name=courier color=green>CMYK</font> or subtractive
 
283
 
 
284
method follows the way a printer
 
285
mixes three pigments (cyan, magenta, and yellow) to form colors.
 
286
Because mixing chemicals is more difficult than combining light there
 
287
is a fourth parameter for darkness.  For example a chemical
 
288
combination of the <font name=courier color=green>CMY</font> pigments generally never makes a perfect
 
289
 
 
290
black -- instead producing a muddy color -- so, to get black printers
 
291
don't use the <font name=courier color=green>CMY</font> pigments but use a direct black ink.  Because
 
292
<font name=courier color=green>CMYK</font> maps more directly to the way printer hardware works it may
 
293
be the case that &amp;| &amp; | colors specified in <font name=courier color=green>CMYK</font> will provide better fidelity
 
294
and better control when printed.
 
295
 
 
296
 
 
297
''',0,DTstyle, 456.0, 42.8, 0),
 
298
('''
 
299
 
 
300
   This is a non rearranging form of the <b>Paragraph</b> class;
 
301
   <b><font color=red>XML</font></b> tags are allowed in <i>text</i> and have the same
 
302
 
 
303
      meanings as for the <b>Paragraph</b> class.
 
304
   As for <b>Preformatted</b>, if dedent is non zero <font color=red size=+1>dedent</font>
 
305
       common leading spaces will be removed from the
 
306
   front of each line.
 
307
 
 
308
''',3, DTstyle, 456.0, 42.8, 0),
 
309
("""\
 
310
    <font color=blue>class </font><font color=red>FastXMLParser</font>:
 
311
        # Nonsense method
 
312
        def nonsense(self):
 
313
            self.foo = 'bar'
 
314
""",0, styleSheet['Code'], 456.0, 4.8, 1),
 
315
]:
 
316
        if active: try_it(text,style,dedent,aW,aH)