pythonreportlabtableofcontents

Add figure and tables list to Table of Content using reportlab


I am latest reportlab and django, and standard platypus TOC with the notify to 'TOCEntry' works great for my document.

I am now trying to add 2 more sections to Table of Contents: 'List of Figures', and 'List of Tables'. Since the flowables h1, h2, table, image etc. in the document can occur in any order, I cannot seem to separate the 2 lists from the main TOC. Ideally I would like to have something like:

Table of Content:

Heading1
  Sub1
  Sub2
Heading2
  Sub3
  Sub4
  Sub5

List of Figures:
  Figure1
  Figure2

List of Tables:
  Table1
  Table2

As far as I understand, the 'TOCEntry' is the tag looked up, and using AfterFlowable ends up putting all flowables in the same sequence as shown in the actual document. And this is not what I want. Any pointers to getting TOC to look somewhat like above depiction would be highly appreciated.


Solution

  • I figured that the simplest approach was to subclass TOCs, and add afterFlowable catchers for them in the docTemplate.

    class MyDocTemplate(BaseDocTemplate):  
         def __init__(self, filename, **kw):  
             self.allowSplitting = 0  
             apply(BaseDocTemplate.__init__, (self, filename), kw)  
             template = PageTemplate('normal', [Frame(1*inch, 1*inch, 6.5*inch, 9.5*inch, id='F1')])
             self.addPageTemplates(template)  
    
         def afterFlowable(self, flowable):  
             "Registers TOC entries."  
             if flowable.__class__.__name__ == 'Paragraph':  
                 text = flowable.getPlainText()  
                 style = flowable.style.name  
    
                 if style == 'reportHeading1':
                     toc_el = [ 0, text, self.page ] # basic elements
                     toc_bm = getattr(flowable, '_bookmarkName', None) # bookmark for links
                     if toc_bm: 
                         toc_el.append( toc_bm )
                     self.notify('TOCEntry', tuple(toc_el) )
    
                 elif style == 'reportHeading2':  
                     toc_el = [ 1, text, self.page ] # basic elements
                     toc_bm = getattr(flowable, '_bookmarkName', None) # bookmark for links
                     if toc_bm: 
                         toc_el.append( toc_bm )
                     self.notify('TOCEntry', tuple(toc_el) )
    
                 elif style == 'TableTitleStyle':
                     toc_el = [ 1, text, self.page ] # basic elements
                     toc_bm = getattr(flowable, '_bookmarkName', None) # bookmark for links
                     if toc_bm: 
                         toc_el.append( toc_bm )
                     self.notify('TOCTable', tuple(toc_el) )
    
                 elif style == 'GraphicTitleStyle':
                     toc_el = [ 1, text, self.page ] # basic elements
                     toc_bm = getattr(flowable, '_bookmarkName', None) # bookmark for links
                     if toc_bm: 
                         toc_el.append( toc_bm )
                     self.notify('TOCFigure', tuple(toc_el) )
    

    Secondary Tables of Content for Figures and Tables:

    class ListOfFigures(TableOfContents):
        def notify(self, kind, stuff):
            """ The notification hook called to register all kinds of events.
                Here we are interested in 'Figure' events only.
            """
            if kind == 'TOCFigure':
                self.addEntry(*stuff)
    
    
    class ListOfTables(TableOfContents):
        def notify(self, kind, stuff):
            """ The notification hook called to register all kinds of events.
                Here we are interested in 'Table' events only.
            """
            if kind == 'TOCTable':
                self.addEntry(*stuff)
    

    And then finally in the doc generation process. I would add the instances of ListOfTables and ListOfFigures after the standard TOC to have it look like they are somewhat related in the actual pdf.