[reportlab-users] question about keepWithNext and multibuild

adam hyde adam at flossmanuals.net
Tue Sep 23 13:47:03 EDT 2008


goodness...it appears to work :)

I patched reportlab 2.1 and it looks good. I will run some more tests
today and tomorrow and let confirm the situation, but from what I see
now it is holding the keepWithNext while building the TOC. Fantastic!
Many thanks for all your help!

adam



On Tue, 2008-09-23 at 18:03 +0100, Robin Becker wrote:

> 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

>

> plain text document attachment (mbe.patch)

> 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

> _______________________________________________

> reportlab-users mailing list

> reportlab-users at reportlab.com

> http://two.pairlist.net/mailman/listinfo/reportlab-users

--
Adam Hyde
Founder FLOSS Manuals
http://www.flossmanuals.net



More information about the reportlab-users mailing list