5326: Add Alphabetical Index and Table of Contents generation for pdf reports
svn: r18842
This commit is contained in:
@@ -72,7 +72,7 @@ import Utils
|
||||
import ListModel
|
||||
import Errors
|
||||
from gui.pluginmanager import GuiPluginManager
|
||||
from gen.plug.docgen import StyleSheet, StyleSheetList, PaperStyle
|
||||
from gen.plug.docgen import StyleSheet, StyleSheetList, PaperStyle, IndexOptions
|
||||
from QuestionDialog import WarningDialog, ErrorDialog
|
||||
from gen.plug.menu import PersonOption, FilterOption, FamilyOption
|
||||
import ManagedWindow
|
||||
@@ -85,6 +85,7 @@ from gen.plug.report import CATEGORY_BOOK, book_categories
|
||||
from gui.plug.report._reportdialog import ReportDialog
|
||||
from gui.plug.report._docreportdialog import DocReportDialog
|
||||
from gen.plug.report._options import ReportOptions
|
||||
from gen.plug.report.toc_index import add_toc_index_styles
|
||||
from cli.plug import CommandLineReport
|
||||
import cli.user
|
||||
|
||||
@@ -1203,6 +1204,7 @@ class BookReportDialog(DocReportDialog):
|
||||
default_style = StyleSheet()
|
||||
make_default_style = item.option_class.make_default_style
|
||||
make_default_style(default_style)
|
||||
add_toc_index_styles(default_style)
|
||||
|
||||
# Read all style sheets available for this item
|
||||
style_file = item.option_class.handler.get_stylesheet_savefile()
|
||||
@@ -1255,7 +1257,14 @@ class BookReportDialog(DocReportDialog):
|
||||
def make_document(self):
|
||||
"""Create a document of the type requested by the user."""
|
||||
pstyle = self.paper_frame.get_paper_style()
|
||||
self.doc = self.format(self.selected_style, pstyle)
|
||||
|
||||
if self.format_menu.get_active_plugin().get_index_support():
|
||||
index_opts = IndexOptions(self.toc.get_active(),
|
||||
self.index.get_active())
|
||||
else:
|
||||
index_opts = None
|
||||
|
||||
self.doc = self.format(self.selected_style, pstyle, index_opts)
|
||||
user = gui.user.User()
|
||||
self.rptlist = []
|
||||
for item in self.book.get_item_list():
|
||||
@@ -1319,6 +1328,7 @@ def cl_report(database, name, category, options_str_dict):
|
||||
default_style = StyleSheet()
|
||||
make_default_style = item.option_class.make_default_style
|
||||
make_default_style(default_style)
|
||||
add_toc_index_styles(default_style)
|
||||
|
||||
# Read all style sheets available for this item
|
||||
style_file = item.option_class.handler.get_stylesheet_savefile()
|
||||
|
||||
@@ -130,8 +130,8 @@ def reformat_para(para='',left=0,right=72,just=LEFT,right_pad=0,first=0):
|
||||
#------------------------------------------------------------------------
|
||||
class AsciiDoc(BaseDoc,TextDoc):
|
||||
|
||||
def __init__(self, styles, type):
|
||||
BaseDoc.__init__(self, styles, type)
|
||||
def __init__(self, styles, type, index_opts):
|
||||
BaseDoc.__init__(self, styles, type, index_opts)
|
||||
self.__note_format = False
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -93,8 +93,8 @@ class HtmlDoc(BaseDoc, TextDoc):
|
||||
Fontface is removed. Size, italic, bold, margins, borders are retained
|
||||
"""
|
||||
|
||||
def __init__(self, styles, paper_style):
|
||||
BaseDoc.__init__(self, styles, None)
|
||||
def __init__(self, styles, paper_style, index_opts):
|
||||
BaseDoc.__init__(self, styles, None, index_opts)
|
||||
self.style_declaration = ''
|
||||
self.htmllist = []
|
||||
self._backend = None
|
||||
|
||||
@@ -433,11 +433,11 @@ class ODFDoc(BaseDoc, TextDoc, DrawDoc):
|
||||
The ODF document class
|
||||
"""
|
||||
|
||||
def __init__(self, styles, ftype):
|
||||
def __init__(self, styles, ftype, index_opts):
|
||||
"""
|
||||
Class init
|
||||
"""
|
||||
BaseDoc.__init__(self, styles, ftype)
|
||||
BaseDoc.__init__(self, styles, ftype, index_opts)
|
||||
self.media_list = []
|
||||
self.init_called = False
|
||||
self.cntnt = None
|
||||
|
||||
@@ -56,8 +56,8 @@ def coords(grp):
|
||||
#-------------------------------------------------------------------------
|
||||
class PSDrawDoc(BaseDoc, DrawDoc):
|
||||
|
||||
def __init__(self, styles, type):
|
||||
BaseDoc.__init__(self, styles, type)
|
||||
def __init__(self, styles, type, index_opts):
|
||||
BaseDoc.__init__(self, styles, type, index_opts)
|
||||
self.file = None
|
||||
self.filename = None
|
||||
self.level = 0
|
||||
|
||||
@@ -38,6 +38,8 @@ import sys
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import libcairodoc
|
||||
from gen.plug.docgen import INDEX_TYPE_ALP, INDEX_TYPE_TOC
|
||||
from gen.plug.report.toc_index import write_toc, write_index
|
||||
import Errors
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -85,6 +87,10 @@ class PdfDoc(libcairodoc.CairoDoc):
|
||||
left_margin = self.paper.get_left_margin() * DPI / 2.54
|
||||
top_margin = self.paper.get_top_margin() * DPI / 2.54
|
||||
|
||||
# get index options
|
||||
include_toc = self.index_options.get_include_toc()
|
||||
include_index = self.index_options.get_include_index()
|
||||
|
||||
# create cairo context and pango layout
|
||||
filename = self._backend.filename.encode(sys.getfilesystemencoding())
|
||||
try:
|
||||
@@ -109,11 +115,39 @@ class PdfDoc(libcairodoc.CairoDoc):
|
||||
cr.update_context(pango_context)
|
||||
|
||||
# paginate the document
|
||||
finished = self.paginate(layout, page_width, page_height, DPI, DPI)
|
||||
while not finished:
|
||||
finished = self.paginate(layout, page_width, page_height, DPI, DPI)
|
||||
self.paginate_document(layout, page_width, page_height, DPI, DPI)
|
||||
body_pages = self._pages
|
||||
|
||||
# build the table of contents and alphabetical index
|
||||
toc = []
|
||||
index = {}
|
||||
for page_nr, page in enumerate(body_pages):
|
||||
for mark in page.get_marks():
|
||||
if mark.type == INDEX_TYPE_ALP:
|
||||
if mark.key in index:
|
||||
if page_nr not in index[mark.key]:
|
||||
index[mark.key].append(page_nr)
|
||||
else:
|
||||
index[mark.key] = [page_nr]
|
||||
elif mark.type == INDEX_TYPE_TOC:
|
||||
toc.append([mark, page_nr])
|
||||
|
||||
# paginate the table of contents
|
||||
if include_toc:
|
||||
toc_pages = self.__generate_toc(layout, page_width, page_height,
|
||||
toc)
|
||||
else:
|
||||
toc_pages = []
|
||||
|
||||
# paginate the index
|
||||
if include_index:
|
||||
index_pages = self.__generate_index(layout, page_width, page_height,
|
||||
index, len(toc_pages))
|
||||
else:
|
||||
index_pages = []
|
||||
|
||||
# render the pages
|
||||
self._pages = toc_pages + body_pages + index_pages
|
||||
for page_nr in range(len(self._pages)):
|
||||
cr.save()
|
||||
cr.translate(left_margin, top_margin)
|
||||
@@ -130,3 +164,37 @@ class PdfDoc(libcairodoc.CairoDoc):
|
||||
# if we don't restore the resolution.
|
||||
fontmap.set_resolution(saved_resolution)
|
||||
|
||||
def __generate_toc(self, layout, page_width, page_height, toc):
|
||||
'''
|
||||
Generate the table of contents
|
||||
'''
|
||||
self._doc = libcairodoc.GtkDocDocument()
|
||||
self._active_element = self._doc
|
||||
self._pages = []
|
||||
write_toc(toc, self, 1) # assume single page
|
||||
self.paginate_document(layout, page_width, page_height, DPI, DPI)
|
||||
toc_pages = self._pages
|
||||
|
||||
# re-generate if table spans more than one page
|
||||
offset = len(toc_pages)
|
||||
if offset != 1:
|
||||
self._doc = libcairodoc.GtkDocDocument()
|
||||
self._active_element = self._doc
|
||||
self._pages = []
|
||||
write_toc(toc, self, offset)
|
||||
self.paginate_document(layout, page_width, page_height, DPI, DPI)
|
||||
toc_pages = self._pages
|
||||
|
||||
return self._pages
|
||||
|
||||
def __generate_index(self, layout, page_width, page_height, index, offset):
|
||||
'''
|
||||
Generate the index
|
||||
'''
|
||||
self._doc = libcairodoc.GtkDocDocument()
|
||||
self._active_element = self._doc
|
||||
self._pages = []
|
||||
write_index(index, self, offset)
|
||||
self.paginate_document(layout, page_width, page_height, DPI, DPI)
|
||||
return self._pages
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ import Errors
|
||||
#-------------------------------------------------------------------------
|
||||
class SvgDrawDoc(BaseDoc, DrawDoc):
|
||||
|
||||
def __init__(self, styles, type):
|
||||
BaseDoc.__init__(self, styles, type)
|
||||
def __init__(self, styles, type, index_opts):
|
||||
BaseDoc.__init__(self, styles, type, index_opts)
|
||||
self.f = None
|
||||
self.filename = None
|
||||
self.level = 0
|
||||
|
||||
@@ -38,6 +38,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'AsciiDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "txt"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -58,6 +59,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'GtkPrint'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = ""
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -78,6 +80,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'HtmlDoc'
|
||||
plg.paper = False
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "html"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -98,6 +101,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'LaTeXDoc'
|
||||
plg.paper = True
|
||||
plg.style = False
|
||||
plg.index = False
|
||||
plg.extension = "tex"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -119,6 +123,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'ODFDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "odt"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -139,6 +144,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'PdfDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = True
|
||||
plg.extension = "pdf"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -159,6 +165,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'PSDrawDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "ps"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -179,6 +186,7 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'RTFDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "rtf"
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
@@ -200,4 +208,5 @@ plg.ptype = DOCGEN
|
||||
plg.basedocclass = 'SvgDrawDoc'
|
||||
plg.paper = True
|
||||
plg.style = True
|
||||
plg.index = False
|
||||
plg.extension = "svg"
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#------------------------------------------------------------------------
|
||||
from gen.ggettext import gettext as _
|
||||
from math import radians
|
||||
import re
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@@ -174,6 +175,18 @@ def tabstops_to_tabarray(tab_stops, dpi):
|
||||
|
||||
return tab_array
|
||||
|
||||
def raw_length(s):
|
||||
"""
|
||||
Return the length of the raw string after all pango markup has been removed.
|
||||
"""
|
||||
s = re.sub('<.*?>', '', s)
|
||||
s = s.replace('&', '&')
|
||||
s = s.replace('<', '<')
|
||||
s = s.replace('>', '>')
|
||||
s = s.replace('"', '"')
|
||||
s = s.replace(''', "'")
|
||||
return len(s)
|
||||
|
||||
###------------------------------------------------------------------------
|
||||
###
|
||||
### Table row style
|
||||
@@ -321,6 +334,14 @@ class GtkDocBaseElement(object):
|
||||
"""
|
||||
return self._children
|
||||
|
||||
def get_marks(self):
|
||||
"""Get the list of index marks for this element.
|
||||
"""
|
||||
marks = []
|
||||
for child in self._children:
|
||||
marks.extend(child.get_marks())
|
||||
return marks
|
||||
|
||||
def divide(self, layout, width, height, dpi_x, dpi_y):
|
||||
"""Divide the element into two depending on available space.
|
||||
|
||||
@@ -410,12 +431,32 @@ class GtkDocParagraph(GtkDocBaseElement):
|
||||
self._plaintext = None
|
||||
self._attrlist = None
|
||||
|
||||
self._marklist = []
|
||||
|
||||
def add_text(self, text):
|
||||
if self._plaintext is not None:
|
||||
raise PluginError('CairoDoc: text is already parsed.'
|
||||
' You cannot add text anymore')
|
||||
self._text = self._text + text
|
||||
|
||||
def add_mark(self, mark):
|
||||
"""
|
||||
Add an index mark to this paragraph
|
||||
"""
|
||||
self._marklist.append((mark, raw_length(self._text)))
|
||||
|
||||
def get_marks(self):
|
||||
"""
|
||||
Return a list of index marks for this paragraph
|
||||
"""
|
||||
return [elem[0] for elem in self._marklist]
|
||||
|
||||
def __set_marklist(self, marklist):
|
||||
"""
|
||||
Internal method to allow for splitting of paragraphs
|
||||
"""
|
||||
self._marklist = marklist
|
||||
|
||||
def __set_plaintext(self, plaintext):
|
||||
"""
|
||||
Internal method to allow for splitting of paragraphs
|
||||
@@ -562,7 +603,18 @@ class GtkDocParagraph(GtkDocBaseElement):
|
||||
# then update the first one
|
||||
self.__set_plaintext(self._plaintext.encode('utf-8')[:index])
|
||||
self._style.set_bottom_margin(0)
|
||||
|
||||
|
||||
# split the list of index marks
|
||||
para1 = []
|
||||
para2 = []
|
||||
for mark, position in self._marklist:
|
||||
if position < index:
|
||||
para1.append((mark, position))
|
||||
else:
|
||||
para2.append((mark, position - index))
|
||||
self.__set_marklist(para1)
|
||||
new_paragraph.__set_marklist(para2)
|
||||
|
||||
paragraph_height = endheight - startheight + spacing + t_margin + 2 * v_padding
|
||||
return (self, new_paragraph), paragraph_height
|
||||
|
||||
@@ -1374,6 +1426,10 @@ links (like ODF) and write PDF from that format.
|
||||
# The markup in the note editor is not in the text so is not
|
||||
# considered. It must be added by pango too
|
||||
text = self._backend.ESCAPE_FUNC()(text)
|
||||
|
||||
if mark:
|
||||
self._active_element.add_mark(mark)
|
||||
|
||||
self._active_element.add_text(text)
|
||||
|
||||
def write_text(self, text, mark=None, links=False):
|
||||
@@ -1515,6 +1571,12 @@ links (like ODF) and write PDF from that format.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def paginate_document(self, layout, page_width, page_height, dpi_x, dpi_y):
|
||||
"""Paginate the entire document.
|
||||
"""
|
||||
while not self.paginate(layout, page_width, page_height, dpi_x, dpi_y):
|
||||
pass
|
||||
|
||||
def paginate(self, layout, page_width, page_height, dpi_x, dpi_y):
|
||||
"""Paginate the meta document in chunks.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user