dabo Commit
Revision 5223
Date: 2009-05-17 19:52:14 -0700 (Sun, 17 May 2009)
Author: Paul
Trac: http://trac.dabodev.com/changeset/5223

Changed:
U   trunk/dabo/lib/caselessDict.py
U   trunk/dabo/lib/reportWriter.py
A   trunk/dabo/lib/reporting_tests/
D   trunk/dabo/lib/reporting_tests/invoice_demo/
A   trunk/dabo/lib/reporting_tests/invoice_demo/
D   trunk/dabo/lib/reporting_tests/invoice_demo/bizcard01_medium.jpg
A   trunk/dabo/lib/reporting_tests/invoice_demo/bizcard01_medium.jpg
D   trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py
A   trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py
D   trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml
A   trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml
D   trunk/dabo/lib/reporting_tests/invoice_demo/logo_2cannisters_medium.jpg
A   trunk/dabo/lib/reporting_tests/invoice_demo/logo_2cannisters_medium.jpg

Log:
Merged in my reporting branch. Reportwriter now handles paragraphs that span 
multiple pages. There are issues still, but they are minor.



Diff:
Modified: trunk/dabo/lib/caselessDict.py
===================================================================
--- trunk/dabo/lib/caselessDict.py      2009-05-18 02:32:03 UTC (rev 5222)
+++ trunk/dabo/lib/caselessDict.py      2009-05-18 02:52:14 UTC (rev 5223)
@@ -24,7 +24,7 @@
                return dict.__getitem__(self, key.lower())
 
        def __delitem__(self, key):
-               dict.__delitem__(self, key)
+               dict.__delitem__(self, key.lower())
                del(self._OriginalCase[key.lower()])
 
        def __contains__(self, key):

