~openerp-dev/openobject-server/trunk-bug-712254-ysa

« back to all changes in this revision

Viewing changes to bin/reportlab/tools/docco/rl_doc_utils.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
#! /usr/bin/python2.3
 
2
#Copyright ReportLab Europe Ltd. 2000-2004
 
3
#see license.txt for license details
 
4
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/tools/docco/rl_doc_utils.py
 
5
__version__=''' $Id$ '''
 
6
 
 
7
 
 
8
__doc__ = """
 
9
This module contains utilities for generating guides
 
10
"""
 
11
 
 
12
import os, sys, glob
 
13
import string
 
14
 
 
15
from rltemplate import RLDocTemplate
 
16
from stylesheet import getStyleSheet
 
17
styleSheet = getStyleSheet()
 
18
 
 
19
#from reportlab.platypus.doctemplate import SimpleDocTemplate
 
20
from reportlab.lib.units import inch
 
21
from reportlab.lib.pagesizes import letter, A4, A5, A3  # latter two for testing
 
22
from reportlab.rl_config import defaultPageSize
 
23
from reportlab.platypus import figures
 
24
from reportlab.platypus import Paragraph, Spacer, Preformatted,\
 
25
            PageBreak, CondPageBreak, Flowable, Table, TableStyle, \
 
26
            NextPageTemplate, KeepTogether, Image, XPreformatted
 
27
from reportlab.lib.styles import ParagraphStyle
 
28
from reportlab.lib import colors
 
29
from reportlab.lib.sequencer import getSequencer
 
30
 
 
31
import examples
 
32
 
 
33
appmode=0
 
34
 
 
35
 
 
36
from t_parse import Template
 
37
QFcodetemplate = Template("X$X$", "X")
 
38
QFreptemplate = Template("X^X^", "X")
 
39
codesubst = "%s<font name=Courier>%s</font>"
 
40
QFsubst = "%s<font name=Courier><i>%s</i></font>"
 
41
 
 
42
 
 
43
def quickfix(text):
 
44
    """inside text find any subsequence of form $subsequence$.
 
45
       Format the subsequence as code.  If similarly if text contains ^arg^
 
46
       format the arg as replaceable.  The escape sequence for literal
 
47
       $ is $\\$ (^ is ^\\^.
 
48
    """
 
49
    from string import join
 
50
    for (template,subst) in [(QFcodetemplate, codesubst), (QFreptemplate, QFsubst)]:
 
51
        fragment = text
 
52
        parts = []
 
53
        try:
 
54
            while fragment:
 
55
                try:
 
56
                    (matches, index) = template.PARSE(fragment)
 
57
                except: raise ValueError
 
58
                else:
 
59
                    [prefix, code] = matches
 
60
                    if code == "\\":
 
61
                        part = fragment[:index]
 
62
                    else:
 
63
                        part = subst % (prefix, code)
 
64
                    parts.append(part)
 
65
                    fragment = fragment[index:]
 
66
        except ValueError:
 
67
            parts.append(fragment)
 
68
        text = join(parts, "")
 
69
    return text
 
70
#print quickfix("$testing$ testing $one$ ^two^ $three(^four^)$")
 
71
 
 
72
 
 
73
 
 
74
H1 = styleSheet['Heading1']
 
75
H2 = styleSheet['Heading2']
 
76
H3 = styleSheet['Heading3']
 
77
H4 = styleSheet['Heading4']
 
78
B = styleSheet['BodyText']
 
79
BU = styleSheet['Bullet']
 
80
Comment = styleSheet['Comment']
 
81
Centred = styleSheet['Centred']
 
82
Caption = styleSheet['Caption']
 
83
 
 
84
#set up numbering
 
85
seq = getSequencer()
 
86
seq.setFormat('Chapter','1')
 
87
seq.setFormat('Section','1')
 
88
seq.setFormat('Appendix','A')
 
89
seq.setFormat('Figure', '1')
 
90
seq.chain('Chapter','Section')
 
91
seq.chain('Chapter','Figure')
 
92
 
 
93
lessonnamestyle = H2
 
94
discussiontextstyle = B
 
95
exampletextstyle = styleSheet['Code']
 
96
# size for every example
 
97
examplefunctionxinches = 5.5
 
98
examplefunctionyinches = 3
 
99
examplefunctiondisplaysizes = (examplefunctionxinches*inch, examplefunctionyinches*inch)
 
100
 
 
101
def getJustFontPaths():
 
102
    '''return afm and pfb for Just's files'''
 
