1 Index: lib/rparsexml.py
2 ===================================================================
3 RCS file: /cvsroot/reportlab/reportlab/lib/rparsexml.py,v
4 retrieving revision 1.2
5 diff -u -r1.2 rparsexml.py
6 --- lib/rparsexml.py 4 Nov 2002 00:11:48 -0000 1.2
7 +++ lib/rparsexml.py 28 May 2003 19:45:52 -0000
9 # raise ValueError, "I don't handle ampersands yet!!!"
13 - #if verbose: print "no tags"
14 - if toplevel is not None:
15 - #D = {NAMEKEY: NONAME, CONTENTSKEY: [xmltext[cursor:]]}
16 - ContentList = [xmltext[cursor:]]
17 - ContentList = unEscapeContentList(ContentList)
18 - return (NameString, AttDict, ContentList, ExtraStuff)
20 - raise ValueError, "no tags at non-toplevel %s" % `xmltext[cursor:cursor+20]`
22 + #if verbose: print "no tags"
23 + if toplevel is not None:
24 + #D = {NAMEKEY: NONAME, CONTENTSKEY: [xmltext[cursor:]]}
25 + ContentList = [xmltext[cursor:]]
26 + ContentList = unEscapeContentList(ContentList)
27 + return ((NameString, AttDict, ContentList, ExtraStuff), cursor)
29 + raise ValueError, "no tags at non-toplevel %s" % `xmltext[cursor:cursor+20]`
33 Index: pdfgen/canvas.py
34 ===================================================================
35 RCS file: /cvsroot/reportlab/reportlab/pdfgen/canvas.py,v
36 retrieving revision 1.111
37 diff -u -r1.111 canvas.py
38 --- pdfgen/canvas.py 10 Apr 2003 00:01:17 -0000 1.111
39 +++ pdfgen/canvas.py 28 May 2003 19:45:54 -0000
41 is to keep the user's current zoom settings. the last
42 arguments may or may not be needed depending on the
46 Fit types and the other arguments they use are:
47 /XYZ left top zoom - fine grained control. null
48 or zero for any of the parameters means 'leave
49 as is', so "0,0,0" will keep the reader's settings.
50 NB. Adobe Reader appears to prefer "null" to 0's.
53 /Fit - entire page fits in window
55 /FitH top - top coord at top of window, width scaled
58 /FitV left - left coord at left of window, height
62 /FitR left bottom right top - scale window to fit
63 the specified rectangle
72 dest.xyz(left,top,zoom)
73 elif fitType == "Fit":
75 elif fitType == "FitBV":
78 - raise "Unknown Fit type %s" % (fitType,)
79 + raise "Unknown Fit type %s" % (fitType,)
85 #This method should probably be deprecated since it is just a sub-set of bookmarkPage
86 return self.bookmarkPage(key,fitType="FitH",top=yhorizontal)
89 def bookmarkHorizontal(self, key, relativeX, relativeY):
90 """w.r.t. the current transformation, bookmark this horizontal."""
91 (xt, yt) = self.absolutePosition(relativeX,relativeY)
93 assert rot % 90.0 == 0.0, "Rotation must be a multiple of 90 degrees"
94 self._pageRotation = rot
98 def addLiteral(self, s, escaped=1):
99 """introduce the literal text of PDF operations s into the current stream.
100 Only use this if you are an expert in the PDF file format."""
101 Index: platypus/para.py
102 ===================================================================
103 RCS file: /cvsroot/reportlab/reportlab/platypus/para.py,v
104 retrieving revision 1.6
105 diff -u -r1.6 para.py
106 --- platypus/para.py 9 Apr 2003 22:58:37 -0000 1.6
107 +++ platypus/para.py 28 May 2003 19:45:55 -0000
109 from reportlab.platypus.flowables import Flowable
110 from reportlab.lib import colors
113 +from types import StringType, UnicodeType, InstanceType, TupleType, ListType, FloatType
114 +from string import letters as LETTERS, whitespace as WHITESPACE
116 # SET THIS TO CAUSE A VIEWING BUG WITH ACROREAD 3 (for at least one input)
120 self.lineOpHandlers = [] # for handling underlining and hyperlinking, etc
121 self.program = program
123 self.indent = self.rightIndent = 0.0
124 self.baseindent = 0.0 # adjust this to add more indentation for bullets, eg
125 self.fontName = "Helvetica"
126 @@ -102,10 +102,12 @@
127 from reportlab.lib.enums import TA_LEFT
128 self.alignment = TA_LEFT
129 self.textStateStack = []
131 TEXT_STATE_VARIABLES = ("indent", "rightIndent", "fontName", "fontSize",
132 "leading", "fontColor", "lineOpHandlers", "rise",
136 def pushTextState(self):
138 for var in self.TEXT_STATE_VARIABLES:
140 #print "push", self.textStateStack
141 #print "push", len(self.textStateStack), state
144 def popTextState(self):
145 state = self.textStateStack[-1]
146 self.textStateStack = self.textStateStack[:-1]
148 remainder = program[:]
149 #program1 = remainder[:] # debug only
151 - from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
152 #if maxheight<TOOSMALLSPACE:
153 # raise ValueError, "attempt to format inside too small a height! "+repr(maxheight)
154 heightremaining = maxheight-leading
156 linewidth = maxwidth - indent - rightIndent
157 beforelinestate = self.__dict__.copy()
158 if linewidth<TOOSMALLSPACE:
159 - raise ValueError, "indents %s %s too wide for space %s" % (self.indent, self.rightIndent, maxwidth)
160 + raise ValueError, "indents %s %s too wide for space %s" % (self.indent, self.rightIndent, \
163 - (lineIsFull, line, cursor, currentLength, usedIndent, maxLength, justStrings) = self.fitLine(remainder, maxwidth)
164 + (lineIsFull, line, cursor, currentLength, \
165 + usedIndent, maxLength, justStrings) = self.fitLine(remainder, maxwidth)
167 ## print "failed to fit line near", cursorcount # debug
168 ## for i in program1[max(0,cursorcount-10): cursorcount]:
169 @@ -235,20 +239,23 @@
170 self.__dict__.update(startstate)
171 heightused = maxheight - heightremaining
172 return (lineprogram, remainder, laststate, heightused)
176 return self.__dict__.copy()
178 def resetState(self, state):
180 self.__dict__.update(state)
182 ## def sizeOfWord(self, word):
183 ## inlineThisFunctionForEfficiency
184 ## return float(stringWidth(word, self.fontName, self.fontSize))
186 def fitLine(self, program, totalLength):
187 "fit words (and other things) onto a line"
188 # assuming word lengths and spaces have not been yet added
189 # fit words onto a line up to maxlength, adding spaces and respecting extra space
190 - from types import StringType, TupleType, InstanceType, FloatType
191 from reportlab.pdfbase.pdfmetrics import stringWidth
192 usedIndent = self.indent
193 maxLength = totalLength - usedIndent - self.rightIndent
195 opcode = program[cursor]
196 #if debug: print "opcode", cursor, opcode
197 topcode = type(opcode)
198 - if topcode is StringType or topcode is InstanceType:
199 + if topcode in (StringType, UnicodeType, InstanceType):
200 lastneedspace = needspace
202 if topcode is InstanceType:
207 - opcode = opcode.strip() #string.strip(opcode)
208 + opcode = opcode.strip()
210 width = stringWidth(opcode, fontName, fontSize)
213 oldcolor = self.fontColor
214 (i, colorname) = opcode
215 #print "opcode", opcode
216 - if type(colorname) is StringType:
217 + if type(colorname) in (StringType, UnicodeType):
218 color = self.fontColor = getattr(colors, colorname)
220 color = self.fontColor = colorname # assume its something sensible :)
223 (i, fontsize) = opcode
224 size = abs(float(fontsize))
225 - if type(fontsize) is StringType:
226 + if type(fontsize) in (StringType, UnicodeType):
227 if fontsize[:1]=="+":
228 fontSize = self.fontSize = self.fontSize + size
229 elif fontsize[:1]=="-":
230 @@ -457,41 +464,43 @@
231 line.append( ("nextLine", 0) )
232 #print "fitline", line
233 return (lineIsFull, line, cursor, currentLength, usedIndent, maxLength, justStrings)
235 def centerAlign(self, line, lineLength, maxLength):
236 diff = maxLength-lineLength
238 if shift>TOOSMALLSPACE:
239 return self.insertShift(line, shift)
242 def rightAlign(self, line, lineLength, maxLength):
243 shift = maxLength-lineLength
245 if shift>TOOSMALLSPACE:
246 return self.insertShift(line, shift)
249 def insertShift(self, line, shift):
250 # insert shift just before first visible element in line
251 - from types import StringType, InstanceType
256 - if first and (te is StringType or te is InstanceType):
257 + if first and (te in (StringType, UnicodeType, InstanceType)):
263 def justifyAlign(self, line, lineLength, maxLength):
264 diff = maxLength-lineLength
265 # count EXPANDABLE SPACES AFTER THE FIRST VISIBLE
266 - from types import InstanceType, StringType, TupleType, FloatType
271 if te is FloatType and e>TOOSMALLSPACE and visible:
272 spacecount = spacecount+1
273 - elif te is StringType or te is InstanceType:
274 + elif te in (StringType, UnicodeType, InstanceType):
276 #if debug: print "diff is", diff, "wordcount", wordcount #; die
282 - if (te is InstanceType or te is StringType):
283 + if (te in (StringType, UnicodeType, InstanceType)):
285 elif te is FloatType and e>TOOSMALLSPACE and visible:
287 @@ -545,25 +554,23 @@
292 def shrinkWrap(self, line):
293 # for non justified text, collapse adjacent text/shift's into single operations
294 - #return line # for testing
298 - from types import FloatType, StringType, InstanceType
299 - from string import join
300 while index<maxindex:
303 - if te is StringType and index<maxindex-1:
304 + if te in (StringType, UnicodeType) and index<maxindex-1:
305 # collect strings and floats
311 - while index<maxindex and (tnexte is FloatType or tnexte is StringType):
312 + while index<maxindex and (tnexte in (FloatType, StringType, UnicodeType)):
313 # switch to expandable space if appropriate
314 if tnexte is FloatType:
315 if thefloats<0 and nexte>0:
316 @@ -571,14 +578,14 @@
317 if nexte<0 and thefloats>0:
319 thefloats = thefloats + nexte
320 - elif tnexte is StringType:
321 + elif tnexte in (StringType, UnicodeType):
322 thestrings.append(nexte)
328 - s = string.join(thestrings)
329 + s = ' '.join(thestrings)
331 result.append(float(thefloats))
332 # back up for unhandled element
333 @@ -588,12 +595,12 @@
338 def cleanProgram(self, line):
339 "collapse adjacent spacings"
340 #return line # for debugging
343 - from types import FloatType, TupleType, StringType, InstanceType
345 if type(e) is FloatType:
346 # switch to expandable space if appropriate
350 # don't swap visibles
351 - if tthis is StringType or tnext is StringType or this is InstanceType or tnext is InstanceType:
352 + if tthis in (StringType, UnicodeType) or \
353 + tnext in (StringType, UnicodeType) or \
354 + this is InstanceType or tnext is InstanceType:
356 # only swap two tuples if the second one is an end operation and the first is something else
357 elif tthis is TupleType:
358 @@ -654,10 +663,10 @@
359 result[nextindex] = this
363 def runOpCodes(self, program, canvas, textobject):
366 - from types import StringType, TupleType, InstanceType, FloatType
368 escape = canvas._escape
369 code = textobject._code
370 startstate = self.__dict__.copy()
373 for opcode in program:
374 topcode = type(opcode)
375 - if topcode is StringType or topcode is InstanceType:
376 + if topcode in (StringType, UnicodeType, InstanceType):
378 if abs(thislineindent)>TOOSMALLSPACE:
379 #if debug: print "INDENTING", thislineindent
383 textobject.setFont(font, size)
384 - if topcode is StringType:
385 + if topcode in (StringType, UnicodeType):
386 #textobject.textOut(opcode)
387 text = escape(opcode)
388 code.append('(%s) Tj' % text)
390 oldcolor = self.fontColor
391 (i, colorname) = opcode
392 #print "opcode", opcode
393 - if type(colorname) is StringType:
394 + if type(colorname) in (StringType, UnicodeType):
395 color = self.fontColor = getattr(colors, colorname)
397 color = self.fontColor = colorname # assume its something sensible :)
400 (i, fontsize) = opcode
401 size = abs(float(fontsize))
402 - if type(fontsize) is StringType:
403 + if type(fontsize) in (StringType, UnicodeType):
404 if fontsize[:1]=="+":
405 fontSize = self.fontSize = self.fontSize + size
406 elif fontsize[:1]=="-":
407 @@ -834,12 +843,12 @@
409 def stringLine(line, length):
410 "simple case: line with just strings and spacings which can be ignored"
413 - from types import StringType
415 - if type(x) is StringType:
416 + if type(x) in (StringType, UnicodeType):
418 - text = string.join(strings)
419 + text = ' '.join(strings)
420 result = [text, float(length)]
421 nextlinemark = ("nextLine", 0)
422 if line and line[-1]==nextlinemark:
423 @@ -848,14 +857,14 @@
425 def simpleJustifyAlign(line, currentLength, maxLength):
426 "simple justification with only strings"
429 - from types import StringType
431 - if type(x) is StringType:
432 + if type(x) in (StringType, UnicodeType):
434 nspaces = len(strings)-1
435 slack = maxLength-currentLength
436 - text = string.join(strings)
437 + text = ' '.join(strings)
438 if nspaces>0 and slack>0:
439 wordspacing = slack/float(nspaces)
440 result = [("wordSpacing", wordspacing), text, maxLength, ("wordSpacing", 0)]
441 @@ -869,16 +878,15 @@
442 from reportlab.lib.colors import black
445 - if string.upper(text) in ("Y", "YES", "TRUE", "1"):
446 + if text.upper() in ("Y", "YES", "TRUE", "1"):
448 - elif string.upper(text) in ("N", "NO", "FALSE", "0"):
449 + elif text.upper() in ("N", "NO", "FALSE", "0"):
452 raise RMLError, "true/false attribute has illegal value '%s'" % text
454 def readAlignment(text):
455 - from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
456 - up = string.upper(text)
461 @@ -891,13 +899,13 @@
462 def readLength(text):
463 """Read a dimension measurement: accept "3in", "5cm",
464 "72 pt" and so on."""
465 - text = string.strip(text)
466 + text = text.strip()
470 - text = string.lower(text)
471 + text = text.lower()
472 numberText, units = text[:-2],text[-2:]
473 - numberText = string.strip(numberText)
474 + numberText = numberText.strip()
476 number = float(numberText)
478 @@ -916,13 +924,12 @@
480 def lengthSequence(s, converter=readLength):
481 """from "(2, 1)" or "2,1" return [2,1], for example"""
482 - from string import split, strip
485 if s[:1]=="(" and s[-1:]==")":
488 - sl = map(strip, sl)
489 - sl = map(converter, sl)
491 + sl = [s.strip() for s in sl]
492 + sl = [converter(s) for s in sl]
499 from reportlab.lib import colors
500 - if text[0] in string.letters:
501 + if text[0] in LETTERS:
502 return colors.__dict__[text]
503 tup = lengthSequence(text)
510 def __init__(self, name, parent=None, **kw):
511 mydict = self.__dict__
515 for (a,b) in kw.items():
518 def addAttributes(self, dictionary):
519 for key in dictionary.keys():
520 value = dictionary[key]
521 @@ -999,14 +1008,21 @@
522 "h1.defaultStyle": "Heading1",
523 "h2.defaultStyle": "Heading2",
524 "h3.defaultStyle": "Heading3",
525 + "h4.defaultStyle": "Heading4",
526 + "h5.defaultStyle": "Heading5",
527 + "h6.defaultStyle": "Heading6",
528 "title.defaultStyle": "Title",
529 + "subtitle.defaultStyle": "SubTitle",
530 "para.defaultStyle": "Normal",
531 "pre.defaultStyle": "Code",
532 - "li.defaultStyle": "Definition"
533 + "ul.defaultStyle": "Definition",
534 + "ol.defaultStyle": "Definition",
535 + "li.defaultStyle": "Definition",
538 class FastPara(Flowable):
539 "paragraph with no special features (not even a single ampersand!)"
541 def __init__(self, style, simpletext):
543 # print "FAST", id(self)
544 @@ -1015,6 +1031,7 @@
546 self.simpletext = simpletext
549 def wrap(self, availableWidth, availableHeight):
550 simpletext = self.simpletext
551 self.availableWidth = availableWidth
552 @@ -1027,7 +1044,7 @@
553 size = style.fontSize
554 firstindent = style.firstLineIndent
555 #textcolor = style.textColor
556 - words = string.split(simpletext)
557 + words = simpletext.split()
559 from reportlab.pdfbase.pdfmetrics import stringWidth
560 spacewidth = stringWidth(" ", font, size)
561 @@ -1062,18 +1079,18 @@
562 #print "currentline", currentline
565 - lines.append( (string.join(currentline), currentlength, len(currentline)) )
566 + lines.append( (' '.join(currentline), currentlength, len(currentline)) )
569 heightused = heightused+leading
570 if heightused+leading>availableHeight:
572 if currentlength and not done:
573 - lines.append( (string.join(currentline), currentlength, len(currentline) ))
574 + lines.append( (' '.join(currentline), currentlength, len(currentline) ))
575 heightused = heightused+leading
577 self.height = heightused
578 - remainder = self.remainder = string.join(words[cursor:])
579 + remainder = self.remainder = ' '.join(words[cursor:])
580 #print "lines", lines
581 #print "remainder is", remainder
583 @@ -1086,6 +1103,7 @@
584 result = (availableWidth, heightused)
585 #if debug: print "wrap is", (availableWidth, availableHeight), result, len(lines)
588 def split(self, availableWidth, availableHeight):
590 leading = style.leading
591 @@ -1102,7 +1120,6 @@
595 - from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
598 rightIndent = style.rightIndent
599 @@ -1158,10 +1175,12 @@
600 #textobject.textOut(text)
602 c.drawText(textobject)
604 def getSpaceBefore(self):
606 # print "got space before", self.spaceBefore
607 return self.style.spaceBefore
609 def getSpaceAfter(self):
610 #print "got space after", self.spaceAfter
611 return self.style.spaceAfter
612 @@ -1174,15 +1193,39 @@
613 result[stylenamekey] = styles[stylenamevalue]
616 +def buildContext(stylesheet=None):
618 + from reportlab.lib.styles import getSampleStyleSheet
619 + from reportlab.lib.styles import StyleSheet1
620 + if stylesheet is not None:
621 + if isinstance(stylesheet, StyleSheet1):
622 + result.update(stylesheet.byName.copy())
623 + result.update(stylesheet.byAlias.copy())
625 + if hasattr(stylesheet, 'copy'):
626 + result.update(stylesheet.copy())
629 + styles = getSampleStyleSheet()
630 + for (stylenamekey, stylenamevalue) in DEFAULT_ALIASES.items():
631 + # Copy styles with the same name as aliases
632 + if stylesheet.has_key(stylenamevalue):
633 + result[stylenamekey] = stylesheet[stylenamevalue]
634 + # Then, fill in defaults if they were not filled yet.
635 + if not result.has_key(stylenamekey) and styles.has_key(stylenamevalue):
636 + result[stylenamekey] = styles[stylenamevalue]
640 class Para(Flowable):
645 def __init__(self, style, parsedText=None, bulletText=None, state=None, context=None, baseindent=0):
646 #print id(self), "para", parsedText
647 self.baseindent = baseindent
648 - if context is None:
649 - context = defaultContext()
650 - self.context = context
651 + self.context = buildContext(context)
652 self.parsedText = parsedText
653 self.bulletText = bulletText
654 self.style1 = style # make sure Flowable doesn't use this unless wanted! call it style1 NOT style
655 @@ -1199,15 +1242,18 @@
656 # print "spaceBefore is", self.spaceBefore, self.parsedText
659 - self.face = "times"
661 + self.face = style.fontName
662 + self.size = style.fontSize
664 def getSpaceBefore(self):
666 # print "got space before", self.spaceBefore
667 return self.spaceBefore
669 def getSpaceAfter(self):
670 #print "got space after", self.spaceAfter
671 return self.spaceAfter
673 def wrap(self, availableWidth, availableHeight):
675 print "WRAPPING", id(self), availableWidth, availableHeight
676 @@ -1242,7 +1288,8 @@
678 self.program = program = self.compileProgram(parsedText)
679 if not self.formattedProgram:
680 - (formattedProgram, remainder, laststate, heightused) = p.format(availableWidth, availableHeight, program, leading)
681 + (formattedProgram, remainder, \
682 + laststate, heightused) = p.format(availableWidth, availableHeight, program, leading)
683 self.formattedProgram = formattedProgram
684 self.height = heightused
685 self.laststate = laststate
686 @@ -1259,7 +1306,8 @@
687 height = availableHeight + 1
688 #print "laststate is", laststate
689 #print "saving remainder", remainder
690 - self.remainder = Para(self.style1, parsedText=None, bulletText=None, state=laststate)
691 + self.remainder = Para(self.style1, parsedText=None, bulletText=None, \
692 + state=laststate, context=self.context)
693 self.remainder.program = remainder
694 self.remainder.spaceAfter = self.spaceAfter
696 @@ -1277,6 +1325,7 @@
697 print "exact match???" + repr(availableHeight, h)
698 print "wrap is", (availableWidth, availableHeight), result
701 def split(self, availableWidth, availableHeight):
703 # print "SPLITTING", id(self), availableWidth, availableHeight
704 @@ -1300,6 +1349,7 @@
706 #if debug: print "split is", result
710 p = self.myengine #paragraphEngine()
711 formattedProgram = self.formattedProgram
712 @@ -1362,40 +1412,15 @@
713 # now look for a place where to insert the unindent after the first line
714 if style.firstLineIndent:
716 - from types import StringType, InstanceType
720 - if tx is StringType or tx is InstanceType:
721 + if tx in (StringType, UnicodeType, InstanceType):
723 program.insert( count, ("indent", -style.firstLineIndent ) ) # defaults to end if no visibles
724 - #print "="*8, id(self), "program is"
728 -## # check pushes and pops
731 -## from types import TupleType
732 -## for x in program:
735 -## if type(x) is TupleType:
738 -## stackcount = stackcount+1
739 -## print " "*stackcount, "push", stackcount
741 -## stackcount = stackcount-1
742 -## print " "*stackcount, "pop", stackcount
745 -## print "STACK UNDERFLOW!"
749 def linearize(self, program = None, parsedText=None):
750 - #print "LINEARIZING", self
751 - #program = self.program = []
752 if parsedText is None:
753 parsedText = self.parsedText
755 @@ -1417,23 +1442,22 @@
756 program.append( ("leading", 0) )
757 program.append( ("nextLine", 0) )
758 program.append( ("pop",) )
760 def compileComponent(self, parsedText, program):
762 ttext = type(parsedText)
763 - #program = self.program
764 - if ttext is types.StringType:
765 + if ttext in (StringType, UnicodeType):
766 # handle special characters here...
769 - stext = parsedText.strip() #string.strip(parsedText)
770 + stext = parsedText.strip()
772 program.append(" ") # contract whitespace to single space
774 handleSpecialCharacters(self, parsedText, program)
775 - elif ttext is types.ListType:
776 + elif ttext is ListType:
778 self.compileComponent(e, program)
779 - elif ttext is types.TupleType:
780 + elif ttext is TupleType:
781 (tagname, attdict, content, extra) = parsedText
784 @@ -1455,10 +1479,11 @@
788 - t = string.join(L, "")
790 handleSpecialCharacters(self, t, program)
792 raise ValueError, "don't know how to handle tag " + repr(tagname)
794 def shiftfont(self, program, face=None, bold=None, italic=None):
797 @@ -1481,26 +1506,29 @@
798 # "anonymous" tag: just do the content
800 self.compileComponent(e, program)
801 - #compile_para = compile_ # at least for now...
803 def compile_pageNumber(self, attdict, content, extra, program):
804 program.append(PageNumberObject())
806 def compile_b(self, attdict, content, extra, program):
807 (f,b,i) = self.shiftfont(program, bold=1)
809 self.compileComponent(e, program)
810 self.shiftfont(program, bold=b)
812 def compile_i(self, attdict, content, extra, program):
813 (f,b,i) = self.shiftfont(program, italic=1)
815 self.compileComponent(e, program)
816 self.shiftfont(program, italic=i)
818 def compile_u(self, attdict, content, extra, program):
819 # XXXX must eventually add things like alternative colors
820 - #program = self.program
821 program.append( ('lineOperation', UNDERLINE) )
823 self.compileComponent(e, program)
824 program.append( ('endLineOperation', UNDERLINE) )
826 def compile_sub(self, attdict, content, extra, program):
828 self.size = newsize = size * 0.7
829 @@ -1515,18 +1543,15 @@
830 program.append( ('rise', rise) )
832 def compile_ul(self, attdict, content, extra, program, tagname="ul"):
833 - # by transformation
834 - #print "compile", tagname, attdict
835 atts = attdict.copy()
836 bulletmaker = bulletMaker(tagname, atts, self.context)
837 # now do each element as a separate paragraph
841 - if te is types.StringType:
842 - if e.strip(): #string.strip(e):
843 + if te in (StringType, UnicodeType):
845 raise ValueError, "don't expect CDATA between list elements"
846 - elif te is types.TupleType:
847 + elif te is TupleType:
848 (tagname, attdict1, content1, extra) = e
850 raise ValueError, "don't expect %s inside list" % repr(tagname)
851 @@ -1534,57 +1559,59 @@
853 newatts.update(attdict1)
854 bulletmaker.makeBullet(newatts)
855 - self.compile_para(newatts, content1, extra, program)
856 + self.compile_li(newatts, content1, extra, program)
858 def compile_ol(self, attdict, content, extra, program):
859 return self.compile_ul(attdict, content, extra, program, tagname="ol")
861 + def compile_li(self, attdict, content, extra, program):
862 + self.compile_para(attdict, content, extra, program)
864 def compile_dl(self, attdict, content, extra, program):
865 - # by transformation
866 - #print "compile", tagname, attdict
867 - atts = attdict.copy()
868 - # by transformation
869 - #print "compile", tagname, attdict
870 atts = attdict.copy()
871 bulletmaker = bulletMaker("dl", atts, self.context)
872 # now do each element as a separate paragraph
874 contentcopy = list(content) # copy for destruction
880 - if te is types.StringType:
881 - if e.strip(): #string.strip(e):
882 + if te in (StringType, UnicodeType):
884 raise ValueError, "don't expect CDATA between list elements"
885 elif not contentcopy:
886 break # done at ending whitespace
888 continue # ignore intermediate whitespace
889 - elif te is types.TupleType:
890 + elif te is TupleType:
891 (tagname, attdict1, content1, extra) = e
892 if tagname!="dd" and tagname!="dt":
893 - raise ValueError, "don't expect %s here inside list, expect 'dd' or 'dt'" % repr(tagname)
894 + raise ValueError, "don't expect %s here inside list, expect 'dd' or 'dt'" % \
898 raise ValueError, "dt will not be displayed unless followed by a dd: "+repr(bullet)
900 - if len(content1)!=1:
901 - raise ValueError, "only simple strings supported in dd content currently: "+repr(content1)
902 - bullet = content1[0]
903 - if type(bullet) is not types.StringType:
904 - raise ValueError, "only simple strings supported in dd content currently: "+repr(content1)
905 + self.compile_dt(attdict1, content1, extra, program)
906 + # raise ValueError, \
907 + # "only simple strings supported in dd content currently: "+repr(content1)
909 newatts = atts.copy()
911 newatts.update(attdict1)
912 bulletmaker.makeBullet(newatts, bl=bullet)
913 - self.compile_para(newatts, content1, extra, program)
914 + self.compile_dd(newatts, content1, extra, program)
915 bullet = "" # don't use this bullet again
917 raise ValueError, "dt will not be displayed unless followed by a dd"+repr(bullet)
919 + def compile_dt(self, attdict, content, extra, program):
920 + self.compile_para(attdict, content, extra, program)
922 + def compile_dd(self, attdict, content, extra, program):
923 + self.compile_para(attdict, content, extra, program)
925 def compile_super(self, attdict, content, extra, program):
927 self.size = newsize = size * 0.7
928 @@ -1597,6 +1624,7 @@
929 program.append( ('size', size) )
931 program.append( ('rise', -rise) )
933 def compile_font(self, attdict, content, extra, program):
934 #program = self.program
935 program.append( ("push",) ) # store current data
936 @@ -1618,6 +1646,7 @@
938 self.compileComponent(e, program)
939 program.append( ("pop",) ) # restore as before
941 def compile_a(self, attdict, content, extra, program):
942 url = attdict["href"]
943 colorname = attdict.get("color", "blue")
944 @@ -1632,6 +1661,7 @@
945 program.append( ('endLineOperation', UNDERLINE) )
946 program.append( ('endLineOperation', Link) )
947 program.append( ("pop",) ) # restore as before
949 def compile_link(self, attdict, content, extra, program):
950 dest = attdict["destination"]
951 colorname = attdict.get("color", None)
952 @@ -1647,6 +1677,7 @@
953 program.append( ('endLineOperation', UNDERLINE) )
954 program.append( ('endLineOperation', Link) )
955 program.append( ("pop",) ) # restore as before
957 def compile_setLink(self, attdict, content, extra, program):
958 dest = attdict["destination"]
959 colorname = attdict.get("color", "blue")
960 @@ -1664,43 +1695,55 @@
961 program.append( ('endLineOperation', UNDERLINE) )
962 program.append( ('endLineOperation', Link) )
963 program.append( ("pop",) ) # restore as before
965 #def compile_p(self, attdict, content, extra, program):
966 # # have to be careful about base indent here!
969 def compile_bullet(self, attdict, content, extra, program):
970 - from types import StringType
971 ### eventually should allow things like images and graphics in bullets too XXXX
972 - if len(content)!=1 or type(content[0]) is not StringType:
973 + if len(content)!=1 or type(content[0]) not in (StringType, UnicodeType):
974 raise ValueError, "content for bullet must be a single string"
976 self.do_bullet(text, program)
978 def do_bullet(self, text, program):
980 - #program = self.program
981 indent = style.bulletIndent + self.baseindent
982 font = style.bulletFontName
983 size = style.bulletFontSize
984 program.append( ("bullet", text, indent, font, size) )
986 def compile_tt(self, attdict, content, extra, program):
987 (f,b,i) = self.shiftfont(program, face="Courier")
989 self.compileComponent(e, program)
990 self.shiftfont(program, face=f)
992 def compile_greek(self, attdict, content, extra, program):
993 self.compile_font({"face": "symbol"}, content, extra, program)
995 def compile_evalString(self, attdict, content, extra, program):
996 program.append( EvalStringObject(attdict, content, extra, self.context) )
998 def compile_name(self, attdict, content, extra, program):
999 program.append( NameObject(attdict, content, extra, self.context) )
1001 def compile_getName(self, attdict, content, extra, program):
1002 program.append( GetNameObject(attdict, content, extra, self.context) )
1004 def compile_seq(self, attdict, content, extra, program):
1005 program.append( SeqObject(attdict, content, extra, self.context) )
1007 def compile_seqReset(self, attdict, content, extra, program):
1008 program.append( SeqResetObject(attdict, content, extra, self.context) )
1010 def compile_seqDefault(self, attdict, content, extra, program):
1011 program.append( SeqDefaultObject(attdict, content, extra, self.context) )
1013 def compile_para(self, attdict, content, extra, program, stylename = "para.defaultStyle"):
1014 + if attdict is None:
1016 context = self.context
1017 stylename = attdict.get("style", stylename)
1018 style = context[stylename]
1019 @@ -1708,45 +1751,37 @@
1020 newstyle.addAttributes(attdict)
1021 bulletText = attdict.get("bulletText", None)
1022 mystyle = self.style1
1023 - #newstyle.bulletIndent = mystyle.leftIndent+newstyle.bulletIndent
1024 - #print "attdict", attdict
1025 - #print "leftindent, baseindent", mystyle.leftIndent
1026 - #print "bulletIndent", newstyle.bulletIndent
1027 - thepara = Para(newstyle, content, context=context, bulletText=bulletText) # possible ref loop on context, break later
1028 + thepara = Para(newstyle, content, context=context, bulletText=bulletText)
1029 + # possible ref loop on context, break later
1030 # now compile it and add it to the program
1031 mybaseindent = self.baseindent
1032 self.baseindent = thepara.baseindent = mystyle.leftIndent + self.baseindent
1033 thepara.linearize(program=program)
1034 - #print "program so far"
1035 - #for x in program:
1037 program.append( ("nextLine", 0) )
1038 self.baseindent = mybaseindent
1043 def __init__(self, tagname, atts, context):
1044 self.tagname = tagname
1045 - #print "context is", context
1046 - style = "li.defaultStyle"
1047 + self.context = context
1048 + style = context.has_key(tagname) and tagname or "%s.defaultStyle" % tagname
1049 self.style = style = atts.get("style", style)
1050 - typ = {"ul": "disc", "ol": "1", "dl": None}[tagname]
1051 - #print tagname, "bulletmaker type is", typ
1052 - self.typ =typ = atts.get("type", typ)
1053 - #print tagname, "bulletmaker type is", typ
1054 + typ = {"ul": "disc", "ol": "1"}.get(tagname, None)
1055 + self.typ = typ = atts.get("type", typ)
1056 if not atts.has_key("leftIndent"):
1057 # get the style so you can choose an indent length
1058 - thestyle = context[style]
1059 from reportlab.pdfbase.pdfmetrics import stringWidth
1060 - size = thestyle.fontSize
1061 + size = self.context[self.style].fontSize
1062 indent = stringWidth("XXX", "Courier", size)
1063 atts["leftIndent"] = str(indent)
1066 def makeBullet(self, atts, bl=None):
1067 count = self.count = self.count+1
1069 tagname = self.tagname
1070 - #print "makeBullet", tagname, typ, count
1071 + if bl == 'm': raise ValueError
1072 # forget space before for non-first elements
1074 atts["spaceBefore"] = "0"
1075 @@ -1758,7 +1793,7 @@
1077 raise ValueError, "unordered list type %s not implemented" % repr(typ)
1078 if not atts.has_key("bulletFontName"):
1079 - atts["bulletFontName"] = "ZapfDingbats"
1080 + atts["bulletFontName"] = self.context[self.style].bulletFontName or "ZapfDingbats"
1082 if typ=="1": bl = repr(count)
1084 @@ -1778,7 +1813,9 @@
1086 class EvalStringObject:
1087 "this will only work if rml2pdf is present"
1089 tagname = "evalString"
1091 def __init__(self, attdict, content, extra, context):
1094 @@ -1786,11 +1823,13 @@
1095 self.content = content
1096 self.context = context
1099 def getOp(self, tuple, engine):
1100 from rlextra.rml2pdf.rml2pdf import Controller
1101 #print "tuple", tuple
1102 op = self.op = Controller.processTuple(tuple, self.context, {})
1105 def width(self, engine):
1106 from reportlab.pdfbase.pdfmetrics import stringWidth
1107 content = self.content
1108 @@ -1803,10 +1842,12 @@
1111 return stringWidth(s, engine.fontName, engine.fontSize)
1113 def execute(self, engine, textobject, canvas):
1114 textobject.textOut(str(self.op))
1116 class SeqObject(EvalStringObject):
1118 def getOp(self, tuple, engine):
1119 from reportlab.lib.sequencer import getSequencer
1120 globalsequencer = getSequencer()
1121 @@ -1830,6 +1871,7 @@
1122 pass # name doesn't produce any output
1124 class SeqDefaultObject(NameObject):
1126 def getOp(self, tuple, engine):
1127 from reportlab.lib.sequencer import getSequencer
1128 globalsequencer = getSequencer()
1129 @@ -1843,6 +1885,7 @@
1132 class SeqResetObject(NameObject):
1134 def getOp(self, tuple, engine):
1135 from reportlab.lib.sequencer import getSequencer
1137 @@ -1864,11 +1907,14 @@
1140 class PageNumberObject:
1142 def __init__(self, example="XXX"):
1143 self.example = example # XXX SHOULD ADD THE ABILITY TO PASS IN EXAMPLES
1145 def width(self, engine):
1146 from reportlab.pdfbase.pdfmetrics import stringWidth
1147 return stringWidth(self.example, engine.fontName, engine.fontSize)
1149 def execute(self, engine, textobject, canvas):
1150 n = canvas.getPageNumber()
1151 textobject.textOut(str(n))
1152 @@ -1890,11 +1936,10 @@
1153 mystyle.addAttributes(attdict)
1154 bulletText = attdict.get("bulletText", None)
1155 # can we use the fast implementation?
1158 if not bulletText and len(content)==1:
1160 - if type(text) is types.StringType and "&" not in text:
1161 + if type(text) in (StringType, UnicodeType) and "&" not in text:
1162 result = FastPara(mystyle, text)
1164 result = Para(mystyle, content, context=context, bulletText=bulletText) # possible ref loop on context, break later
1165 @@ -2119,7 +2164,7 @@
1166 for fragment in amptext:
1168 # check for special chars
1169 - semi = string.find(fragment, ";")
1170 + semi = fragment.find(";")
1172 name = fragment[:semi]
1173 if greeks.has_key(name):
1174 @@ -2128,7 +2173,7 @@
1175 (f,b,i) = engine.shiftfont(program, face="symbol")
1176 program.append(greeksub)
1177 engine.shiftfont(program, face=f)
1178 - if fragment and fragment[0] in string.whitespace:
1179 + if fragment and fragment[0] in WHITESPACE:
1180 program.append(" ") # follow the greek with a space
1183 @@ -2143,10 +2188,10 @@
1184 # does the last one need a space?
1185 if sfragment and fragment:
1186 # reader 3 used to go nuts if you don't special case the last frag, but it's fixed?
1187 - if fragment[-1] in string.whitespace: # or fragment==lastfrag:
1188 + if fragment[-1] in WHITESPACE: # or fragment==lastfrag:
1189 program.append( sfragment[-1]+" " )
1191 - last = sfragment[-1].strip() #string.strip(sfragment[-1])
1192 + last = sfragment[-1].strip()
1194 #print "last is", repr(last)
1195 program.append( last )
1196 @@ -2154,7 +2199,7 @@
1197 #print "HANDLED", program
1200 -def Paragraph(text, style, bulletText=None, frags=None):
1201 +def Paragraph(text, style, bulletText=None, frags=None, context=None):
1202 """ Paragraph(text, style, bulletText=None)
1203 intended to be like a platypus Paragraph but better.
1205 @@ -2165,7 +2210,7 @@
1206 # use the fully featured one.
1207 from reportlab.lib import rparsexml
1208 parsedpara = rparsexml.parsexmlSimple(text)
1209 - return Para(style, parsedText=parsedpara, bulletText=bulletText, state=None)
1210 + return Para(style, parsedText=parsedpara, bulletText=bulletText, state=None, context=context)
1212 ##class Paragraph(Para):
1213 ## """ Paragraph(text, style, bulletText=None)
1214 @@ -2206,8 +2251,10 @@
1215 UNDERLINE = UnderLineHandler()
1217 class HotLink(UnderLineHandler):
1219 def __init__(self, url):
1222 def end_at(self, x, y, para, canvas, textobject):
1223 fontsize = para.fontSize
1224 rect = [self.xStart, self.yStart, x,y+fontsize]
1225 @@ -2215,27 +2262,31 @@
1226 print "LINKING RECTANGLE", rect
1227 #canvas.rect(self.xStart, self.yStart, x-self.xStart,y+fontsize-self.yStart, stroke=1)
1228 self.link(rect, canvas)
1230 def link(self, rect, canvas):
1231 canvas.linkURL(self.url, rect, relative=1)
1233 class InternalLink(HotLink):
1235 def link(self, rect, canvas):
1236 destinationname = self.url
1238 canvas.linkRect(contents, destinationname, rect, Border="[0 0 0]")
1240 class DefDestination(HotLink):
1244 def link(self, rect, canvas):
1245 destinationname = self.url
1246 if not self.defined:
1247 [x, y, x1, y1] = rect
1248 - canvas.bookmarkHorizontal(destinationname, x,y1) # use the upper y
1249 + canvas.bookmarkHorizontal(destinationname, x, y1) # use the upper y
1252 def splitspace(text):
1253 # split on spacing but include spaces at element ends
1254 - stext = string.split(text)
1255 + stext = text.split()
1258 result.append(e+" ")