ext/xhtml2fo.py
author Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
Thu, 18 Mar 2010 23:22:40 +0100
branchstable
changeset 4952 f32dcf3925d4
parent 4721 8f63691ccb7f
child 5421 8167de96c523
permissions -rw-r--r--
[web] get rid of spurious '[Errno 2] No such file or directory' on load This was caused by can_do_pdf_conversion() which tries to use '/usr/bin/fop'. When fop was not available, an OSError was raised by suprocess.Popen. This changeset first checks for /usr/bin/fop presence, then tries to run fop. If an error occurs, log it instead of printing it. NOTE for later: why do we test explicitly for "/usr/bin/fop" rather than simply "fop" ?

from xml.etree.ElementTree import QName
from pysixt.standard.xhtml_xslfo.transformer import XHTML2FOTransformer
from pysixt.utils.xslfo.standard import cm
from pysixt.utils.xslfo import SimplePageMaster
from pysixt.standard.xhtml_xslfo.default_styling import default_styles
from pysixt.standard.xhtml_xslfo import XHTML_NS


class ReportTransformer(XHTML2FOTransformer):
    """
    Class transforming an XHTML input tree into a FO document
    displaying reports (one report for each <div class="contentmain">
    element in the input tree.
    """

    def __init__(self, section,
                 page_width=21.0, page_height=29.7,
                 margin_top=1.0, margin_bottom=1.0,
                 margin_left=1.0, margin_right=1.0,
                 header_footer_height=0.75,
                 standard_font_size=11.0, default_lang=u"fr" ):
        """
        Initializes a transformer turning an XHTML input tree
        containing <div class="contentmain"> elements representing
        main content sections into a FO output tree displaying the
        reports.

        page_width: float - width of the page (in cm)
        page_height: float - height of the page (in cm)
        margin_top: float - top margin of the page (in cm)
        margin_bottom: float - bottom margin of the page (in cm)
        margin_left: float - left margin of the page (in cm)
        margin_right: float - right margin of the page (in cm)
        header_footer_height: float - height of the header or the footer of the
                              page that the page number (if any) will be
                              inserted in.
        standard_font_size: float - standard size of the font (in pt)
        default_lang: u"" - default language (used for hyphenation)
        """
        self.section = section
        self.page_width = page_width
        self.page_height = page_height

        self.page_tmargin = margin_top
        self.page_bmargin = margin_bottom
        self.page_lmargin = margin_left
        self.page_rmargin = margin_right

        self.hf_height = header_footer_height

        self.font_size = standard_font_size
        self.lang = default_lang

        XHTML2FOTransformer.__init__(self)


    def define_pagemasters(self):
        """
        Defines the page masters for the FO output document.
        """
        pm = SimplePageMaster(u"page-report")
        pm.set_page_dims( self.page_width*cm, self.page_height*cm )
        pm.set_page_margins({u'top'   : self.page_tmargin*cm,
                             u'bottom': self.page_bmargin*cm,
                             u'left'  : self.page_lmargin*cm,
                             u'right' : self.page_rmargin*cm })
        pm.add_peripheral_region(u"end", self.hf_height)
        dims = {}
        dims[u"bottom"] = self.hf_height + 0.25
        pm.set_main_region_margins(dims)
        return [pm]

    def _visit_report(self, in_elt, _out_elt, params):
        """
        Specific visit function for the input <div> elements whose class is
        "report". The _root_visit method of this class selects these input
        elements and asks the process of these elements with this specific
        visit function.
        """

        ps = self.create_pagesequence(u"page-report")
        props = { u"force-page-count": u"no-force",
                  u"initial-page-number": u"1",
                  u"format": u"1", }
        self._output_properties(ps, props)

        sc = self.create_staticcontent(ps, u"end")
        sc_bl = self.create_block(sc)
        attrs = { u"hyphenate": u"false", }
        attrs[u"font-size"] = u"%.1fpt" % (self.font_size * 0.7)
        attrs[u"language"] = self.lang
        attrs[u"text-align"] = u"center"
        self._output_properties(sc_bl, attrs)
        sc_bl.text = u"Page" + u" " # ### Should be localised!
        pn = self.create_pagenumber(sc_bl)
        pn.tail = u"/"
        self.create_pagenumbercitation(
            sc_bl, u"last-block-of-report-%d" % params[u"context_pos"])

        fl = self.create_flow(ps, u"body")
        bl = self.create_block(fl)

        # Sets on the highest block element the properties of the XHTML body
        # element. These properties (at the least the inheritable ones) will
        # be inherited by all the future FO elements.
        bodies = list(self.in_tree.getiterator(QName(XHTML_NS, u"body")))
        if len(bodies) > 0:
            attrs = self._extract_properties([bodies[0]])
        else:
            attrs = default_styles[u"body"].copy()
        attrs[u"font-size"] = u"%.1fpt" % self.font_size
        attrs[u"language"] = self.lang
        self._output_properties(bl,attrs)

        # Processes the report content
        self._copy_text(in_elt, bl)
        self._process_nodes(in_elt.getchildren(), bl)

        # Inserts an empty block at the end of the report in order to be able
        # to compute the last page number of this report.
        last_bl = self.create_block(bl)
        props = { u"keep-with-previous": u"always", }
        props[u"id"] = u"last-block-of-report-%d" % params[u"context_pos"]
        self._output_properties(last_bl,props)


    def _root_visit(self):
        """
        Visit function called when starting the process of the input tree.
        """
        content = [ d for d in self.in_tree.getiterator(QName(XHTML_NS, u"div"))
                    if d.get(u"id") == self.section ]
        # Asks the process of the report elements with a specific visit
        # function
        self._process_nodes(content, self.fo_root,
                            with_function=self._visit_report)