[reportlab-users] question about keepWithNext and multibuild

Robin Becker robin at reportlab.com
Tue Sep 23 13:03:38 EDT 2008


adam hyde wrote:

>........

> So we are really needing to build a TOC without multipass. We just pick

> up on h1 headings using Pisa as this is the only depth required in a

> book TOC for our purposes. If anyone has a nice snippet for producing a

> TOC without multipass we would very much appreciate it.

>

> adam

.........

At the moment the keepTogether style is handled thusly;

in the main loop of the doctemplate build process at the start of the flowable
handling the head of the list is examined for flowables with keepWithNext style.
If any are found these are bundled together and replaced by a single
KeepTogether flowable; to avoid doing this recursively we force the keepWithNext
value for each flowable to be zero.

KeepTogether has just enough intelligence to try and ensure its contents stay on
a single page and when wrapped it always fails first time inorder to allow the
split method a chance to force a frame throw.

Even though we've messed about with the current passed story quite a bit the
main problem is that we changed the keepWithNext attribute on each flowable we
bundled together. The multiBuild method is careful to keep the original story
list intact, but we have forgotten that flowables are mutable (in this case a
structural property of the flowable was changed).

It should be possible to just remember the flowables which have been modified by
the handle_keepWithNext method and restore them at the end of the loop. After
checking I see that we are already attempting to eliminate some side effects of
the main loop.


I have run all tests with this patch in place. It attempts to fix the
keepWithNext values back to their original state. Can you give it a whirl? It is
against current head, but the coding is not that hard so should apply to recent
sources.

C:\code\reportlab\platypus>svn diff doctemplate.py
Index: doctemplate.py
===================================================================
--- doctemplate.py (revision 3298)
+++ doctemplate.py (working copy)
@@ -600,8 +600,17 @@
if i:
if i<n and not getattr(flowables[i],'locChanger',None): i += 1
K = KeepTogether(flowables[:i])
- for f in K._content[:-1]:
- f.__dict__['keepWithNext'] = 0
+ mbe = getattr(self,'_multiBuildEdits',None)
+ if mbe:
+ for f in K._content[:-1]:
+ if hasattr(f,'keepWithNext'):
+ mbe((setattr,f,'keepWithNext',f.keepWithNext))
+ else:
+ mbe((delattr,f,'keepWithNext')) #must get it from a style
+ f.__dict__['keepWithNext'] = 0
+ else:
+ for f in K._content[:-1]:
+ f.__dict__['keepWithNext'] = 0
del flowables[:i]
flowables.insert(0,K)

@@ -818,6 +827,8 @@
#better fix for filename is a 'file' problem
self._doSave = 0
passes = 0
+ mbe = []
+ self._multiBuildEdits = mbe.append
while 1:
passes += 1
if self._onProgress:
@@ -832,12 +843,6 @@
self.build(tempStory, filename, canvasmaker)
#self.notify('debug',None)

- #clean up so multi-build does not go wrong - the frame
- #packer might have tacked an attribute onto some flowables
- for elem in story:
- if hasattr(elem, '_postponed'):
- del elem._postponed
-
for fl in self._indexingFlowables:
fl.afterBuild()

@@ -850,6 +855,18 @@
if passes > maxPasses:
raise IndexError, "Index entries not resolved after %d passes"
% maxPasses

+ #clean up so multi-build does not go wrong - the frame
+ #packer might have tacked an attribute onto some flowables
+ for elem in story:
+ if hasattr(elem, '_postponed'):
+ del elem._postponed
+
+ #work through any edits
+ while mbe:
+ e = mbe.pop(0)
+ e[0](*e[1:])
+
+ del self._multiBuildEdits
if verbose: print 'saved'

#these are pure virtuals override in derived classes

--
Robin Becker
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: mbe.patch
Url: <http://two.pairlist.net/pipermail/reportlab-users/attachments/20080923/e42c3027/attachment.ksh>


More information about the reportlab-users mailing list