103
    import reportlab
 
104
    folder = os.path.dirname(reportlab.__file__) + os.sep + 'fonts'
 
105
    return os.path.join(folder, 'Wargames.afm'), os.path.join(folder, 'Wargames.pfb')
 
106
 
 
107
# for testing
 
108
def NOP(*x,**y):
 
109
    return None
 
110
 
 
111
def CPage(inches):
 
112
    getStory().append(CondPageBreak(inches*inch))
 
113
 
 
114
def newPage():
 
115
    getStory().append(PageBreak())
 
116
 
 
117
def nextTemplate(templName):
 
118
    f = NextPageTemplate(templName)
 
119
    getStory().append(f)
 
120
 
 
121
def disc(text, klass=Paragraph, style=discussiontextstyle):
 
122
    text = quickfix(text)
 
123
    P = klass(text, style)
 
124
    getStory().append(P)
 
125
 
 
126
def restartList():
 
127
    getSequencer().reset('list1')
 
128
 
 
129
def list(text, doBullet=1):
 
130
    text=quickfix(text)
 
131
    if doBullet:
 
132
        text='<bullet><seq id="list1"/>.</bullet>'+text
 
133
    P = Paragraph(text, BU)
 
134
    getStory().append(P)
 
135
 
 
136
def bullet(text):
 
137
    text='<bullet><font name="Symbol">'+chr(183)+'</font></bullet>' + quickfix(text)
 
138
    P = Paragraph(text, BU)
 
139
    getStory().append(P)
 
140
 
 
141
def eg(text,before=0.1,after=0):
 
142
    space(before)
 
143
    disc(text, klass=Preformatted, style=exampletextstyle)
 
144
    space(after)
 
145
 
 
146
def space(inches=1./6):
 
147
    if inches: getStory().append(Spacer(0,inches*inch))
 
148
 
 
149
def EmbeddedCode(code,name='t'):
 
150
    eg(code)
 
151
    disc("produces")
 
152
    exec code+("\ngetStory().append(%s)\n"%name)
 
153
 
 
154
def startKeep():
 
155
    return len(getStory())
 
156
 
 
157
def endKeep(s):
 
158
    S = getStory()
 
159
    k = KeepTogether(S[s:])
 
160
    S[s:] = [k]
 
161
 
 
162
def title(text):
 
163
    """Use this for the document title only"""
 
164
    disc(text,style=styleSheet['Title'])
 
165
 
 
166
#AR 3/7/2000 - defining three new levels of headings; code
 
167
#should be swapped over to using them.
 
168
 
 
169
def heading1(text):
 
170
    """Use this for chapters.  Lessons within a big chapter
 
171
    should now use heading2 instead.  Chapters get numbered."""
 
172
    getStory().append(PageBreak())
 
173
    p = Paragraph('Chapter <seq id="Chapter"/> ' + quickfix(text), H1)
 
174
    getStory().append(p)
 
175
 
 
176
def Appendix1(text,):
 
177
    global appmode
 
178
    getStory().append(PageBreak())
 
179
    if not appmode:
 
180
        seq.setFormat('Chapter','A')
 
181
        seq.reset('Chapter')
 
182
        appmode = 1
 
183
    p = Paragraph('Appendix <seq id="Chapter"/> ' + quickfix(text), H1)
 
184
    getStory().append(p)
 
185
 
 
186
def heading2(text):
 
187
    """Used to be 'lesson'"""
 
188
    getStory().append(CondPageBreak(inch))
 
189
    p = Paragraph('<seq template="%(Chapter)s.%(Section+)s "/>' + quickfix(text), H2)
 
190
    getStory().append(p)
 
191
 
 
192
def heading3(text):
 
193
    """Used to be most of the plain old 'head' sections"""
 
194
    getStory().append(CondPageBreak(inch))
 
195
    p = Paragraph(quickfix(text), H3)
 
196
    getStory().append(p)
 
197
 
 
198
def image(path, width=None, height=None ):
 
199
    s = startKeep()
 
200
    space(.2)
 
201
    import reportlab
 
202
    rlDocImageDir = os.path.join(os.path.dirname(reportlab.__file__), 'docs','images')
 
203
    getStory().append(Image(os.path.join(rlDocImageDir,path),width,height))
 
204
    space(.2)
 
205
    endKeep(s)
 
206
 
 
207
def heading4(text):
 
208
    """Used to be most of the plain old 'head' sections"""
 
209
    getStory().append(CondPageBreak(inch))
 
