class Cell(PodElement):
    OD = XmlElement('table-cell', nsUri=ns.NS_TABLE)
    subTags = [Text.OD]

    def __init__(self):
        self.tableInfo = None  # ~OdTable~
        self.colIndex = None  # The column index for this cell, within its table.
Beispiel #2
0
class Table(PodElement):
    OD = XmlElement('table', nsUri=ns.NS_TABLE)
    subTags = [Row.OD, Cell.OD, Text.OD]
    # When we must remove the Table element from a buffer, the deepest element
    # to remove is the Cell (it can only be done for one-row, one-cell tables).
    DEEPEST_TO_REMOVE = Cell.OD
    def __init__(self):
        self.tableInfo = None # ~OdTable~
Beispiel #3
0
    def __init__(self, template, context, result, pythonWithUnoPath=None,
                 ooPort=2002, stylesMapping={}, forceOoCall=False,
                 finalizeFunction=None, overwriteExisting=False,
                 raiseOnError=False, imageResolver=None):
        '''This Python Open Document Renderer (PodRenderer) loads a document
           template (p_template) which is an ODT or ODS file with some elements
           written in Python. Based on this template and some Python objects
           defined in p_context, the renderer generates an ODT file (p_result)
           that instantiates the p_template and fills it with objects from the
           p_context.

         - If p_result does not end with .odt or .ods, the Renderer will call
           LibreOffice to perform a conversion. If p_forceOoCall is True, even
           if p_result ends with .odt, LibreOffice will be called, not for
           performing a conversion, but for updating some elements like indexes
           (table of contents, etc) and sections containing links to external
           files (which is the case, for example, if you use the default
           function "document").

         - If the Python interpreter which runs the current script is not
           UNO-enabled, this script will run, in another process, a UNO-enabled
           Python interpreter (whose path is p_pythonWithUnoPath) which will
           call LibreOffice. In both cases, we will try to connect to
           LibreOffice in server mode on port p_ooPort.

         - If you plan to make "XHTML to OpenDocument" conversions, you may
           specify a styles mapping in p_stylesMapping.

         - If you specify a function in p_finalizeFunction, this function will
           be called by the renderer before re-zipping the ODT/S result. This
           way, you can still perform some actions on the content of the ODT/S
           file before it is zipped and potentially converted. This function
           must accept one arg: the absolute path to the temporary folder
           containing the un-zipped content of the ODT/S result.

         - If you set p_overwriteExisting to True, the renderer will overwrite
           the result file. Else, an exception will be thrown if the result file
           already exists.

         - If p_raiseOnError is False (the default value), any error encountered
           during the generation of the result file will be dumped into it, as
           a Python traceback within a note. Else, the error will be raised.

         - p_imageResolver allows POD to retrieve images, from "img" tags within
           XHTML content. Indeed, POD may not be able (ie, may not have the
           permission to) perform a HTTP GET on those images. Currently, the
           resolver can only be a Zope application object.
        '''
        self.template = template
        self.templateZip = zipfile.ZipFile(template)
        self.result = result
        self.contentXml = None # Content (string) of content.xml
        self.stylesXml = None # Content (string) of styles.xml
        self.stylesManager = None # Manages the styles defined into the ODT
        # template
        self.tempFolder = None
        self.env = None
        self.pyPath = pythonWithUnoPath
        self.ooPort = ooPort
        self.forceOoCall = forceOoCall
        self.finalizeFunction = finalizeFunction
        self.overwriteExisting = overwriteExisting
        self.raiseOnError = raiseOnError
        self.imageResolver = imageResolver
        # Remember potential files or images that will be included through
        # "do ... from document" statements: we will need to declare them in
        # META-INF/manifest.xml. Keys are file names as they appear within the
        # ODT file (to dump in manifest.xml); values are original paths of
        # included images (used for avoiding to create multiple copies of a file
        # which is imported several times).
        self.fileNames = {}
        self.prepareFolders()
        # Unzip template
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
        os.mkdir(self.unzipFolder)
        for zippedFile in self.templateZip.namelist():
            # Before writing the zippedFile into self.unzipFolder, create the
            # intermediary subfolder(s) if needed.
            fileName = None
            if zippedFile.endswith('/') or zippedFile.endswith(os.sep):
                # This is an empty folder. Create it nevertheless. If zippedFile
                # starts with a '/', os.path.join will consider it an absolute
                # path and will throw away self.unzipFolder.
                os.makedirs(os.path.join(self.unzipFolder,
                                         zippedFile.lstrip('/')))
            else:
                fileName = os.path.basename(zippedFile)
                folderName = os.path.dirname(zippedFile)
                fullFolderName = self.unzipFolder
                if folderName:
                    fullFolderName = os.path.join(fullFolderName, folderName)
                    if not os.path.exists(fullFolderName):
                        os.makedirs(fullFolderName)
            # Unzip the file in self.unzipFolder
            if fileName:
                fullFileName = os.path.join(fullFolderName, fileName)
                f = open(fullFileName, 'wb')
                fileContent = self.templateZip.read(zippedFile)
                if (fileName == 'content.xml') and not folderName:
                    # content.xml files may reside in subfolders.
                    # We modify only the one in the root folder.
                    self.contentXml = fileContent
                elif (fileName == 'styles.xml') and not folderName:
                    # Same remark as above.
                    self.stylesManager = StylesManager(fileContent)
                    self.stylesXml = fileContent
                elif (fileName == 'mimetype') and \
                     (fileContent == mimeTypes['ods']):
                    # From LibreOffice 3.5, it is not possible anymore to dump
                    # errors into the resulting ods as annotations. Indeed,
                    # annotations can't reside anymore within paragraphs. ODS
                    # files generated with pod and containing error messages in
                    # annotations cause LibreOffice 3.5 and 4.0 to crash.
                    # LibreOffice >= 4.1 simply does not show the annotation.
                    self.raiseOnError = True
                f.write(fileContent)
                f.close()
        self.templateZip.close()
        # Create the content.xml parser
        pe = PodEnvironment
        contentInserts = (
            OdInsert(CONTENT_POD_FONTS,
                XmlElement('font-face-decls', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'svg': pe.NS_SVG}),
            OdInsert(CONTENT_POD_STYLES,
                XmlElement('automatic-styles', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'fo': pe.NS_FO,
                        'text': pe.NS_TEXT, 'table': pe.NS_TABLE}))
        self.contentParser = self.createPodParser('content.xml', context,
                                                  contentInserts)
        # Create the styles.xml parser
        stylesInserts = (
            OdInsert(STYLES_POD_FONTS,
                XmlElement('font-face-decls', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'svg': pe.NS_SVG}),
            OdInsert(STYLES_POD_STYLES,
                XmlElement('styles', nsUri=pe.NS_OFFICE),
                nsUris={'style': pe.NS_STYLE, 'fo': pe.NS_FO,
                        'text': pe.NS_TEXT}))
        self.stylesParser = self.createPodParser('styles.xml', context,
                                                 stylesInserts)
        # Store the styles mapping
        self.setStylesMapping(stylesMapping)
        # While working, POD may identify "dynamic styles" to insert into
        # the "automatic styles" section of content.xml, like the column styles
        # of tables generated from XHTML tables via xhtml2odt.py.
        self.dynamicStyles = []
