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$ '''
9
This module contains utilities for generating guides
15
from rltemplate import RLDocTemplate
16
from stylesheet import getStyleSheet
17
styleSheet = getStyleSheet()
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
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>"
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
49
from string import join
50
for (template,subst) in [(QFcodetemplate, codesubst), (QFreptemplate, QFsubst)]:
56
(matches, index) = template.PARSE(fragment)
57
except: raise ValueError
59
[prefix, code] = matches
61
part = fragment[:index]
63
part = subst % (prefix, code)
65
fragment = fragment[index:]
67
parts.append(fragment)
68
text = join(parts, "")
70
#print quickfix("$testing$ testing $one$ ^two^ $three(^four^)$")
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']
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')
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)
101
def getJustFontPaths():
102
'''return afm and pfb for Just's files'''
104
folder = os.path.dirname(reportlab.__file__) + os.sep + 'fonts'
105
return os.path.join(folder, 'Wargames.afm'), os.path.join(folder, 'Wargames.pfb')
112
getStory().append(CondPageBreak(inches*inch))
115
getStory().append(PageBreak())
117
def nextTemplate(templName):
118
f = NextPageTemplate(templName)
121
def disc(text, klass=Paragraph, style=discussiontextstyle):
122
text = quickfix(text)
123
P = klass(text, style)
127
getSequencer().reset('list1')
129
def list(text, doBullet=1):
132
text='<bullet><seq id="list1"/>.</bullet>'+text
133
P = Paragraph(text, BU)
137
text='<bullet><font name="Symbol">'+chr(183)+'</font></bullet>' + quickfix(text)
138
P = Paragraph(text, BU)
141
def eg(text,before=0.1,after=0):
143
disc(text, klass=Preformatted, style=exampletextstyle)
146
def space(inches=1./6):
147
if inches: getStory().append(Spacer(0,inches*inch))
149
def EmbeddedCode(code,name='t'):
152
exec code+("\ngetStory().append(%s)\n"%name)
155
return len(getStory())
159
k = KeepTogether(S[s:])
163
"""Use this for the document title only"""
164
disc(text,style=styleSheet['Title'])
166
#AR 3/7/2000 - defining three new levels of headings; code
167
#should be swapped over to using them.
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)
176
def Appendix1(text,):
178
getStory().append(PageBreak())
180
seq.setFormat('Chapter','A')
183
p = Paragraph('Appendix <seq id="Chapter"/> ' + quickfix(text), H1)
187
"""Used to be 'lesson'"""
188
getStory().append(CondPageBreak(inch))
189
p = Paragraph('<seq template="%(Chapter)s.%(Section+)s "/>' + quickfix(text), H2)
193
"""Used to be most of the plain old 'head' sections"""
194
getStory().append(CondPageBreak(inch))
195
p = Paragraph(quickfix(text), H3)
198
def image(path, width=None, height=None ):
202
rlDocImageDir = os.path.join(os.path.dirname(reportlab.__file__), 'docs','images')
203
getStory().append(Image(os.path.join(rlDocImageDir,path),width,height))
208
"""Used to be most of the plain old 'head' sections"""
209
getStory().append(CondPageBreak(inch))
210
p = Paragraph(quickfix(text), H4)
214
"""Used for notes to ourselves"""
215
getStory().append(Paragraph(quickfix(text), Comment))
218
getStory().append(Paragraph(quickfix(text), Centred))
221
getStory().append(Paragraph(quickfix(text), Caption))
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."""
228
def __init__(self, operation, caption, width=None, height=None):
229
stdwidth, stdheight = examplefunctiondisplaysizes
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
239
def drawFigure(self):
240
#shrink it a little...
241
#self.canv.scale(0.75, 0.75)
242
self.operation(self.canv)
245
def illust(operation, caption, width=None, height=None):
246
i = Illustration(operation, caption, width=width, height=height)
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,
257
'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
259
self.drawing = drawing
261
def drawFigure(self):
263
d.wrap(d.width, d.height)
264
d.drawOn(self.canv, 0, 0)
266
def draw(drawing, caption):
267
d = GraphicsDrawing(drawing, caption)
270
class ParaBox(figures.Figure):
271
"""Illustrates paragraph examples, with style attributes on the left"""
272
descrStyle = ParagraphStyle('description',
277
def __init__(self, text, style, caption):
278
figures.Figure.__init__(self, 0, 0, caption)
281
self.para = Paragraph(text, style)
283
styleText = self.getStyleText(style)
284
self.pre = Preformatted(styleText, self.descrStyle)
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)
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)
303
def getStyleText(self, style):
304
"""Converts style to preformatted block of text"""
306
for (key, value) in style.__dict__.items():
307
lines.append('%s = %s' % (key, value))
309
return string.join(lines, '\n')
311
def drawFigure(self):
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,
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,
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,
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)
341
def getStyleText(self, style):
342
"""Converts style to preformatted block of text"""
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')
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',
361
self.left = Paragraph('<![CDATA[' + text + ']]>', descrStyle)
362
self.right = Paragraph(text, B)
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)
373
def drawFigure(self):
374
self.left.drawOn(self.canv,
376
self.figureHeight * 0.95 - self.lh
378
self.right.drawOn(self.canv,
380
self.figureHeight * 0.95 - self.rh
383
def parabox(text, style, caption):
384
p = ParaBox(text, style,
385
'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
389
def parabox2(text, caption):
391
'Figure <seq template="%(Chapter)s-%(Figure+)s"/>: ' + quickfix(caption)
396
getStory().append(examples.NoteAnnotation())
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))
404
#make a singleton, created when requested rather
405
#than each time a chapter imports it.
407
def setStory(story=[]):