Modified: trunk/dabo/lib/reportWriter.py
===================================================================
--- trunk/dabo/lib/reportWriter.py      2009-05-18 02:32:03 UTC (rev 5222)
+++ trunk/dabo/lib/reportWriter.py      2009-05-18 02:52:14 UTC (rev 5223)
@@ -462,11 +462,18 @@
        def initAvailableProps(self):
                super(Band, self).initAvailableProps()
                self.AvailableProps["Height"] = toPropDict(float, 0.0, 
-                               """Specifies the height of the band.
+                               """Specifies the height of the band, not 
including growable objects.
 
                                If the height evaluates to None, the height of 
the band will size
                                itself dynamically at runtime.""")
 
+               self.AvailableProps["TotalHeight"] = toPropDict(float, 0.0, 
+                               """Specifies the height of the band, including 
growable objects.
+
+                               Read-only/calculated at runtime. Specifies the 
height of the band
+                               on the page, and gets reevaluated for each page 
the band continues
+                               printing on.""")
+
                self.AvailableProps["DesignerLock"] = toPropDict(bool, False, 
                                """Specifies whether the band height can be 
changed interactively.
 
@@ -693,6 +700,7 @@
        """Represents a frameset."""
        def initAvailableProps(self):
                super(Frameset, self).initAvailableProps()
+
                self.AvailableProps["FrameId"] = toPropDict(str, None, 
                                """(to remove)""")
 
@@ -717,8 +725,6 @@
                self.AvailableProps["ColumnCount"] = toPropDict(int, 1, 
                                """Specifies the number of columns in the 
frame.""")
 
-               self.AvailableProps["calculatedHeight"] = toPropDict(float, 0, 
-                               """(to remove)""")
 
        def insertRequiredElements(self):
                """Insert any missing required elements into the frameset."""
@@ -807,19 +813,21 @@
        """
        _clearMemento = True
 
-
-       def draw(self, obj, origin, getNeededHeight=False):
+       def draw(self, obj, origin=(0,0),       availableHeight=None, 
deferred=None):
                """Draw the given object on the Canvas.
 
                The object is a dictionary containing properties, and   origin 
is the (x,y)
                tuple where the object will be drawn. 
+
+               availableHeight is the height available on the current page; 
deferred is 
+               the contents of the object partially printed on the last page 
that needs
+               to continue printing now (paragraph story). 
                """
-               neededHeight = 0
-
                ## (Can't get x,y directly from object because it may have been 
modified 
                ## by the calling program to adjust for band position, and 
draw() 
                ## doesn't know about bands.)
-
+               neededHeight = 0
+               objType = obj.__class__.__name__
                c = self.Canvas
                x,y = origin
 
@@ -828,18 +836,11 @@
                ## returns between c.saveState() and c.restoreState()!
                c.saveState()
 
+               neededHeight = 0
+
                ## These properties can apply to all objects:
                width = self.getPt(obj.getProp("width"))
        
-               try:
-                       height = obj.getProp("calculatedHeight")
-               except ValueError:
-                       height = None
-               if height is not None:
-                       height = self.getPt(height)
-               else:
-                       height = self.getPt(obj.getProp("Height"))
-       
                rotation = obj.getProp("rotation")
                hAnchor = obj.getProp("hAnchor").lower()
                vAnchor = obj.getProp("vAnchor").lower()
@@ -848,15 +849,16 @@
                        x = x - width
                elif hAnchor == "center":
                        x = x - (width / 2)
-               
-               if vAnchor == "top":
-                       y = y - height
-               elif vAnchor == "middle":
-                       y = y - (height / 2)
        
+               if objType != "Frameset":       
+                       height = self.getPt(obj.getProp("Height"))
+                       if vAnchor == "top":
+                               y = y - height
+                       elif vAnchor == "middle":
+                               y = y - (height / 2)
+       
                
                ## Do specific things based on object type:
-               objType = obj.__class__.__name__
                if objType == "Rectangle":
                        d = shapes.Drawing(width, height)
                        d.rotate(rotation)
@@ -1009,17 +1011,43 @@
        
                elif objType == "Frameset":
                        # A frame is directly related to reportlab's platypus 
Frame.
+                               
                        borderWidth = self.getPt(obj.getProp("borderWidth"))
                        borderColor = obj.getProp("borderColor")
-                       frameId = obj.getProp("frameId")
+                       columnCount = obj.getProp("columnCount")
+                       columnWidth = width/columnCount
                        padLeft = self.getPt(obj.getProp("padLeft"))
                        padRight = self.getPt(obj.getProp("padRight"))
                        padTop = self.getPt(obj.getProp("padTop"))
                        padBottom = self.getPt(obj.getProp("padBottom"))
-                       columnCount = obj.getProp("columnCount")
-       
-                       columnWidth = width/columnCount
+                       frameId = obj.getProp("frameId")
 
+                       if deferred:
+                               story = deferred
+                               neededHeight = sum([s[1] for s in story])
+                       else:
+                               story, neededHeight = self.getStory(obj)
+                       printStory = story
+                       deferredStory = []
+                       tot_p_height = 0
+                       printStoryHeight = deferredStoryHeight = 0
+                       if neededHeight >= availableHeight:
+                               printStory = []
+                               for p, p_height in story:
+                                       tot_p_height += p_height
+                                       if tot_p_height + padTop + padBottom >= 
availableHeight:
+                                               deferredStory.append((p, 
p_height))
+                                               deferredStoryHeight += p_height
+                                       else:
+                                               printStory.append((p, p_height))
+                                               printStoryHeight += p_height
+                               neededHeight = printStoryHeight + padTop + 
padBottom
+               
+                       if vAnchor == "top":
+                               y = y - neededHeight
+                       elif vAnchor == "middle":
+                               y = y - (neededHeight / 2)
+
                        ## Set canvas props based on our props:
                        c.translate(x, y)
                        c.rotate(rotation)
@@ -1031,79 +1059,17 @@
                        else:
                                boundary = 0
 
-                       story = []      
-                       
-                       styles_ = styles.getSampleStyleSheet()
-
-                       objects = obj["Objects"]
-                       story = []
-                       for fobject in objects:
-                               objNeededHeight = 0
-
-                               t = fobject.__class__.__name__
-                               s = styles_[fobject.getProp("style")]
-                               expr = fobject.getProp("expr", 
returnException=True)
-
-                               if isinstance(s, basestring):
-                                       expr = expr.encode(self.Encoding)
-                               else:
-                                       expr = unicode(expr)
-                               s = copy.deepcopy(s)
-
-                               if fobject.has_key("fontSize"):
-                                       s.fontSize = fobject.getProp("fontSize")
-
-                               if fobject.has_key("fontName"):
-                                       s.fontName = fobject.getProp("fontName")
-                               
-                               if fobject.has_key("leading"):
-                                       s.leading = fobject.getProp("leading")
-
-                               if fobject.has_key("spaceAfter"):
-                                       s.spaceAfter = 
fobject.getProp("spaceAfter")
-       
-                               if fobject.has_key("spaceBefore"):
-                                       s.spaceBefore = 
fobject.getProp("spaceBefore")
-
-                               if fobject.has_key("leftIndent"):
-                                       s.leftIndent = 
fobject.getProp("leftIndent")
-
-                               if fobject.has_key("firstLineIndent"):
-                                       s.firstLineIndent = 
fobject.getProp("firstLineIndent")
-
-                               if t.lower() == "paragraph":
-                                       paras = expr.split("\n")
-                                       for para in paras:
-                                               if len(para) == 0: 
-                                                       # Blank line
-                                                       p = platypus.Spacer(0, 
s.leading)
-                                               else:
-                                                       def escapePara(para):
-                                                               words = 
para.split(" ")
-                                                               for idx, word 
in enumerate(words):
-                                                                       if "&" 
in word and ";" not in word:
-                                                                               
word = word.replace("&", "&")
-                                                                       if "<" 
in word and ">" not in word:
-                                                                               
word = word.replace("<", "&lt;")
-                                                                       
words[idx] = word
-                                                               return " 
".join(words)
-                                                       para = escapePara(para)
-                                                       p = ParaClass(para, s)
-                                               story.append(p)
-                                               objNeededHeight += 
p.wrap(columnWidth-padLeft-padRight, None)[1]
-
-                               neededHeight = max(neededHeight, 
objNeededHeight) + padTop + padBottom
-
                        for columnIndex in range(columnCount):
-                               f = platypus.Frame(columnIndex*columnWidth, 0, 
columnWidth, height, leftPadding=padLeft,
+                               f = platypus.Frame(columnIndex*columnWidth, 0, 
columnWidth, neededHeight, leftPadding=padLeft,
                                                rightPadding=padRight, 
topPadding=padTop,
                                                bottomPadding=padBottom, 
id=frameId, 
                                                showBoundary=boundary)
-                               if getNeededHeight:
-                                       obj["calculatedHeight"] = "%s" % 
neededHeight
-                               else:
-                                       f.addFromList(story, c)
+                               f.addFromList([s[0] for s in printStory], c)
        
+                       deferred = deferredStory
+                       neededHeight = deferredStoryHeight
+
+
                elif objType == "Image":
                        borderWidth = self.getPt(obj.getProp("borderWidth"))
                        borderColor = obj.getProp("borderColor")
@@ -1252,9 +1218,90 @@
                ## rotating, scaling, etc. are cumulative, not absolute and we 
don't want
                ## to start with a canvas in an unknown state.)
                c.restoreState()
-               return neededHeight
+               return deferred, neededHeight
 
 
+       def getStory(self, obj):
+               width = self.getPt(obj.getProp("width"))
+               padLeft = self.getPt(obj.getProp("padLeft"))
+               padRight = self.getPt(obj.getProp("padRight"))
+               padTop = self.getPt(obj.getProp("padTop"))
+               padBottom = self.getPt(obj.getProp("padBottom"))
+               columnCount = obj.getProp("columnCount")
+               columnWidth = width/columnCount
+
+               styles_ = styles.getSampleStyleSheet()
+
+               objects = obj["Objects"]
+               story = []
+               for fobject in objects:
+                       objNeededHeight = 0
+
+                       t = fobject.__class__.__name__
+                       s = styles_[fobject.getProp("style")]
+                       expr = fobject.getProp("expr", returnException=True)
+
+                       if isinstance(s, basestring):
+                               expr = expr.encode(self.Encoding)
+                       else:
+                               expr = unicode(expr)
+                       s = copy.deepcopy(s)
+
+                       if fobject.has_key("fontSize"):
+                               s.fontSize = fobject.getProp("fontSize")
+
+                       if fobject.has_key("fontName"):
+                               s.fontName = fobject.getProp("fontName")
+                               
+                       if fobject.has_key("leading"):
+                               s.leading = fobject.getProp("leading")
+
+                       if fobject.has_key("spaceAfter"):
+                               s.spaceAfter = fobject.getProp("spaceAfter")
+       
+                       if fobject.has_key("spaceBefore"):
+                               s.spaceBefore = fobject.getProp("spaceBefore")
+
+                       if fobject.has_key("leftIndent"):
+                               s.leftIndent = fobject.getProp("leftIndent")
+
+                       if fobject.has_key("firstLineIndent"):
+                               s.firstLineIndent = 
fobject.getProp("firstLineIndent")
+
+                       if t.lower() == "paragraph":
+                               paras = expr.splitlines()
+                               for idx, para in enumerate(paras):
+                                       if len(para) == 0: 
+                                               # Blank line
+                                               p = platypus.Spacer(0, 
s.leading)
+                                       else:
+                                               def escapePara(para):
+                                                       words = para.split(" ")
+                                                       for idx, word in 
enumerate(words):
+                                                               if "&" in word 
and ";" not in word:
+                                                                       word = 
word.replace("&", "&amp;")
+                                                               if "<" in word 
and ">" not in word:
+                                                                       word = 
word.replace("<", "&lt;")
+                                                               words[idx] = 
word
+                                                       return " ".join(words)
+                                               para = escapePara(para)
+                                               p = ParaClass(para, s)
+                                       p_height = 
p.wrap(columnWidth-padLeft-padRight, None)[1]
+                                       objNeededHeight += p_height
+                                       story.append((p, p_height))
+
+                               def hackDeferredPara():
+                                       """When a paragraph wraps to the next 
page, the last line won't print if this isn't done."""
+                                       append_p = ParaClass("Hack: see 
hackDeferredPara() in reportWriter.py", s)
+                                       p_height = p.wrap(99999, None)[1]
+                                       story.append((p, p_height))
+                               if paras:
+                                       hackDeferredPara()
+
+               neededHeight = objNeededHeight + padTop + padBottom
+               return story, neededHeight
+
+
        def getColorTupleFromReportLab(self, val):
                """Given a color tuple in reportlab format (values between 0 
and 1), return
                a color tuple in 0-255 format."""
@@ -1323,6 +1370,7 @@
                the PDF file will be left open so that additional pages can be 
added 
                with another call, perhaps after creating a different report 
form.
                """
+               self._calcObjectHeights = {}
                _form = self.ReportForm
                if _form is None:
                        raise ValueError("ReportForm must be set first.")
@@ -1403,7 +1451,7 @@
                                self.Variables[varName] = vv["value"]           
        
                                        
 
-               def printBand(band, y=None, group=None):
+               def printBand(band, y=None, group=None, deferred=None):
                        """Generic function for printing any band."""
 
                        _form = self.ReportForm
@@ -1425,6 +1473,12 @@
 #                      print workingPageWidth / 72, columnWidth / 72
 #                      print columnWidth, columnCount
 
+                       pf = _form.get("pageFooter")
+                       if pf is None:
+                               pfHeight = 0
+                       else:
+                               pfHeight = self.getPt(pf.getProp("Height"))
+
                        if y is None:
                                y = pageHeaderOrigin[1]
 
@@ -1439,33 +1493,38 @@
 
                        self.ReportForm.Bands[band] = CaselessDict()
 
-                       height = bandDict.getProp("Height")
-                       if height is not None:
-                               height = self.getPt(height)
-                       else:
-                               # figure out height based on the objects in the 
band.
-                               height = self.calculateBandHeight(bandDict)
+                       bandHeight = self.getBandHeight(bandDict)
+                       if not deferred:
+                               y -= bandHeight
 
-                       y = y - height
                        width = pageWidth - ml - mr
 
-                       # Non-detail band special cases:
-                       if band == "pageHeader":
-                               x,y = pageHeaderOrigin
-                       elif band == "pageFooter":
-                               x,y = pageFooterOrigin
-                       elif band in ("pageBackground", "pageForeground"):
-                               x,y = 0,1
-                               width, height = pageWidth-1, pageHeight-1
+                       # Set this property as quickly as possible as other 
properties (y, for example)
+                       # could depend on it.
+                       self.ReportForm.Bands[band]["Height"] = bandHeight
 
+                       def getTotalBandHeight():
+                               maxBandHeight = bandHeight
+                               if deferred:
+                                       for obj, obj_deferred, neededHeight in 
deferred:
+                                               needed = neededHeight
+                                               maxBandHeight = 
max(maxBandHeight, neededHeight)
+                               else:
+                                       for obj in bandDict.get("Objects", []):
+                                               if obj.getProp("Height") is 
None:
+                                                       story = 
self.getStory(obj)
+                                                       storyheight = story[1]
+                                                       needed = storyheight + 
bandHeight - self.getPt(obj.getProp("y"))  ## y could be dep. on band height.
+                       
+                                                       maxBandHeight = 
max(maxBandHeight, needed)
+                               availableHeight = y - (pageFooterOrigin[1] + 
pfHeight)
+                               if maxBandHeight > availableHeight:
+                                       maxBandHeight = availableHeight
+                               return maxBandHeight
 
-                       pf = _form.get("pageFooter")
-                       if pf is None:
-                               pfHeight = 0
-                       else:
-                               pfHeight = self.getPt(pf.getProp("Height"))
+                       maxBandHeight = getTotalBandHeight()
 
-                       if band in ("detail", "groupHeader", "groupFooter"):
+                       if band in ("groupHeader", "groupFooter", "detail"):
                                extraHeight = 0
                                if band == "groupHeader":
                                        # Also account for the height of the 
first detail record: don't print the
@@ -1473,52 +1532,121 @@
                                        # printed as well. Actually, this 
should be reworked so that any subsequent
                                        # group header records get accounted 
for as well...
                                        b = _form["detail"]
-                                       extraHeight = b.get("Height")
-                                       if extraHeight is None:
-                                               extraHeight = 
b.AvailableProps["Height"]["default"]
-                                       else:
-                                               extraHeight = eval(extraHeight)
-                                       if extraHeight is None:
-                                               extraHeight = 
self.calculateBandHeight(b)
-                                       else:
-                                               extraHeight = 
self.getPt(extraHeight)
-                               if y < pageFooterOrigin[1] + pfHeight + 
extraHeight:
+                                       extraHeight = self.getBandHeight(b)
+
+                               check = pageFooterOrigin[1] + pfHeight + 
extraHeight
+                               if bandDict.getProp("height") is not None:
+                                       # band height is fixed, won't flow to 
next page. 
+                                       check += bandHeight
+
+                               if y < check:
                                        if self._currentColumn >= columnCount-1:
                                                endPage()
                                                beginPage()
                                        else:
                                                self._currentColumn += 1
                                        y = pageHeaderOrigin[1]
+                                       maxBandHeight = getTotalBandHeight()
                                        if band == "detail":
                                                y = reprintGroupHeaders(y)
-                                       y = y - height
+                                       if not deferred:
+                                               y -= bandHeight
                                
+                       # Non-detail band special cases:
+                       if band == "pageHeader":
+                               x,y = pageHeaderOrigin
+                       elif band == "pageFooter":
+                               x,y = pageFooterOrigin
+                       elif band in ("pageBackground", "pageForeground"):
+                               x,y = 0,1
+                               width, height = pageWidth-1, pageHeight-1
+
                        x = ml + (self._currentColumn * columnWidth)
                                
                        self.ReportForm.Bands[band]["x"] = x
                        self.ReportForm.Bands[band]["y"] = y
                        self.ReportForm.Bands[band]["Width"] = width
-                       self.ReportForm.Bands[band]["Height"] = height
-               
+                       self.ReportForm.Bands[band]["TotalHeight"] = 
maxBandHeight      
+
                        if self.ShowBandOutlines:
                                self.printBandOutline("%s (record %s)" % (band, 
self.RecordNumber), 
-                                               x, y, width, height)
+                                               x, y, width, bandHeight)
 
