reportlab/platypus/doctemplate.py
changeset 2955 cc16265295fb
parent 2950 6c243412b06c
child 2956 5c17941635bd
equal deleted inserted replaced
2954:5ec6485e810a 2955:cc16265295fb
    33 from reportlab.platypus.paragraph import Paragraph
    33 from reportlab.platypus.paragraph import Paragraph
    34 from reportlab.platypus.frames import Frame
    34 from reportlab.platypus.frames import Frame
    35 from reportlab.rl_config import defaultPageSize, verbose
    35 from reportlab.rl_config import defaultPageSize, verbose
    36 import reportlab.lib.sequencer
    36 import reportlab.lib.sequencer
    37 from reportlab.pdfgen import canvas
    37 from reportlab.pdfgen import canvas
       
    38 import tokenize
    38 
    39 
    39 from types import *
    40 from types import *
    40 import sys
    41 import sys
    41 import logging
    42 import logging
    42 logger = logging.getLogger("reportlab.platypus")
    43 logger = logging.getLogger("reportlab.platypus")
   336     _firstPageTemplateIndex = 0
   337     _firstPageTemplateIndex = 0
   337 
   338 
   338     def __init__(self, filename, **kw):
   339     def __init__(self, filename, **kw):
   339         """create a document template bound to a filename (see class documentation for keyword arguments)"""
   340         """create a document template bound to a filename (see class documentation for keyword arguments)"""
   340         self.filename = filename
   341         self.filename = filename
       
   342         self._nameSpace = dict(doc=self)
       
   343         self._lifetimes = {}
   341 
   344 
   342         for k in self._initArgs.keys():
   345         for k in self._initArgs.keys():
   343             if not kw.has_key(k):
   346             if not kw.has_key(k):
   344                 v = self._initArgs[k]
   347                 v = self._initArgs[k]
   345             else:
   348             else:
   432     def handle_pageEnd(self):
   435     def handle_pageEnd(self):
   433         ''' show the current page
   436         ''' show the current page
   434             check the next page template
   437             check the next page template
   435             hang a page begin
   438             hang a page begin
   436         '''
   439         '''
       
   440         self._removeVars('page')
   437         #detect infinite loops...
   441         #detect infinite loops...
   438         if self._curPageFlowableCount == 0:
   442         if self._curPageFlowableCount == 0:
   439             self._emptyPages += 1
   443             self._emptyPages += 1
   440         else:
   444         else:
   441             self._emptyPages = 0
   445             self._emptyPages = 0
   486 
   490 
   487     def handle_frameEnd(self,resume=0):
   491     def handle_frameEnd(self,resume=0):
   488         ''' Handles the semantics of the end of a frame. This includes the selection of
   492         ''' Handles the semantics of the end of a frame. This includes the selection of
   489             the next frame or if this is the last frame then invoke pageEnd.
   493             the next frame or if this is the last frame then invoke pageEnd.
   490         '''
   494         '''
       
   495         self._removeVars('frame')
   491         self._leftExtraIndent = self.frame._leftExtraIndent
   496         self._leftExtraIndent = self.frame._leftExtraIndent
   492         self._rightExtraIndent = self.frame._rightExtraIndent
   497         self._rightExtraIndent = self.frame._rightExtraIndent
   493 
   498 
   494         f = self.frame
   499         f = self.frame
   495         if hasattr(self,'_nextFrameIndex'):
   500         if hasattr(self,'_nextFrameIndex'):
   555         else:
   560         else:
   556             raise TypeError, "argument fx should be string or integer"
   561             raise TypeError, "argument fx should be string or integer"
   557 
   562 
   558     def handle_currentFrame(self,fx,resume=0):
   563     def handle_currentFrame(self,fx,resume=0):
   559         '''change to the frame with name or index fx'''
   564         '''change to the frame with name or index fx'''
   560 
       
   561         self.handle_nextFrame(fx,resume)
   565         self.handle_nextFrame(fx,resume)
   562         self.handle_frameEnd(resume)
   566         self.handle_frameEnd(resume)
   563 
   567 
   564     def handle_breakBefore(self, flowables):
   568     def handle_breakBefore(self, flowables):
   565         '''preprocessing step to allow pageBreakBefore and frameBreakBefore attributes'''
   569         '''preprocessing step to allow pageBreakBefore and frameBreakBefore attributes'''
   692     def _startBuild(self, filename=None, canvasmaker=canvas.Canvas):
   696     def _startBuild(self, filename=None, canvasmaker=canvas.Canvas):
   693         self._calc()
   697         self._calc()
   694 
   698 
   695         #each distinct pass gets a sequencer
   699         #each distinct pass gets a sequencer
   696         self.seq = reportlab.lib.sequencer.Sequencer()
   700         self.seq = reportlab.lib.sequencer.Sequencer()
   697         
   701 
   698         self.canv = canvasmaker(filename or self.filename,
   702         self.canv = canvasmaker(filename or self.filename,
   699                                 pagesize=self.pagesize,
   703                                 pagesize=self.pagesize,
   700                                 invariant=self.invariant,
   704                                 invariant=self.invariant,
   701                                 pageCompression=self.pageCompression)
   705                                 pageCompression=self.pageCompression)
   702 
   706 
   708         if self._onPage:
   712         if self._onPage:
   709             self.canv.setPageCallBack(self._onPage)
   713             self.canv.setPageCallBack(self._onPage)
   710         self.handle_documentBegin()
   714         self.handle_documentBegin()
   711 
   715 
   712     def _endBuild(self):
   716     def _endBuild(self):
       
   717         self._removeVars('build')
   713         if self._hanging!=[] and self._hanging[-1] is PageBegin:
   718         if self._hanging!=[] and self._hanging[-1] is PageBegin:
   714             del self._hanging[-1]
   719             del self._hanging[-1]
   715             self.clean_hanging()
   720             self.clean_hanging()
   716         else:
   721         else:
   717             self.clean_hanging()
   722             self.clean_hanging()
   883 
   888 
   884     def afterFlowable(self, flowable):
   889     def afterFlowable(self, flowable):
   885         '''called after a flowable has been rendered'''
   890         '''called after a flowable has been rendered'''
   886         pass
   891         pass
   887 
   892 
       
   893     _allowedLifetimes = 'page','frame','build','forever'
       
   894     def docAssign(self,var,expr,lifetime):
       
   895         var=var.strip()+'\n'
       
   896         expr=expr.strip()
       
   897         T=tokenize.generate_tokens(lambda :var)
       
   898         tokens=[]
       
   899         while 1:
       
   900             t=T.next()
       
   901             if t[0]==tokenize.NEWLINE: break
       
   902             tokens.append(t)
       
   903         simple = len(tokens)==1
       
   904         del T
       
   905         var=var.strip()
       
   906         try:
       
   907             if lifetime not in self._allowedLifetimes:
       
   908                 raise ValueError('bad lifetime %r not in %r'%(lifetime,self._allowedLifetimes))
       
   909             exec '%s=(%s)' % (var,expr) in {},self._nameSpace
       
   910         except:
       
   911             exc = sys.exc_info()[1]
       
   912             args = list(exc.args)
       
   913             args[-1] += '\ndocAssign %s=(%s) lifetime=%r failed!' % (var,expr,lifetime)
       
   914             exc.args = tuple(args)
       
   915             raise
       
   916         if simple:
       
   917             for v in self._lifetimes.itervalues():
       
   918                 if var in v:
       
   919                     v.remove(var)
       
   920             self._lifetimes.setdefault(lifetime,set([])).add(var)
       
   921 
       
   922     def docExec(self,stmt):
       
   923         stmt=stmt.strip()
       
   924         try:
       
   925             exec stmt in {},self._nameSpace
       
   926         except:
       
   927             exc = sys.exc_info()[1]
       
   928             args = list(exc.args)
       
   929             args[-1] += '\ndocExec %s failed!' % stmt
       
   930             exc.args = tuple(args)
       
   931             raise
       
   932 
       
   933     def _removeVars(self,lifetime):
       
   934         for k in self._lifetimes.setdefault(lifetime,[]):
       
   935             try:
       
   936                 del self._nameSpace[k]
       
   937             except KeyError:
       
   938                 pass
       
   939         del self._lifetimes[lifetime]
       
   940 
       
   941     def docEval(self,expr):
       
   942         try:
       
   943             return eval(expr.strip(),{},self._nameSpace)
       
   944         except:
       
   945             exc = sys.exc_info()[1]
       
   946             args = list(exc.args)
       
   947             args[-1] += '\ndocEval %s failed!' % expr
       
   948             exc.args = tuple(args)
       
   949             raise
       
   950 
   888 class SimpleDocTemplate(BaseDocTemplate):
   951 class SimpleDocTemplate(BaseDocTemplate):
   889     """A special case document template that will handle many simple documents.
   952     """A special case document template that will handle many simple documents.
   890        See documentation for BaseDocTemplate.  No pageTemplates are required
   953        See documentation for BaseDocTemplate.  No pageTemplates are required
   891        for this special case.   A page templates are inferred from the
   954        for this special case.   A page templates are inferred from the
   892        margin information and the onFirstPage, onLaterPages arguments to the build method.
   955        margin information and the onFirstPage, onLaterPages arguments to the build method.