#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: xpreformatted.py 2426 2004-09-02 11:52:56Z rgbecker $ ''' 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', ''), 'keyword' : ('', ''), 'parameter' : ('', ''), 'identifier' : ('', ''), 'string' : ('', '') } 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, '&', '&') s = string.replace(s, '<', '<') s = string.replace(s, '>', '>') 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 CMYK 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 CMY pigments generally never makes a perfect black -- instead producing a muddy color -- so, to get black printers don't use the CMY pigments but use a direct black ink. Because CMYK maps more directly to the way printer hardware works it may be the case that &| & | colors specified in CMYK will provide better fidelity and better control when printed. ''',0,DTstyle, 456.0, 42.8, 0), (''' This is a non rearranging form of the Paragraph class; XML tags are allowed in text and have the same meanings as for the Paragraph class. As for Preformatted, if dedent is non zero dedent common leading spaces will be removed from the front of each line. ''',3, DTstyle, 456.0, 42.8, 0), ("""\ class FastXMLParser: # 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)