-                       if bandDict.has_key("Objects"):
-                               for obj in bandDict["Objects"]:
-                                       show = obj.getProp("show", 
returnException=True)
-                                       if show == False:
-                                               continue
+                       del_deferred_idxs = []
+                       objects = bandDict.get("Objects", [])
+                       was_deferred = False
+                       if deferred:
+                               was_deferred = True
+                               objects = deferred
+                       for idx, obj in enumerate(objects):
+                               if isinstance(obj, tuple):
+                                       # deferred (obj, obj_deferred)
+                                       obj, obj_deferred, neededHeight = obj
+                               else:
+                                       obj_deferred = None
+                                       neededHeight = 0
+                               show = obj.getProp("show", returnException=True)
+                               if show == False:
+                                       continue
 
-                                       x1 = self.getPt(obj.getProp("x"))
-                                       y1 = self.getPt(obj.getProp("y"))
-                                       x1 = x + x1
+                               x1 = self.getPt(obj.getProp("x"))
+                               y1 = obj_y = self.getPt(obj.getProp("y"))
+                               x1 = x + x1
+                               if obj_deferred:
+                                       y1 = y
+                               else:
                                        y1 = y + y1
-                                       self.draw(obj, (x1, y1))
-                                               
-                       return y                
 
+                               availableHeight = y - (pageFooterOrigin[1] + 
pfHeight)
+                               obj_height = obj.getProp("height")
+                               if obj_height is not None:
+                                       obj_height = self.getPt(obj_height)
+                                       if availableHeight > obj_height:
+                                               availableHeight = obj_height
+                               if bandDict.getProp("height") is not None:
+                                       if availableHeight > obj_y:
+                                               availableHeight = obj_y
+                               #availableHeight = min(availableHeight, 
bandHeight+y)
+                               new_obj_deferred, neededHeight = self.draw(obj, 
(x1, y1),       availableHeight=availableHeight,
+                                               deferred=obj_deferred)
 
