reportlab/platypus/doctemplate.py
changeset 2192 955d4bf3b9d2
parent 2127 d5e43db37d59
child 2193 e19196dc3942
--- a/reportlab/platypus/doctemplate.py	Wed Jan 07 16:36:34 2004 +0000
+++ b/reportlab/platypus/doctemplate.py	Wed Jan 07 22:58:54 2004 +0000
@@ -1,9 +1,9 @@
 #copyright ReportLab Inc. 2000
 #see license.txt for license details
 #history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/doctemplate.py?cvsroot=reportlab
-#$Header: /tmp/reportlab/reportlab/platypus/doctemplate.py,v 1.68 2003/11/13 17:15:19 william_ng Exp $
+#$Header: /tmp/reportlab/reportlab/platypus/doctemplate.py,v 1.69 2004/01/07 22:58:54 andy_robinson Exp $
 
-__version__=''' $Id: doctemplate.py,v 1.68 2003/11/13 17:15:19 william_ng Exp $ '''
+__version__=''' $Id: doctemplate.py,v 1.69 2004/01/07 22:58:54 andy_robinson Exp $ '''
 
 __doc__="""
 This module contains the core structure of platypus.
@@ -38,6 +38,8 @@
 from types import *
 import sys
 
+class LayoutError(Exception):
+    pass
 
 def _doNothing(canvas, doc):
     "Dummy callback for onPage"
@@ -111,6 +113,9 @@
     def __call__(self):
         return self
 
+    def identity(self, maxLen=None):
+        return "ActionFlowable: %s" % str(self.action)
+    
 class NextFrameFlowable(ActionFlowable):
     def __init__(self,ix,resume=0):
         ActionFlowable.__init__(self,('nextFrame',ix,resume))
@@ -306,6 +311,12 @@
         self._onProgress = None
         self._flowableCount = 0  # so we know how far to go
 
+
+        #infinite loop detection if we start doing lots of empty pages
+        self._curPageFlowableCount = 0
+        self._emptyPages = 0
+        self._emptyPagesAllowed = 3
+
         #context sensitive margins - set by story, not from outside
         self._leftExtraIndent = 0.0
         self._rightExtraIndent = 0.0
@@ -357,6 +368,8 @@
         self.pageTemplate.onPage(self.canv,self)
         for f in self.pageTemplate.frames: f._reset()
         self.beforePage()
+        #keep a count of flowables added to this page.  zero indicates bad stuff
+        self._curPageFlowableCount = 0
         if hasattr(self,'_nextFrameIndex'):
             del self._nextFrameIndex
         self.frame = self.pageTemplate.frames[0]
@@ -367,6 +380,15 @@
             check the next page template
             hang a page begin
         '''
+        #detect infinite loops...
+        if self._curPageFlowableCount == 0:
+            self._emptyPages = self._emptyPages + 1
+        else:
+            self._emptyPages = 0
+        if self._emptyPages >= self._emptyPagesAllowed:
+            raise LayoutError("More than %d pages generated without content - halting layout.  Likely that a flowable is too large for any frame." % self._emptyPagesAllowed)
+
+
         if self._onProgress:
             self._onProgress('PAGE', self.canv.getPageNumber())
         self.pageTemplate.afterDrawPage(self.canv, self)
@@ -507,6 +529,7 @@
         self.handle_breakBefore(flowables)
         self.handle_keepWithNext(flowables)
         f = flowables[0]
+        #print 'handling flowable %s' % f.identity()
         del flowables[0]
         if f is None:
             return
@@ -520,6 +543,7 @@
         else:
             #try to fit it then draw it
             if self.frame.add(f, self.canv, trySplit=self.allowSplitting):
+                self._curPageFlowableCount = self._curPageFlowableCount + 1
                 self.afterFlowable(f)
             else:
                 #if isinstance(f, KeepTogether): print 'could not add it to frame'
@@ -533,6 +557,7 @@
                 #if isinstance(f, KeepTogether): print 'n=%d' % n
                 if n:
                     if self.frame.add(S[0], self.canv, trySplit=0):
+                        self._curPageFlowableCount = self._curPageFlowableCount + 1
                         self.afterFlowable(S[0])
                     else:
                         print 'n = %d' % n
@@ -545,6 +570,7 @@
 ##                  if hasattr(f,'postponed'):
                     if hasattr(f,'_postponed'):
                         message = "Flowable %s too large on page %d" % (f.identity(30), self.page)
+                        #print message
                         #show us, it might be handy
                         #HACK = it seems within tables we sometimes
                         #get an empty paragraph that won't fit and this