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$ '''
7
from types import StringType, ListType
9
from reportlab.lib import PyFontify
10
from paragraph import Paragraph, cleanBlockQuotedText, _handleBulletWidth, \
11
ParaLines, _getFragWords, stringWidth, _sameFrag
12
from flowables import _dedenter
15
def _getFragLines(frags):
23
i = string.find(t,'\n')
26
cline.append(w.clone(text=t[:i]))
30
W.insert(0,w.clone(text=tleft))
37
def _split_blPara(blPara,start,stop):
39
for a in ('lines', 'text'):
40
if hasattr(f,a): delattr(f,a)
41
f.lines = blPara.lines[start:stop]
44
# Will be removed shortly.
45
def _countSpaces(text):
46
return string.count(text, ' ')
50
## j = string.find(text,' ',i)
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
66
n = n + stringWidth(text, f.fontName, f.fontSize)
68
#s = s + _countSpaces(text)
69
s = s + string.count(text, ' ') # much faster for many blanks
71
#del f.text # we can't do this until we sort out splitting
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)
82
def breakLines(self, width):
84
Returns a broken line structure. There are two cases
86
A) For the simple case of a single formatting input fragment the output is
87
A fragment specifier with
89
fontName, fontSize, leading, textColor
90
lines= A list of lines
91
Each line has two items.
92
1) unused width in points
95
B) When there is more than one input formatting fragment the out put is
96
A fragment specifier with
98
lines= A list of fragments each having fields
99
extraspace (needed for justified)
102
each word is itself a fragment with
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."""
111
if type(width) <> ListType: maxWidths = [width]
112
else: maxWidths = width
115
maxWidth = maxWidths[lineno]
117
fFontSize = float(style.fontSize)
120
#for bullets, work out width and ensure we wrap the right amount onto line one
121
_handleBulletWidth(self.bulletText,style,maxWidths)
128
if hasattr(f,'text'):
129
fontSize = f.fontSize
130
fontName = f.fontName
132
L=string.split(f.text, '\n')
134
currentWidth = stringWidth(l,fontName,fontSize)
135
requiredWidth = max(currentWidth,requiredWidth)
136
extraSpace = maxWidth-currentWidth
137
lines.append((extraSpace,string.split(l,' '),currentWidth))
139
maxWidth = lineno<len(maxWidths) and maxWidths[lineno] or maxWidths[-1]
147
currentWidth = L.currentWidth
148
requiredWidth = max(currentWidth,requiredWidth)
150
self.width = max(self.width,requiredWidth)
151
return f.clone(kind=kind, lines=lines)
153
return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName,
154
textColor=style.textColor, lines=[])
156
for L in _getFragLines(frags):
158
currentWidth, n, w = _getFragWord(L)
160
maxSize = max(maxSize,f.fontSize)
162
words[-1].text = w[0][1]
167
maxSize = max(maxSize,f.fontSize)
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))
175
self.width = max(self.width,requiredWidth)
176
return ParaLines(kind=1, lines=lines)
180
# we need this her to get the right splitter
181
def _get_split_blParaFunc(self):
185
class PythonPreformatted(XPreformatted):
186
"""Used for syntax-colored Python code, otherwise like XPreformatted.
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>') }
197
def __init__(self, text, style, bulletText = None, dedent=0, frags=None):
199
text = self.fontify(self.escapeHtml(text))
200
apply(XPreformatted.__init__,
202
{'bulletText':bulletText, 'dedent':dedent, 'frags':frags})
204
def escapeHtml(self, text):
205
s = string.replace(text, '&', '&')
206
s = string.replace(s, '<', '<')
207
s = string.replace(s, '>', '>')
210
def fontify(self, code):
211
"Return a fontified version of some Python code."
216
tags = PyFontify.fontify(code)
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
225
fontifiedCode = fontifiedCode + code[pos:]
230
if __name__=='__main__': #NORUNTESTS
231
def dumpXPreformattedLines(P):
232
print '\n############dumpXPreforemattedLines(%s)' % str(P)
233
lines = P.blPara.lines
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),
244
def dumpXPreformattedFrags(P):
245
print '\n############dumpXPreforemattedFrags(%s)' % str(P)
249
print "frag%d: '%s'" % (l, frags[l].text)
252
for L in _getFragLines(frags):
254
for W in _getFragWords(L):
255
print "frag%d.%d: size=%d" % (l, n, W[0]),
262
def try_it(text,style,dedent,aW,aH):
263
P=XPreformatted(text,style,dedent=dedent)
264
dumpXPreformattedFrags(P)
266
dumpXPreformattedLines(P)
268
dumpXPreformattedLines(P)
271
dumpXPreformattedLines(s)
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 [('''
282
The <font name=courier color=green>CMYK</font> or subtractive
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
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 &| & | colors specified in <font name=courier color=green>CMYK</font> will provide better fidelity
294
and better control when printed.
297
''',0,DTstyle, 456.0, 42.8, 0),
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
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
308
''',3, DTstyle, 456.0, 42.8, 0),
310
<font color=blue>class </font><font color=red>FastXMLParser</font>:
314
""",0, styleSheet['Code'], 456.0, 4.8, 1),
316
if active: try_it(text,style,dedent,aW,aH)