+                               if bandDict.getProp("height") is not None:
+                                       # Band height is fixed; cancel any 
deferrals.
+                                       new_obj_deferred = None
+
+                               if new_obj_deferred:
+                                       if obj_deferred:
+                                               # was already deferred, and now 
deferred again. WARNING: if para longer 
+                                               # than a page, we'll recurse 
forever. FIXME.
+                                               deferred[idx] = (obj, 
new_obj_deferred, neededHeight)
+                                       else:
+                                               # new deferral.
+                                               if deferred is None:
+                                                       deferred = []
+                                               deferred.append((obj, 
new_obj_deferred, neededHeight))
+                               else:
+                                       if obj_deferred:
+                                               # need to delete the old 
deferral
+                                               del_deferred_idxs.append(idx)
+
+                       del_deferred_idxs.sort(reverse=True)
+                       for idx in del_deferred_idxs:
+                               del(deferred[idx])
+
+                       if was_deferred and not deferred:
+                               # just printed the last page of deferreds
+                               return y - maxBandHeight
+
+                       elif deferred:
+                               # the deferred objs will print on the next 
page. RECURSE WARNING.
+                               dy = printBand(band=band, y=-1, group=group, 
deferred=deferred)
+                               return dy
+                       else:
+                               # no deferreds ever involved
+                               y -= (maxBandHeight-bandHeight)
+                               return y
+
+
                def beginPage():
                        # Print the static bands that appear below detail in 
z-order:
                        self._pageNumber += 1
@@ -1597,10 +1725,8 @@
                                                brandNewPage = True  ## don't 
start multiple new pages
                                        y = printBand("groupHeader", y, group)
 
-
                        # print the detail band:
                        y = printBand("detail", y)
-
                        self._recordNumber += 1
 
 
