summaryrefslogtreecommitdiff
path: root/bin/reportlab/platypus/xpreformatted.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/reportlab/platypus/xpreformatted.py')
-rw-r--r--bin/reportlab/platypus/xpreformatted.py316
1 files changed, 316 insertions, 0 deletions
diff --git a/bin/reportlab/platypus/xpreformatted.py b/bin/reportlab/platypus/xpreformatted.py
new file mode 100644
index 00000000000..6d18c99aba9
--- /dev/null
+++ b/bin/reportlab/platypus/xpreformatted.py
@@ -0,0 +1,316 @@
+#Copyright ReportLab Europe Ltd. 2000-2004
+#see license.txt for license details
+#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/xpreformatted.py
+__version__=''' $Id$ '''
+
+import string
+from types import StringType, ListType
+
+from reportlab.lib import PyFontify
+from paragraph import Paragraph, cleanBlockQuotedText, _handleBulletWidth, \
+ ParaLines, _getFragWords, stringWidth, _sameFrag
+from flowables import _dedenter
+
+
+def _getFragLines(frags):
+ lines = []
+ cline = []
+ W = frags[:]
+ while W != []:
+ w = W[0]
+ t = w.text
+ del W[0]
+ i = string.find(t,'\n')
+ if i>=0:
+ tleft = t[i+1:]
+ cline.append(w.clone(text=t[:i]))
+ lines.append(cline)
+ cline = []
+ if tleft!='':
+ W.insert(0,w.clone(text=tleft))
+ else:
+ cline.append(w)
+ if cline!=[]:
+ lines.append(cline)
+ return lines
+
+def _split_blPara(blPara,start,stop):
+ f = blPara.clone()
+ for a in ('lines', 'text'):
+ if hasattr(f,a): delattr(f,a)
+ f.lines = blPara.lines[start:stop]
+ return [f]
+
+# Will be removed shortly.
+def _countSpaces(text):
+ return string.count(text, ' ')
+## i = 0
+## s = 0
+## while 1:
+## j = string.find(text,' ',i)
+## if j<0: return s
+## s = s + 1
+## i = j + 1
+
+def _getFragWord(frags):
+ ''' given a fragment list return a list of lists
+ [size, spaces, (f00,w00), ..., (f0n,w0n)]
+ each pair f,w represents a style and some string
+ '''
+ W = []
+ n = 0
+ s = 0
+ for f in frags:
+ text = f.text[:]
+ W.append((f,text))
+ n = n + stringWidth(text, f.fontName, f.fontSize)
+
+ #s = s + _countSpaces(text)
+ s = s + string.count(text, ' ') # much faster for many blanks
+
+ #del f.text # we can't do this until we sort out splitting
+ # of paragraphs
+ return n, s, W
+
+
+class XPreformatted(Paragraph):
+ def __init__(self, text, style, bulletText = None, frags=None, caseSensitive=1, dedent=0):
+ self.caseSensitive = caseSensitive
+ cleaner = lambda text, dedent=dedent: string.join(_dedenter(text or '',dedent),'\n')
+ self._setup(text, style, bulletText, frags, cleaner)
+
+ def breakLines(self, width):
+ """
+ Returns a broken line structure. There are two cases
+
+ A) For the simple case of a single formatting input fragment the output is
+ A fragment specifier with
+ kind = 0
+ fontName, fontSize, leading, textColor
+ lines= A list of lines
+ Each line has two items.
+ 1) unused width in points
+ 2) a list of words
+
+ B) When there is more than one input formatting fragment the out put is
+ A fragment specifier with
+ kind = 1
+ lines= A list of fragments each having fields
+ extraspace (needed for justified)
+ fontSize
+ words=word list
+ each word is itself a fragment with
+ various settings
+
+ This structure can be used to easily draw paragraphs with the various alignments.
+ You can supply either a single width or a list of widths; the latter will have its
+ last item repeated until necessary. A 2-element list is useful when there is a
+ different first line indent; a longer list could be created to facilitate custom wraps
+ around irregular objects."""
+
+ if type(width) <> ListType: maxWidths = [width]
+ else: maxWidths = width
+ lines = []
+ lineno = 0
+ maxWidth = maxWidths[lineno]
+ style = self.style
+ fFontSize = float(style.fontSize)
+ requiredWidth = 0
+
+ #for bullets, work out width and ensure we wrap the right amount onto line one
+ _handleBulletWidth(self.bulletText,style,maxWidths)
+
+ self.height = 0
+ frags = self.frags
+ nFrags= len(frags)
+ if nFrags==1:
+ f = frags[0]
+ if hasattr(f,'text'):
+ fontSize = f.fontSize
+ fontName = f.fontName
+ kind = 0
+ L=string.split(f.text, '\n')
+ for l in L:
+ currentWidth = stringWidth(l,fontName,fontSize)
+ requiredWidth = max(currentWidth,requiredWidth)
+ extraSpace = maxWidth-currentWidth
+ lines.append((extraSpace,string.split(l,' '),currentWidth))
+ lineno = lineno+1
+ maxWidth = lineno<len(maxWidths) and maxWidths[lineno] or maxWidths[-1]
+ else:
+ kind = f.kind
+ lines = f.lines
+ for L in lines:
+ if kind==0:
+ currentWidth = L[2]
+ else:
+ currentWidth = L.currentWidth
+ requiredWidth = max(currentWidth,requiredWidth)
+
+ self.width = max(self.width,requiredWidth)
+ return f.clone(kind=kind, lines=lines)
+ elif nFrags<=0:
+ return ParaLines(kind=0, fontSize=style.fontSize, fontName=style.fontName,
+ textColor=style.textColor, lines=[])
+ else:
+ for L in _getFragLines(frags):
+ maxSize = 0
+ currentWidth, n, w = _getFragWord(L)
+ f = w[0][0]
+ maxSize = max(maxSize,f.fontSize)
+ words = [f.clone()]
+ words[-1].text = w[0][1]
+ for i in w[1:]:
+ f = i[0].clone()
+ f.text=i[1]
+ words.append(f)
+ maxSize = max(maxSize,f.fontSize)
+
+ lineno = lineno+1
+ maxWidth = lineno<len(maxWidths) and maxWidths[lineno] or maxWidths[-1]
+ requiredWidth = max(currentWidth,requiredWidth)
+ extraSpace = maxWidth - currentWidth
+ lines.append(ParaLines(extraSpace=extraSpace,wordCount=n, words=words, fontSize=maxSize, currentWidth=currentWidth))
+
+ self.width = max(self.width,requiredWidth)
+ return ParaLines(kind=1, lines=lines)
+
+ return lines
+
+ # we need this her to get the right splitter
+ def _get_split_blParaFunc(self):
+ return _split_blPara
+
+
+class PythonPreformatted(XPreformatted):
+ """Used for syntax-colored Python code, otherwise like XPreformatted.
+ """
+
+ formats = {
+ 'rest' : ('', ''),
+ 'comment' : ('<font color="green">', '</font>'),
+ 'keyword' : ('<font color="blue"><b>', '</b></font>'),
+ 'parameter' : ('<font color="black">', '</font>'),
+ 'identifier' : ('<font color="red">', '</font>'),
+ 'string' : ('<font color="gray">', '</font>') }
+
+ def __init__(self, text, style, bulletText = None, dedent=0, frags=None):
+ if text:
+ text = self.fontify(self.escapeHtml(text))
+ apply(XPreformatted.__init__,
+ (self, text, style),
+ {'bulletText':bulletText, 'dedent':dedent, 'frags':frags})
+
+ def escapeHtml(self, text):
+ s = string.replace(text, '&', '&amp;')
+ s = string.replace(s, '<', '&lt;')
+ s = string.replace(s, '>', '&gt;')
+ return s
+
+ def fontify(self, code):
+ "Return a fontified version of some Python code."
+
+ if code[0] == '\n':
+ code = code[1:]
+
+ tags = PyFontify.fontify(code)
+ fontifiedCode = ''
+ pos = 0
+ for k, i, j, dummy in tags:
+ fontifiedCode = fontifiedCode + code[pos:i]
+ s, e = self.formats[k]
+ fontifiedCode = fontifiedCode + s + code[i:j] + e
+ pos = j
+
+ fontifiedCode = fontifiedCode + code[pos:]
+
+ return fontifiedCode
+
+
+if __name__=='__main__': #NORUNTESTS
+ def dumpXPreformattedLines(P):
+ print '\n############dumpXPreforemattedLines(%s)' % str(P)
+ lines = P.blPara.lines
+ n =len(lines)
+ for l in range(n):
+ line = lines[l]
+ words = line.words
+ nwords = len(words)
+ print 'line%d: %d(%d)\n ' % (l,nwords,line.wordCount),
+ for w in range(nwords):
+ print "%d:'%s'"%(w,words[w].text),
+ print
+
+ def dumpXPreformattedFrags(P):
+ print '\n############dumpXPreforemattedFrags(%s)' % str(P)
+ frags = P.frags
+ n =len(frags)
+ for l in range(n):
+ print "frag%d: '%s'" % (l, frags[l].text)
+
+ l = 0
+ for L in _getFragLines(frags):
+ n=0
+ for W in _getFragWords(L):
+ print "frag%d.%d: size=%d" % (l, n, W[0]),
+ n = n + 1
+ for w in W[1:]:
+ print "'%s'" % w[1],
+ print
+ l = l + 1
+
+ def try_it(text,style,dedent,aW,aH):
+ P=XPreformatted(text,style,dedent=dedent)
+ dumpXPreformattedFrags(P)
+ w,h = P.wrap(aW, aH)
+ dumpXPreformattedLines(P)
+ S = P.split(aW,aH)
+ dumpXPreformattedLines(P)
+ for s in S:
+ s.wrap(aW,aH)
+ dumpXPreformattedLines(s)
+ aH = 500
+
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
+ styleSheet = getSampleStyleSheet()
+ B = styleSheet['BodyText']
+ DTstyle = ParagraphStyle("discussiontext", parent=B)
+ DTstyle.fontName= 'Helvetica'
+ for (text,dedent,style, aW, aH, active) in [('''
+
+
+The <font name=courier color=green>CMYK</font> or subtractive
+
+method follows the way a printer
+mixes three pigments (cyan, magenta, and yellow) to form colors.
+Because mixing chemicals is more difficult than combining light there
+is a fourth parameter for darkness. For example a chemical
+combination of the <font name=courier color=green>CMY</font> pigments generally never makes a perfect
+
+black -- instead producing a muddy color -- so, to get black printers
+don't use the <font name=courier color=green>CMY</font> pigments but use a direct black ink. Because
+<font name=courier color=green>CMYK</font> maps more directly to the way printer hardware works it may
+be the case that &amp;| &amp; | colors specified in <font name=courier color=green>CMYK</font> will provide better fidelity
+and better control when printed.
+
+
+''',0,DTstyle, 456.0, 42.8, 0),
+('''
+
+ This is a non rearranging form of the <b>Paragraph</b> class;
+ <b><font color=red>XML</font></b> tags are allowed in <i>text</i> and have the same
+
+ meanings as for the <b>Paragraph</b> class.
+ As for <b>Preformatted</b>, if dedent is non zero <font color=red size=+1>dedent</font>
+ common leading spaces will be removed from the
+ front of each line.
+
+''',3, DTstyle, 456.0, 42.8, 0),
+("""\
+ <font color=blue>class </font><font color=red>FastXMLParser</font>:
+ # Nonsense method
+ def nonsense(self):
+ self.foo = 'bar'
+""",0, styleSheet['Code'], 456.0, 4.8, 1),
+]:
+ if active: try_it(text,style,dedent,aW,aH)