Files
novelWriter/nw/core/toodt.py
T
Veronica K. B. Olsen e3c37f003b Add main ODT style XML
2021-01-26 20:22:32 +01:00

357 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
novelWriter ODT Text Converter
================================
Extends the Tokenizer class to generate ODT and FODT files
File History:
Created: 2021-01-26 [1.1rc1]
This file is a part of novelWriter
Copyright 20182021, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import nw
import logging
import os
from lxml import etree
from nw.core.tokenizer import Tokenizer
logger = logging.getLogger(__name__)
XML_NS = {
"office" : "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
"style" : "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
"text" : "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
"fo" : "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
"loext" : "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
}
class ToOdt(Tokenizer):
def __init__(self, theProject, theParent):
Tokenizer.__init__(self, theProject, theParent)
self.mainConf = nw.CONFIG
self._xRoot = None
self._xStyl = None
self._xText = None
self._dLanguage = "en"
self._dCountry = "GB"
self._dFontFace = "Liberation Serif"
self._dFontSize = 12
return
##
# Setters
##
def setLanguage(self, theLang):
"""Set language for the document.
"""
if theLang is None:
return False
langBits = theLang.split("_")
self._dLanguage = langBits[0]
if len(langBits) > 1:
self._dCountry = langBits[1]
return True
def setFont(self, fontFace, fontSize):
"""Set font and font size.
"""
self._dFontFace = fontFace
self._dFontSize = fontSize
return
##
# Class Methods
##
def initDocument(self):
"""Initialises a new open document XML tree.
"""
rAttr = {
_mkTag("office", "version") : "1.3",
_mkTag("office", "mimetype") : "application/vnd.oasis.opendocument.text",
}
self._xRoot = etree.Element(_mkTag("office", "document"), attrib=rAttr, nsmap=XML_NS)
self._xStyl = etree.SubElement(self._xRoot, _mkTag("office", "styles"))
self._xText = etree.SubElement(self._xRoot, _mkTag("office", "text"))
# Add Styles
self._styleParagraph()
self._styleHeaders()
return
def doConvert(self):
"""Convert the list of text tokens into a HTML document saved
to theResult.
"""
self.theResult = ""
for tType, tLine, tText, tFormat, tStyle in self.theTokens:
# Process Text Type
if tType == self.T_EMPTY:
continue
elif tType == self.T_TITLE:
continue
return
def closeDocument(self):
"""Return the serialised XML document
"""
self.theResult = etree.tostring(
self._xRoot,
pretty_print = True,
encoding = "utf-8",
xml_declaration = True
)
cacheFile = os.path.join(os.path.expanduser("~"), "Temp", "odtGen.fodt")
with open(cacheFile, mode="wb") as outFile:
outFile.write(self.theResult)
return
##
# Style Elements
##
def _styleParagraph(self):
"""Set the paragraph styles.
"""
# Add Default Paragraph Style
# ===========================
theAttr = {}
theAttr[_mkTag("style", "family")] = "paragraph"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("style", "line-break")] = "strict"
theAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm"
theAttr[_mkTag("style", "writing-mode")] = "page"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("style", "font-name")] = self._dFontFace
theAttr[_mkTag("fo", "font-size")] = "%dpt" % self._dFontSize
theAttr[_mkTag("fo", "language")] = self._dLanguage
theAttr[_mkTag("fo", "country")] = self._dCountry
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Paragraph Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Standard"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "class")] = "text"
etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
# Add Text Body Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Text_body"
theAttr[_mkTag("style", "display-name")] = "Text Body"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Standard"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.247cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
theAttr[_mkTag("fo", "line-height")] = "115%"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
return
def _styleHeaders(self):
"""Set the header styles.
"""
# Add Default Heading Style
# =========================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Heading"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Standard"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0.423cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.212cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
theAttr[_mkTag("fo", "keep-with-next")] = "always"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("style", "font-name")] = self._dFontFace
theAttr[_mkTag("fo", "font-family")] = "'%s'" % self._dFontFace
theAttr[_mkTag("style", "font-pitch")] = "variable"
theAttr[_mkTag("fo", "font-size")] = "14pt"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Title Style
# ===============
theAttr = {}
theAttr[_mkTag("style", "name")] = "Title"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Heading"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "class")] = "chapter"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "text-align")] = "center"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "font-size")] = "28pt"
theAttr[_mkTag("fo", "font-weight")] = "bold"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Heading 1 Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Heading_1"
theAttr[_mkTag("style", "display-name")] = "Heading 1"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Heading"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "default-outline-level")] = "1"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0.423cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.212cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "font-size")] = "130%"
theAttr[_mkTag("fo", "font-weight")] = "bold"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Heading 2 Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Heading_2"
theAttr[_mkTag("style", "display-name")] = "Heading 2"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Heading"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "default-outline-level")] = "2"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0.353cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.212cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "font-size")] = "120%"
theAttr[_mkTag("fo", "font-weight")] = "bold"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Heading 3 Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Heading_3"
theAttr[_mkTag("style", "display-name")] = "Heading 3"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Heading"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "default-outline-level")] = "3"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0.247cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.212cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "font-size")] = "110%"
theAttr[_mkTag("fo", "font-weight")] = "bold"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
# Add Heading 4 Style
# ===================
theAttr = {}
theAttr[_mkTag("style", "name")] = "Heading_4"
theAttr[_mkTag("style", "display-name")] = "Heading 4"
theAttr[_mkTag("style", "family")] = "paragraph"
theAttr[_mkTag("style", "parent-style-name")] = "Heading"
theAttr[_mkTag("style", "next-style-name")] = "Text_body"
theAttr[_mkTag("style", "default-outline-level")] = "4"
theAttr[_mkTag("style", "class")] = "text"
xStyl = etree.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "margin-top")] = "0.247cm"
theAttr[_mkTag("fo", "margin-bottom")] = "0.212cm"
theAttr[_mkTag("style", "contextual-spacing")] = "false"
etree.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
theAttr = {}
theAttr[_mkTag("fo", "font-size")] = "100%"
theAttr[_mkTag("fo", "font-weight")] = "bold"
etree.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
return
# END Class ToOdt
# =========================================================================== #
# Local Functions
# =========================================================================== #
def _mkTag(nsName, tagName):
"""Assemble namespace and tag name.
"""
theNS = XML_NS.get(nsName, "")
if theNS:
return "{%s}%s" % (theNS, tagName)
logger.warning("Missing xml namespace '%s'" % nsName)
return tagName