@@ -1616,27 +1742,34 @@
                        self._canvas = None
 
 
-       def calculateBandHeight(self, bandDict):
-               maxHeight = 0
-               if bandDict.has_key("Objects"):
-                       for obj in bandDict["Objects"]:
-                               y = self.getPt(obj.getProp("y"))
+       def getBandHeight(self, bandDict):
+               """Return the height of the band.
 
-                               ht = obj.getProp("Height")
-                               if ht is None:
-                                       ht = self.calculateObjectHeight(obj)
-                               ht = self.getPt(ht)
+               If the band's Height property is None, the height will be
+               calculated based on the objects in the band.
+               """
 
-                               thisHeight = y + ht
-                               maxHeight = max(thisHeight, maxHeight)
-               return maxHeight
+               bandHeight = bandDict.getProp("Height")
+               if bandHeight is not None:
+                       # explicitly-set height
+                       return self.getPt(bandHeight)
 
-               
-       def calculateObjectHeight(self, obj):
-               neededHeight = self.draw(obj, (0,0), getNeededHeight=True)
-               return neededHeight
+               # dynamic height: figure out based on the objects in the band.
+               bandHeight = 0
+               objects = bandDict.get("objects", [])
 
+               for obj in objects:
+                       obj_y = self.getPt(obj.getProp("y"))
+                       obj_ht = obj.getProp("Height")
+                       if obj_ht is None:
+                               continue
+                       # object height is fixed.
+                       obj_ht = self.getPt(obj_ht)
+                       thisHeight = obj_y + obj_ht
+                       bandHeight = max(thisHeight, bandHeight)
+               return bandHeight
 
+
        def getPageSize(self):
                ## Set the Page Size:
                # get the string pageSize value from the spec file:

Copied: trunk/dabo/lib/reporting_tests (from rev 5222, 
branches/paul_reporting/dabo/lib/reporting_tests)

Copied: trunk/dabo/lib/reporting_tests/invoice_demo (from rev 5222, 
branches/paul_reporting/dabo/lib/reporting_tests/invoice_demo)

Deleted: trunk/dabo/lib/reporting_tests/invoice_demo/bizcard01_medium.jpg

Copied: trunk/dabo/lib/reporting_tests/invoice_demo/bizcard01_medium.jpg (from 
rev 5222, 
branches/paul_reporting/dabo/lib/reporting_tests/invoice_demo/bizcard01_medium.jpg)
===================================================================
(Binary files differ)

Deleted: trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py

Copied: trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py (from rev 5222, 
branches/paul_reporting/dabo/lib/reporting_tests/invoice_demo/invoice.py)
===================================================================
--- trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py                      
        (rev 0)