class Row(PodElement):
    OD = XmlElement('table-row', nsUri=ns.NS_TABLE)
    subTags = [Cell.OD, Text.OD]
class Section(PodElement):
    OD = XmlElement('section', nsUri=ns.NS_TEXT)
    subTags = [Text.OD]
    DEEPEST_TO_REMOVE = OD  # When we must remove the Section element from a
class Title(PodElement):
    OD = XmlElement('h', nsUri=ns.NS_TEXT)
    subTags = []
class Text(PodElement):
    OD = XmlElement('p', nsUri=ns.NS_TEXT)
    subTags = []  # When generating an error we may need to surround the error
Beispiel #8
0
    def __init__(self,
                 template,
                 context,
                 result,
                 pythonWithUnoPath=None,
                 ooPort=2002,
                 stylesMapping={},
                 forceOoCall=False,
                 finalizeFunction=None,
                 overwriteExisting=False):
        '''This Python Open Document Renderer (PodRenderer) loads a document
        template (p_template) which is an ODT file with some elements
        written in Python. Based on this template and some Python objects
        defined in p_context, the renderer generates an ODT file
        (p_result) that instantiates the p_template and fills it with objects
        from the p_context.

         - If p_result does not end with .odt, the Renderer
           will call OpenOffice to perform a conversion. If p_forceOoCall is
           True, even if p_result ends with .odt, OpenOffice will be called, not
           for performing a conversion, but for updating some elements like
           indexes (table of contents, etc) and sections containing links to
           external files (which is the case, for example, if you use the
           default function "document").

         - If the Python interpreter which runs the current script is not
           UNO-enabled, this script will run, in another process, a UNO-enabled
           Python interpreter (whose path is p_pythonWithUnoPath) which will
           call OpenOffice. In both cases, we will try to connect to OpenOffice
           in server mode on port p_ooPort.

         - If you plan to make "XHTML to OpenDocument" conversions, you may
           specify a styles mapping in p_stylesMapping.

         - If you specify a function in p_finalizeFunction, this function will
           be called by the renderer before re-zipping the ODT result. This way,
           you can still perform some actions on the content of the ODT file
           before it is zipped and potentially converted. This function must
           accept one arg: the absolute path to the temporary folder containing
           the un-zipped content of the ODT result.

         - If you set p_overwriteExisting to True, the renderer will overwrite
           the result file. Else, an exception will be thrown if the result file
           already exists.'''
        self.template = template
        self.templateZip = zipfile.ZipFile(template)
        self.result = result
        self.contentXml = None  # Content (string) of content.xml
        self.stylesXml = None  # Content (string) of styles.xml
        self.stylesManager = None  # Manages the styles defined into the ODT
        # template
        self.tempFolder = None
        self.env = None
        self.pyPath = pythonWithUnoPath
        self.ooPort = ooPort
        self.forceOoCall = forceOoCall
        self.finalizeFunction = finalizeFunction
        self.overwriteExisting = overwriteExisting
        # Remember potential files or images that will be included through
        # "do ... from document" statements: we will need to declare them in
        # META-INF/manifest.xml. Keys are file names as they appear within the
        # ODT file (to dump in manifest.xml); values are original paths of
        # included images (used for avoiding to create multiple copies of a file
        # which is imported several times).
        # imported file).
        self.fileNames = {}
        self.prepareFolders()
        # Unzip template
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
        os.mkdir(self.unzipFolder)
        for zippedFile in self.templateZip.namelist():
            # Before writing the zippedFile into self.unzipFolder, create the
            # intermediary subfolder(s) if needed.
            fileName = None
            if zippedFile.endswith('/') or zippedFile.endswith(os.sep):
                # This is an empty folder. Create it nevertheless.
                os.makedirs(os.path.join(self.unzipFolder, zippedFile))
            else:
                fileName = os.path.basename(zippedFile)
                folderName = os.path.dirname(zippedFile)
                fullFolderName = self.unzipFolder
                if folderName:
                    fullFolderName = os.path.join(fullFolderName, folderName)
                    if not os.path.exists(fullFolderName):
                        os.makedirs(fullFolderName)
            # Unzip the file in self.unzipFolder
            if fileName:
                fullFileName = os.path.join(fullFolderName, fileName)
                f = open(fullFileName, 'wb')
                fileContent = self.templateZip.read(zippedFile)
                if (fileName == 'content.xml') and not folderName:
                    # content.xml files may reside in subfolders.
                    # We modify only the one in the root folder.
                    self.contentXml = fileContent
                elif (fileName == 'styles.xml') and not folderName:
                    # Same remark as above.
                    self.stylesManager = StylesManager(fileContent)
                    self.stylesXml = fileContent
                f.write(fileContent)
                f.close()
        self.templateZip.close()
        # Create the content.xml parser
        pe = PodEnvironment
        contentInserts = (OdInsert(CONTENT_POD_FONTS,
                                   XmlElement('font-face-decls',
                                              nsUri=pe.NS_OFFICE),
                                   nsUris={
                                       'style': pe.NS_STYLE,
                                       'svg': pe.NS_SVG
                                   }),
                          OdInsert(CONTENT_POD_STYLES,
                                   XmlElement('automatic-styles',
                                              nsUri=pe.NS_OFFICE),
                                   nsUris={
                                       'style': pe.NS_STYLE,
                                       'fo': pe.NS_FO,
                                       'text': pe.NS_TEXT,
                                       'table': pe.NS_TABLE
                                   }))
        self.contentParser = self.createPodParser('content.xml', context,
                                                  contentInserts)
        # Create the styles.xml parser
        stylesInserts = (OdInsert(STYLES_POD_FONTS,
                                  XmlElement('font-face-decls',
                                             nsUri=pe.NS_OFFICE),
                                  nsUris={
                                      'style': pe.NS_STYLE,
                                      'svg': pe.NS_SVG
                                  }),
                         OdInsert(STYLES_POD_STYLES,
                                  XmlElement('styles', nsUri=pe.NS_OFFICE),
                                  nsUris={
                                      'style': pe.NS_STYLE,
                                      'fo': pe.NS_FO
                                  }))
        self.stylesParser = self.createPodParser('styles.xml', context,
                                                 stylesInserts)
        # Stores the styles mapping
        self.setStylesMapping(stylesMapping)
Beispiel #9
0
class Section(PodElement):
    OD = XmlElement('section', nsUri=ns.NS_TEXT)
    subTags = [Text.OD]
    # When we must remove the Section element from a buffer, the deepest element
    # to remove is the Section element itself.
    DEEPEST_TO_REMOVE = OD
Beispiel #10
0
class Text(PodElement):
    OD = XmlElement('p', nsUri=ns.NS_TEXT)
    # When generating an error we may need to surround it with a given tag and
    # sub-tags.
    subTags = []