Add main ODT style XML
This commit is contained in:
+302
-1
@@ -24,23 +24,87 @@ 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.
|
||||
@@ -48,8 +112,245 @@ class ToOdt(Tokenizer):
|
||||
self.theResult = ""
|
||||
|
||||
for tType, tLine, tText, tFormat, tStyle in self.theTokens:
|
||||
continue
|
||||
|
||||
# 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
|
||||
|
||||
@@ -20,16 +20,32 @@ 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 pytest
|
||||
|
||||
from nw.core import NWProject, NWIndex, ToOdt
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_Convert(dummyGUI):
|
||||
def testCoreToOdt_Convert(tmpConf, dummyGUI):
|
||||
"""Test the converter of the ToHtml class.
|
||||
"""
|
||||
nw.CONFIG = tmpConf
|
||||
|
||||
theProject = NWProject(dummyGUI)
|
||||
dummyGUI.theIndex = NWIndex(theProject, dummyGUI)
|
||||
theDoc = ToOdt(theProject, dummyGUI)
|
||||
|
||||
# Export Mode
|
||||
# ===========
|
||||
|
||||
theDoc.isNovel = True
|
||||
|
||||
# Header 1
|
||||
theDoc.theText = "# Title\n"
|
||||
theDoc.tokenizeText()
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.theResult == ""
|
||||
|
||||
# END Test testCoreToOdt_Convert
|
||||
|
||||
Reference in New Issue
Block a user