+++ trunk/dabo/lib/reporting_tests/invoice_demo/invoice.py      2009-05-18 
02:52:14 UTC (rev 5223)
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+This demo uses a copy of my invoice report with bogus data to show how to
+interact with the ReportWriter to create a PDF. Run this script to create
+invoice.pdf. To modify the report form, use daboide/ReportDesigner to open
+the invoice.rfxml file.
+"""
+
+from dabo.lib.reportWriter import ReportWriter
+from dabo.lib import reportUtils
+
+outFile = "invoice.pdf"
+
+print "Instantiating the report writer..."
+rw = ReportWriter()
+
+# Set some required properties:
+rw.ReportFormFile = "invoice.rfxml"
+rw.OutputFile = "%s" % outFile
+# (Normally, you'd also set the Cursor property, to provide the data,
+#  but this sample just uses the test cursor inside the report form.)
+
+# Set some optional properties:
+rw.UseTestCursor = True
+rw.ShowBandOutlines = True
+
+print "Writing %s..." % outFile
+rw.write()
+
+print "Trying to preview it..."
+reportUtils.previewPDF(outFile)

Deleted: trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml

Copied: trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml (from rev 
5222, 
branches/paul_reporting/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml)
===================================================================
--- trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml                   
        (rev 0)
+++ trunk/dabo/lib/reporting_tests/invoice_demo/invoice.rfxml   2009-05-18 
02:52:14 UTC (rev 5223)
@@ -0,0 +1,695 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+
+<!-- 
+               This is a Dabo report form xml (rfxml) document, describing a
+               report form. It was generated by the Dabo Report Writer, and can
+               be edited by hand or by using the Dabo Report Designer.
+-->
+
+<Report>
+       <title>Invoice</title>
+
+       <page>
+               <MarginBottom>".4 in"</MarginBottom>
+               <marginLeft>".75 in"</marginLeft>
+               <marginRight>".75 in"</marginRight>
+               <marginTop>".75 in"</marginTop>
+               <orientation>"portrait"</orientation>
+               <size>"letter"</size>
+       </page>
+
+       <variables>
+               <Variable>
+                       <expr>self.Variables['clientBalance'] + 
self.Record['amount']</expr>
+                       <initialValue>decimal.Decimal('0.00')</initialValue>
+                       <name>clientBalance</name>
+                       <resetAt>self.Record['clientid']</resetAt>
+               </Variable>
+               <Variable>
+                       <expr>self.Variables['timeCodeBalance'] + 
self.Record['amount']</expr>
+                       <initialValue>decimal.Decimal('0.00')</initialValue>
+                       <name>timeCodeBalance</name>
+                       <resetAt>"%s-%s" % (self.Record['clientid'], 
self.Record['timecodeid'])</resetAt>
+               </Variable>
+               <Variable>
+                       <expr>self.Variables['recordsPrinted_timecode'] + 
1</expr>
+                       <initialValue>decimal.Decimal('0.00')</initialValue>
+                       <name>recordsPrinted_timecode</name>
+                       <resetAt>"%s-%s" % (self.Record['clientid'], 
self.Record['timecodeid'])</resetAt>
+               </Variable>
+       </variables>
+
+       <groups>
+               <Group>
+                       <expr>self.clientid</expr>
+                       <ResetPageNumber>True</ResetPageNumber>
+                       <startOnNewPage>True</startOnNewPage>
+                       <groupHeader>
+                               <Height>"1.75 in"</Height>
+                               <objects>
+                                       <String>
+                                               <expr>self.clientname</expr>
+                                               <fontSize>14</fontSize>
+                                               <hAnchor>"Left"</hAnchor>
+                                               <Height>'14.0 pt'</Height>
+                                               <width>"6 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>'1.5497 in'</y>
+                                       </String>
+                                       <String>
+                                               <expr>self.clientaddress1</expr>
+                                               <fontSize>14</fontSize>
+                                               <hAnchor>"Left"</hAnchor>
+                                               <Height>'14.0 pt'</Height>
+                                               <width>"6 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>'1.3297 in'</y>
+                                       </String>
+                                       <String>
+                                               <expr>self.clientaddress2</expr>
+                                               <fontSize>14</fontSize>
+                                               <hAnchor>"Left"</hAnchor>
+                                               <Height>'14.0 pt'</Height>
+                                               <width>"6 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>'1.1097 in'</y>
+                                       </String>
+                                       <String>
+                                               <expr>self.clientaddress3</expr>
+                                               <fontSize>14</fontSize>
+                                               <hAnchor>"Left"</hAnchor>
+                                               <Height>'14.0 pt'</Height>
+                                               <width>"6 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>'0.9012 in'</y>
+                                       </String>
+                               </objects>
+                       </groupHeader>
+                       <groupFooter>
+                               <height>"0.25 in"</height>
+                               <objects>
+                                       <String>
+                                               <align>"right"</align>
+                                               <expr>"Amount due:            $ 
%s" % locale.format('%.2f', self.clientBalance, True)</expr>
+                                               <fontSize>14</fontSize>
+                                               <hAnchor>"Right"</hAnchor>
+                                               <height>20</height>
+                                               <width>"6 in"</width>
+                                               <x>"6.925 in"</x>
+                                               <y>"0 in"</y>
+                                       </String>
+                               </objects>
+                       </groupFooter>
+               </Group>
+               <Group>
+                       <expr>self.subclientid</expr>
+                       <ReprintHeaderOnNewPage>True</ReprintHeaderOnNewPage>
+                       <GroupHeader>
+                               <Height>28.8</Height>
+                               <Objects>
+                                       <Rectangle>
+                                               <fillColor>(.9, .9, 
.9)</fillColor>
+                                               <height>".25 in"</height>
+                                               <strokeWidth>".25 
pt"</strokeWidth>
+                                               <width>"7 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>"0 in"</y>
+                                       </Rectangle>
+                                       <String>
+                                               <expr>self.subclientname</expr>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>'165.0 pt'</width>
+                                               <y>'20.0 pt'</y>
+                                       </String>
+                                       <Line>
+                                               <height>"0.25 in"</height>
+                                               <LineSlant>"|"</LineSlant>
+                                               
<strokeColor>(.2,.2,.2)</strokeColor>
+                                               <strokeWidth>0.25</strokeWidth>
+                                               <width>2</width>
+                                               <x>".575 in"</x>
+                                               <y>0</y>
+                                       </Line>
+                                       <Line>
+                                               <height>"0.25 in"</height>
+                                               <LineSlant>"|"</LineSlant>
+                                               
<strokeColor>(.2,.2,.2)</strokeColor>
+                                               <strokeWidth>0.25</strokeWidth>
+                                               <width>2</width>
+                                               <x>"5.25 in"</x>
+                                               <y>0</y>
+                                       </Line>
+                                       <Line>
+                                               <height>"0.25 in"</height>
+                                               <LineSlant>"|"</LineSlant>
+                                               
<strokeColor>(.2,.2,.2)</strokeColor>
+                                               <strokeWidth>0.25</strokeWidth>
+                                               <width>2</width>
+                                               <x>"5.78 in"</x>
+                                               <y>0</y>
+                                       </Line>
+                                       <Line>
+                                               <height>"0.25 in"</height>
+                                               <LineSlant>"|"</LineSlant>
+                                               
<strokeColor>(.2,.2,.2)</strokeColor>
+                                               <strokeWidth>0.25</strokeWidth>
+                                               <width>2</width>
+                                               <x>"6.3 in"</x>
+                                               <y>0</y>
+                                       </Line>
+                                       <String>
+                                               <expr>"Date"</expr>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>'0.5305 in'</width>
+                                               <x>"0.025 in"</x>
+                                               <y>5</y>
+                                       </String>
+                                       <String>
+                                               <expr>"Description"</expr>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>"4.6225 in"</width>
+                                               <x>"0.6075 in"</x>
+                                               <y>5</y>
+                                       </String>
+                                       <String>
+                                               <align>"right"</align>
+                                               <expr>"Hours"</expr>
+                                               <hAnchor>"right"</hAnchor>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>'0.4166 in'</width>
+                                               <x>"5.6975 in"</x>
+                                               <y>5</y>
+                                       </String>
+                                       <String>
+                                               <align>"right"</align>
+                                               <expr>"Rate"</expr>
+                                               <hAnchor>"right"</hAnchor>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>'0.4166 in'</width>
+                                               <x>"6.2225 in"</x>
+                                               <y>5</y>
+                                       </String>
+                                       <String>
+                                               <align>"right"</align>
+                                               <expr>"Amount"</expr>
+                                               <hAnchor>"right"</hAnchor>
+                                               <Height>'11.0 pt'</Height>
+                                               <width>'0.5832 in'</width>
+                                               <x>"6.925 in"</x>
+                                               <y>5</y>
+                                       </String>
+                               </Objects>
+                       </GroupHeader>
+                       <GroupFooter>
+                               <Objects></Objects>
+                       </GroupFooter>
+               </Group>
+               <Group>
+                       <expr>self.timecodeid</expr>
+                       <reprintHeaderOnNewPage>True</reprintHeaderOnNewPage>
+                       <startOnNewPage>False</startOnNewPage>
+                       <groupHeader>
+                               <height>"0.25 in"</height>
+                               <objects>
+                                       <Rectangle>
+                                               <fillColor>(.3, .3, 
.3)</fillColor>
+                                               <height>".25 in"</height>
+                                               <strokeWidth>".25 
pt"</strokeWidth>
+                                               <width>"7 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>0</y>
+                                       </Rectangle>
+                                       <String>
+                                               <align>"center"</align>
+                                               <expr>"%s: %s%s" % 
(self.timecode, self.timecodename, self.recordsPrinted_timecode > 1 and "   
(continued)" or "")</expr>
+                                               <fontColor>(1,1,1)</fontColor>
+                                               <fontItalic>True</fontItalic>
+                                               <height>15</height>
+                                               <width>"7 in"</width>
+                                               <x>"0.0 in"</x>
+                                               <y>5</y>
+                                       </String>
+                               </objects>
+                       </groupHeader>
+                       <groupFooter>
+                               <height>"0.25 in"</height>
+                               <objects>
+                                       <Rectangle>
+                                               <height>".25 in"</height>
+                                               <strokeWidth>".25 
pt"</strokeWidth>
+                                               <width>"7 in"</width>
+                                               <x>"0 in"</x>
+                                               <y>1</y>
+                                       </Rectangle>
+                                       <String>
+                                               <align>"right"</align>
+                                               <expr>"Total for code %s:       
     $ %s" % (self.Record["timecode"], locale.format('%.2f', 
self.Variables["timeCodeBalance"], True))</expr>
+                                               <fontItalic>True</fontItalic>
+                                               <hAnchor>"right"</hAnchor>
+                                               <height>15</height>
+                                               <width>"6.5 in"</width>
+                                               <x>"6.925 in"</x>
+                                               <y>6</y>
+                                       </String>
+                               </objects>
+                       </groupFooter>
+               </Group>
+       </groups>
+
+       <pageBackground>
+               <objects>
+                       <Rectangle>
+                               <height>.25</height>
+                               <strokeColor>(.7,.7,.7)</strokeColor>
+                               <width>.25</width>
+                               <x>".25 in"</x>
+                               <y>"6.875 in"</y>
+                       </Rectangle>
+                       <Rectangle>
+                               <height>.25</height>
+                               <strokeColor>(.7,.7,.7)</strokeColor>
+                               <width>.25</width>
+                               <x>"6.75 in"</x>
+                               <y>"6.875 in"</y>
+                       </Rectangle>
+               </objects>
+       </pageBackground>
+
+       <pageHeader>
+               <height>"1.75 in"</height>
+               <Objects>
+                       <Rectangle>
+                               <fillColor>(1, 1, 1)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".5 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"3 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1</x>
+                               <y>"0.65 in"</y>
+                       </Rectangle>
+                       <Rectangle>
+                               <fillColor>(1, 1, 1)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".3 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1</x>
+                               <y>"0.65 in"</y>
+                       </Rectangle>
+                       <Image>
+                               <borderColor>(.7, .7, .7)</borderColor>
+                               <borderWidth>0</borderWidth>
+                               <expr>"logo_2cannisters_medium.jpg"</expr>
+                               <height>"1.22 in"</height>
+                               <mode>"scale"</mode>
+                               <width>"0.95 in"</width>
+                               <x>"0 in"</x>
+                               <y>"0.6375 in"</y>
+                       </Image>
+                       <String>
+                               <align>"left"</align>
+                               <borderWidth>"0 pt"</borderWidth>
+                               <expr>"Paul McNett"</expr>
+                               <fontBold>True</fontBold>
+                               <FontName>"Helvetica"</FontName>
+                               <fontSize>14</fontSize>
+                               <hAnchor>"left"</hAnchor>
+                               <height>16</height>
+                               <name>companyName</name>
+                               <vAlign>"top"</vAlign>
+                               <vAnchor>"top"</vAnchor>
+                               <Width>"2.875 in"</Width>
+                               <x>"1.1 in"</x>
+                               <y>"1.7875 in"</y>
+                       </String>
+                       <String>
+                               <align>"left"</align>
+                               <borderWidth>"0 pt"</borderWidth>
+                               <expr>"881 B Street"</expr>
+                               <fontName>"Helvetica"</fontName>
+                               <fontSize>14</fontSize>
+                               <hAnchor>"left"</hAnchor>
+                               <height>16</height>
+                               <name>companyAddress1</name>
+                               <vAlign>"top"</vAlign>
+                               <vAnchor>"top"</vAnchor>
+                               <Width>"2.875 in"</Width>
+                               <x>"1.1 in"</x>
+                               <y>"1.5575 in"</y>
+                       </String>
+                       <String>
+                               <align>"left"</align>
+                               <borderWidth>"0 pt"</borderWidth>
+                               <expr>"Hollister, CA  95023"</expr>
+                               <fontName>"Helvetica"</fontName>
+                               <fontSize>14</fontSize>
+                               <hAnchor>"left"</hAnchor>
+                               <height>16</height>
+                               <name>companyAddress1</name>
+                               <vAlign>"top"</vAlign>
+                               <vAnchor>"top"</vAnchor>
+                               <Width>"2.875 in"</Width>
+                               <x>"1.1 in"</x>
+                               <y>"1.3275 in"</y>
+                       </String>
+                       <String>
+                               <align>"left"</align>
+                               <borderWidth>"0 pt"</borderWidth>
+                               <expr>"(831) 636-9900"</expr>
+                               <fontName>"Helvetica"</fontName>
+                               <fontSize>14</fontSize>
+                               <hAnchor>"left"</hAnchor>
+                               <height>16</height>
+                               <name>companyAddress1</name>
+                               <vAlign>"top"</vAlign>
+                               <vAnchor>"top"</vAnchor>
+                               <Width>"2.875 in"</Width>
+                               <x>"1.1 in"</x>
+                               <y>"1.0975 in"</y>
+                       </String>
+                       <String>
+                               <align>"right"</align>
+                               <borderWidth>"0 pt"</borderWidth>
+                               <expr>"Invoice"</expr>
+                               <fontName>"Helvetica"</fontName>
+                               <fontSize>36</fontSize>
+                               <hAnchor>"right"</hAnchor>
+                               <height>30</height>
+                               <name>title</name>
+                               <vAlign>"top"</vAlign>
+                               <vAnchor>"top"</vAnchor>
+                               <width>'2.9992 in'</width>
+                               <x>self.Bands["pageHeader"]["width"]-1</x>
+                               <y>self.Bands["pageHeader"]["height"]</y>
+                       </String>
+                       <Rectangle>
+                               <fillColor>(.9, .9, .9)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".2 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1</x>
+                               <y>"0.95 in"</y>
+                       </Rectangle>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"Due"</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1</x>
+                               <y>"1 in"</y>
+                       </String>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"%s %s %s" % (self.duedate.day, 
self.duedate.strftime("%b"), self.duedate.year)</expr>
+                               <fontSize>12</fontSize>
+                               <hAnchor>"Left"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>'430.0 pt'</x>
+                               <y>'0.7500 in'</y>
+                       </String>
+                       <Rectangle>
+                               <fillColor>(.9, .9, .9)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".2 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72</x>
+                               <y>"0.95 in"</y>
+                       </Rectangle>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"Date"</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72</x>
+                               <y>"1 in"</y>
+                       </String>
+                       <Rectangle>
+                               <fillColor>(1, 1, 1)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".3 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72</x>
+                               <y>"0.65 in"</y>
+                       </Rectangle>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"%s %s %s" % (self.invdate.day, 
self.invdate.strftime("%b"), self.invdate.year)</expr>
+                               <fontSize>12</fontSize>
+                               <hAnchor>"Left"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>'359.0 pt'</x>
+                               <y>'0.7500 in'</y>
+                       </String>
+                       <Rectangle>
+                               <fillColor>(.9, .9, .9)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".2 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72 - 
72</x>
+                               <y>"0.95 in"</y>
+                       </Rectangle>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"Invoice #"</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72 - 
72</x>
+                               <y>"1 in"</y>
+                       </String>
+                       <Rectangle>
+                               <fillColor>(1, 1, 1)</fillColor>
+                               <hAnchor>"right"</hAnchor>
+                               <height>".3 in"</height>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"1 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72 - 
72</x>
+                               <y>"0.65 in"</y>
+                       </Rectangle>
+                       <String>
+                               <align>"center"</align>
+                               <expr>self.invnum</expr>
+                               <fontSize>12</fontSize>
+                               <hAnchor>"Left"</hAnchor>
+                               <height>15</height>
+                               <width>"1 in"</width>
+                               <x>'287.0 pt'</x>
+                               <y>'0.7500 in'</y>
+                       </String>
+                       <String>
+                               <align>"center"</align>
+                               <expr>"COPY"</expr>
+                               <fontColor>(.7, .1, .1)</fontColor>
+                               <fontSize>24</fontSize>
+                               <hAnchor>"center"</hAnchor>
+                               <height>"1 in"</height>
+                               <rotation>33</rotation>
+                               <show>self.Record["copy"] == True</show>
+                               <width>"2 in"</width>
+                               <x>self.Bands["pageHeader"]["width"]-1 - 72 - 
72 - 60</x>
+                               <y>"0.64 in"</y>
+                       </String>
+               </Objects>
+       </pageHeader>
+
+       <detail>
+               <height>None</height>
+               <Objects>
+                       <Rectangle>
+                               
<height>self.Bands["detail"]["TotalHeight"]</height>
+                               <name>test2</name>
+                               <strokeWidth>".25 pt"</strokeWidth>
+                               <width>"7 in"</width>
+                               <x>"0 in"</x>
+                               <y>self.Bands["detail"]["Height"]</y>
+                               <vAnchor>"top"</vAnchor>
+                       </Rectangle>
+                       <String>
+                               <expr>"%s %s" % (self.Record["date"].day, 
self.Record["date"].strftime("%b"))</expr>
+                               <height>12</height>
+                               <vAnchor>"top"</vAnchor>
+                               <width>"0.60 in"</width>
+                               <x>"0.025 in"</x>
+                               <y>self.Bands["detail"]["height"]</y>
+                       </String>
+                       <Frameset>
+                               <borderWidth>0</borderWidth>
+                               <height>None</height>
+                               <padBottom>4</padBottom>
+                               <padTop>2</padTop>
+                               <vAnchor>"top"</vAnchor>
+                               <width>"4.6225 in"</width>
+                               <x>"0.6075 in"</x>
+                               <y>self.Bands["detail"]["height"]</y>
+                               <objects>
+                                       <Paragraph>
+                                               
<expr>self.Record["invdesc"]</expr>
+                                               <fontName>"Helvetica"</fontName>
+                                       </Paragraph>
+                               </objects>
+                       </Frameset>
+                       <String>
+                               <align>"right"</align>
+                               <expr>self.Record["hours"]</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>12</height>
+                               <show>self.Record["mode"] == 1</show>
+                               <vAnchor>"top"</vAnchor>
+                               <width>'0.4166 in'</width>
+                               <x>"5.6975 in"</x>
+                               <y>self.Bands["detail"]["height"]</y>
+                       </String>
+                       <String>
+                               <align>"right"</align>
+                               <expr>"$%s" % int(self.Record["rate"])</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>12</height>
+                               <show>self.Record["mode"] == 1</show>
+                               <vAnchor>"top"</vAnchor>
+                               <width>'0.4166 in'</width>
+                               <x>"6.2225 in"</x>
+                               <y>self.Bands["detail"]["height"]</y>
+                       </String>
+                       <String>
+                               <align>"right"</align>
+                               <expr>locale.format("%.2f", 
self.Record["amount"], True)</expr>
+                               <hAnchor>"right"</hAnchor>
+                               <height>12</height>
+                               <vAnchor>"top"</vAnchor>
+                               <width>'0.5832 in'</width>
+                               <x>"6.925 in"</x>
+                               <y>self.Bands["detail"]["height"]</y>
+                       </String>
+                       <Line>
+                               <height>self.Ban

 (32312 bytes were truncated as it was too long for the email (max 40000 bytes.)

_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev
Searchable Archives: http://leafe.com/archives/search/dabo-dev
This message: 
http://leafe.com/archives/byMID/[email protected]

Reply via email to