210
    p = Paragraph(quickfix(text), H4)
 
211
    getStory().append(p)
 
212
 
 
213
def todo(text):
 
214
    """Used for notes to ourselves"""
 
215
    getStory().append(Paragraph(quickfix(text), Comment))
 
216
 
 
217
def centred(text):
 
218
    getStory().append(Paragraph(quickfix(text), Centred))
 
219
 
 
220
def caption(text):
 
221
    getStory().append(Paragraph(quickfix(text), Caption))
 
222
 
 
223
class Illustration(figures.Figure):
 
224
    """The examples are all presented as functions which do
 
225
    something to a canvas, with a constant height and width
 
226
    used.  This puts them inside a figure box with a caption."""
 
227
 
 
228
    def __init__(self, operation, caption, width=None, height=None):
 
229
        stdwidth, stdheight = examplefunctiondisplaysizes
 
230
        if not width:
 
231
            width = stdwidth
 
232
        if not height:
 
233
            height = stdheight
 
234
        #figures.Figure.__init__(self, stdwidth * 0.75, stdheight * 0.75)
 
235
        figures.Figure.__init__(self, width, height,
 
236
                    'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption))
 
237
        self.operation = operation
 
238
 
 
239
    def drawFigure(self):
 
240
        #shrink it a little...
 
241
        #self.canv.scale(0.75, 0.75)
 
242
        self.operation(self.canv)
 
243
 
 
244
 
 
245
def illust(operation, caption, width=None, height=None):
 
246
    i = Illustration(operation, caption, width=width, height=height)
 
247
    getStory().append(i)
 
248
 
 
249
 
 
250
class GraphicsDrawing(Illustration):
 
251
    """Lets you include reportlab/graphics drawings seamlessly,
 
252
    with the right numbering."""
 
253
    def __init__(self, drawing, caption):
 
254
        figures.Figure.__init__(self,
 
255
                                  drawing.width,
 
256
                                  drawing.height,
 
257
                    'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
 
258
                                  )
 
259
        self.drawing = drawing
 
260
 
 
261
    def drawFigure(self):
 
262
        d = self.drawing
 
263
        d.wrap(d.width, d.height)
 
264
        d.drawOn(self.canv, 0, 0)
 
265
 
 
266
def draw(drawing, caption):
 
267
    d = GraphicsDrawing(drawing, caption)
 
268
    getStory().append(d)
 
269
 
 
270
class ParaBox(figures.Figure):
 
271
    """Illustrates paragraph examples, with style attributes on the left"""
 
272
    descrStyle = ParagraphStyle('description',
 
273
                                fontName='Courier',
 
274
                                fontSize=8,
 
275
                                leading=9.6)
 
276
 
 
277
    def __init__(self, text, style, caption):
 
278
        figures.Figure.__init__(self, 0, 0, caption)
 
279
        self.text = text
 
280
        self.style = style
 
281
        self.para = Paragraph(text, style)
 
282
 
 
283
        styleText = self.getStyleText(style)
 
284
        self.pre = Preformatted(styleText, self.descrStyle)
 
285
 
 
286
    def wrap(self, availWidth, availHeight):
 
287
        """Left 30% is for attributes, right 50% for sample,
 
288
        10% gutter each side."""
 
289
        self.x0 = availWidth * 0.05  #left of box
 
290
        self.x1 = availWidth * 0.1   #left of descriptive text
 
291
        self.x2 = availWidth * 0.5   #left of para itself
 
292
        self.x3 = availWidth * 0.9   #right of para itself
 
293
        self.x4 = availWidth * 0.95  #right of box
 
294
        self.width = self.x4 - self.x0
 
295
        self.dx = 0.5 * (availWidth - self.width)
 
296
 
 
297
        paw, self.pah = self.para.wrap(self.x3 - self.x2, availHeight)
 
298
        self.pah = self.pah + self.style.spaceBefore + self.style.spaceAfter
 
299
        prw, self.prh = self.pre.wrap(self.x2 - self.x1, availHeight)
 
300
        self.figureHeight = max(self.prh, self.pah) * 10.0/9.0
 
301
        return figures.Figure.wrap(self, availWidth, availHeight)
 
302
 
 
303
    def getStyleText(self, style):
 
304
        """Converts style to preformatted block of text"""
 
305
        lines = []
 
306
        for (key, value) in style.__dict__.items():
 
307
            lines.append('%s = %s' % (key, value))
 
308
        lines.sort()
 
309
        return string.join(lines, '\n')
 
310
 
 
311
    def drawFigure(self):
 
312
 
 
313
        #now we fill in the bounding box and before/after boxes
 
314
        self.canv.saveState()
 
315
        self.canv.setFillGray(0.95)
 
316
        self.canv.setDash(1,3)
 
317
        self.canv.rect(self.x2 - self.x0,
 
318
                       self.figureHeight * 0.95 - self.pah,
 
319
                       self.x3-self.x2, self.para.height,
 
320
                       fill=1,stroke=1)
 
321
 
 
322
        self.canv.setFillGray(0.90)
 
323
        self.canv.rect(self.x2 - self.x0, #spaceBefore
 
324
                       self.figureHeight * 0.95 - self.pah + self.para.height,
 
325
                       self.x3-self.x2, self.style.spaceBefore,
 
326
                       fill=1,stroke=1)
 
327
 
 
328
        self.canv.rect(self.x2 - self.x0, #spaceBefore
 
329
                       self.figureHeight * 0.95 - self.pah - self.style.spaceAfter,
 
330
                       self.x3-self.x2, self.style.spaceAfter,
 
331
                       fill=1,stroke=1)
 
332
 
 
333
        self.canv.restoreState()
 
334
        #self.canv.setFillColor(colors.yellow)
 
335
        self.para.drawOn(self.canv, self.x2 - self.x0,
 
336
                         self.figureHeight * 0.95 - self.pah)
 
337
        self.pre.drawOn(self.canv, self.x1 - self.x0,
 
338
                         self.figureHeight * 0.95 - self.prh)
 
339
 
 
340
 
 
341
    def getStyleText(self, style):
 
342
        """Converts style to preformatted block of text"""
 
343
        lines = []
 
344
        for (key, value) in style.__dict__.items():
 
345
            if key not in ('name','parent'):
 
346
                lines.append('%s = %s' % (key, value))
 
347
        return string.join(lines, '\n')
 
348
 
 
349
 
 
350
class ParaBox2(figures.Figure):
 
351
    """Illustrates a paragraph side-by-side with the raw
 
352
    text, to show how the XML works."""
 
353
    def __init__(self, text, caption):
 
354
        figures.Figure.__init__(self, 0, 0, caption)
 
355
        descrStyle = ParagraphStyle('description',
 
356
                                fontName='Courier',
 
357
                                fontSize=8,
 
358
                                leading=9.6)
 
359
        textStyle = B
 
360
        self.text = text
 
361
        self.left = Paragraph('<![CDATA[' + text + ']]>', descrStyle)
 
362
        self.right = Paragraph(text, B)
 
363
 
 
364
 
 
365
    def wrap(self, availWidth, availHeight):
 
366
        self.width = availWidth * 0.9
 
367
        colWidth = 0.4 * self.width
 
368
        lw, self.lh = self.left.wrap(colWidth, availHeight)
 
369
        rw, self.rh = self.right.wrap(colWidth, availHeight)
 
370
        self.figureHeight = max(self.lh, self.rh) * 10.0/9.0
 
371
        return figures.Figure.wrap(self, availWidth, availHeight)
 
372
 
 
373
    def drawFigure(self):
 
374
        self.left.drawOn(self.canv,
 
375
                         self.width * 0.05,
 
376
                         self.figureHeight * 0.95 - self.lh
 
377
                         )
 
378
        self.right.drawOn(self.canv,
 
379
                         self.width * 0.55,
 
380
                         self.figureHeight * 0.95 - self.rh
 
381
                         )
 
382
 
 
383
def parabox(text, style, caption):
 
384
    p = ParaBox(text, style,
 
385
                'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
 
386
                )
 
387
    getStory().append(p)
 
388
 
 
389
def parabox2(text, caption):
 
390
    p = ParaBox2(text,
 
391
                'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
 
392
                )
 
393
    getStory().append(p)
 
394
 
 
395
def pencilnote():
 
396
    getStory().append(examples.NoteAnnotation())
 
397
 
 
398
 
 
399
from reportlab.lib.colors import tan, green
 
400
def handnote(xoffset=0, size=None, fillcolor=tan, strokecolor=green):
 
401
    getStory().append(examples.HandAnnotation(xoffset,size,fillcolor,strokecolor))
 
402
 
 
403
 
 
404
#make a singleton, created when requested rather
 
405
#than each time a chapter imports it.
 
406
_story = []
 
407
def setStory(story=[]):
 
408
    global _story
 
409
    _story = story
 
410
def getStory():
 
411
    return _story