Add annotations to odt class
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – HTML Text Converter
|
||||
=================================
|
||||
Extends the Tokenizer class to generate HTML output
|
||||
|
||||
File History:
|
||||
Created: 2019-05-07 [0.0.1]
|
||||
@@ -37,6 +36,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ToHtml(Tokenizer):
|
||||
"""Core: HTML Document Writer
|
||||
|
||||
Extend the Tokenizer class to writer HTML output. This class is
|
||||
also used by the Document Viewer, and Manuscript Build Preview.
|
||||
"""
|
||||
|
||||
M_PREVIEW = 0 # Tweak output for the DocViewer
|
||||
M_EXPORT = 1 # Tweak output for saving to HTML or printing
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Text Tokenizer
|
||||
============================
|
||||
Split novelWriter plain text into its elements
|
||||
|
||||
File History:
|
||||
Created: 2019-05-05 [0.0.1] Tokenizer
|
||||
@@ -55,6 +54,13 @@ def stripEscape(text):
|
||||
|
||||
|
||||
class Tokenizer(ABC):
|
||||
"""Core: Text Tokenizer Abstract Base Class
|
||||
|
||||
This is the base class for all document build classes. It parses the
|
||||
novelWriter markup format and generates a registry of tokens and
|
||||
text that can be further processed into other output formats by
|
||||
subclasses.
|
||||
"""
|
||||
|
||||
# In-Text Format
|
||||
FMT_B_B = 1 # Begin bold
|
||||
@@ -309,6 +315,9 @@ class Tokenizer(ABC):
|
||||
"""Add a heading at the start of a new root folder."""
|
||||
if not self._project.tree.checkType(tHandle, nwItemType.ROOT):
|
||||
return False
|
||||
theItem = self._project.tree[tHandle]
|
||||
if not theItem:
|
||||
return False
|
||||
|
||||
if self._isFirst:
|
||||
textAlign = self.A_CENTRE
|
||||
@@ -316,7 +325,6 @@ class Tokenizer(ABC):
|
||||
else:
|
||||
textAlign = self.A_PBB | self.A_CENTRE
|
||||
|
||||
theItem = self._project.tree[tHandle]
|
||||
locNotes = self._localLookup("Notes")
|
||||
theTitle = f"{locNotes}: {theItem.itemName}"
|
||||
self._tokens = []
|
||||
@@ -781,10 +789,10 @@ class HeadingFormatter:
|
||||
chWord = self._project.localLookup(self._chCount)
|
||||
hFormat = hFormat.replace(nwHeadFmt.CH_WORD, chWord)
|
||||
if nwHeadFmt.CH_ROML in hFormat:
|
||||
chRom = numberToRoman(self._chCount, True)
|
||||
chRom = numberToRoman(self._chCount, toLower=True)
|
||||
hFormat = hFormat.replace(nwHeadFmt.CH_ROML, chRom)
|
||||
if nwHeadFmt.CH_ROMU in hFormat:
|
||||
chRom = numberToRoman(self._chCount, False)
|
||||
chRom = numberToRoman(self._chCount, toLower=False)
|
||||
hFormat = hFormat.replace(nwHeadFmt.CH_ROMU, chRom)
|
||||
|
||||
return hFormat
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Markdown Text Converter
|
||||
=====================================
|
||||
Extends the Tokenizer class to generate Makrdown output
|
||||
|
||||
File History:
|
||||
Created: 2021-02-06 [1.2b1]
|
||||
@@ -36,6 +35,12 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ToMarkdown(Tokenizer):
|
||||
"""Core: Markdown Document Writer
|
||||
|
||||
Extend the Tokenizer class to writer Markdown output. It supports
|
||||
both Standard Markdown and GitHub Flavour Markdown (Extended). The
|
||||
class also supports concatenating novelWriter markup files.
|
||||
"""
|
||||
|
||||
M_STD = 0 # Standard Markdown
|
||||
M_GH = 1 # GitHub Markdown
|
||||
|
||||
+248
-268
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – ODT Text Converter
|
||||
================================
|
||||
Extends the Tokenizer class to generate ODT and FODT files
|
||||
|
||||
File History:
|
||||
Created: 2021-01-26 [1.2b1] ToOdt
|
||||
@@ -25,8 +24,10 @@ 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/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from hashlib import sha256
|
||||
@@ -36,6 +37,7 @@ from datetime import datetime
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import xmlIndent
|
||||
from novelwriter.constants import nwKeyWords, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer, stripEscape
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -55,9 +57,8 @@ for ns, uri in XML_NS.items():
|
||||
ET.register_namespace(ns, uri)
|
||||
|
||||
|
||||
def _mkTag(ns, tag):
|
||||
"""Assemble namespace and tag name.
|
||||
"""
|
||||
def _mkTag(ns: str, tag: str) -> str:
|
||||
"""Assemble namespace and tag name."""
|
||||
uri = XML_NS.get(ns, "")
|
||||
if uri:
|
||||
return f"{{{uri}}}{tag}"
|
||||
@@ -89,9 +90,16 @@ M_DEL = ~X_DEL
|
||||
|
||||
|
||||
class ToOdt(Tokenizer):
|
||||
"""Core: Open Document Writer
|
||||
|
||||
def __init__(self, theProject, isFlat):
|
||||
super().__init__(theProject)
|
||||
Extend the Tokenizer class to writer Open Document files. The output
|
||||
should conform to the 1.3 Extended standard.
|
||||
|
||||
Test with: https://odfvalidator.org/
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject, isFlat: bool):
|
||||
super().__init__(project)
|
||||
|
||||
self._isFlat = isFlat # Flat: .fodt, otherwise .odt
|
||||
|
||||
@@ -178,36 +186,26 @@ class ToOdt(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setLanguage(self, theLang):
|
||||
"""Set language for the document.
|
||||
"""
|
||||
if theLang is None:
|
||||
return False
|
||||
def setLanguage(self, language: str):
|
||||
"""Set language for the document."""
|
||||
if language:
|
||||
langBits = language.split("_")
|
||||
self._dLanguage = langBits[0]
|
||||
if len(langBits) > 1:
|
||||
self._dCountry = langBits[1]
|
||||
return
|
||||
|
||||
langBits = theLang.split("_")
|
||||
self._dLanguage = langBits[0]
|
||||
if len(langBits) > 1:
|
||||
self._dCountry = langBits[1]
|
||||
|
||||
return True
|
||||
|
||||
def setColourHeaders(self, doColour):
|
||||
"""Enable/disable coloured headings and comments.
|
||||
"""
|
||||
self._colourHead = doColour
|
||||
def setColourHeaders(self, state: bool):
|
||||
"""Enable/disable coloured headings and comments."""
|
||||
self._colourHead = state
|
||||
return
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def getErrors(self):
|
||||
"""Return the list of errors."""
|
||||
return self._errData
|
||||
|
||||
def initDocument(self):
|
||||
"""Initialises a new open document XML tree.
|
||||
"""
|
||||
"""Initialises a new open document XML tree."""
|
||||
# Initialise Variables
|
||||
# ====================
|
||||
|
||||
@@ -369,8 +367,7 @@ class ToOdt(Tokenizer):
|
||||
return
|
||||
|
||||
def doConvert(self):
|
||||
"""Convert the list of text tokens into XML elements.
|
||||
"""
|
||||
"""Convert the list of text tokens into XML elements."""
|
||||
self._result = "" # Not used, but cleared just in case
|
||||
|
||||
odtTags = {
|
||||
@@ -421,12 +418,12 @@ class ToOdt(Tokenizer):
|
||||
if self._doJustify:
|
||||
parStyle.setTextAlign("left")
|
||||
|
||||
if len(thisPar) > 0:
|
||||
if len(thisPar) > 0 and parStyle is not None:
|
||||
tTemp = "\n".join(thisPar)
|
||||
fTemp = " ".join(thisFmt)
|
||||
tTxt = tTemp.rstrip()
|
||||
tFmt = fTemp[:len(tTxt)]
|
||||
self._addTextPar("Text_20_body", parStyle, tTxt, theFmt=tFmt)
|
||||
self._addTextPar("Text_20_body", parStyle, tTxt, tFmt=tFmt)
|
||||
|
||||
thisPar = []
|
||||
thisFmt = []
|
||||
@@ -477,41 +474,37 @@ class ToOdt(Tokenizer):
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
tTemp, fTemp = self._formatSynopsis(tText)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
tTemp, fTemp = self._formatComments(tText)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
tTemp, fTemp = self._formatKeywords(tText)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, theFmt=fTemp)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
|
||||
return
|
||||
|
||||
def closeDocument(self):
|
||||
"""Return the serialised XML document
|
||||
"""
|
||||
"""Return the serialised XML document"""
|
||||
# Build the auto-generated styles
|
||||
for styleName, styleObj in self._autoPara.values():
|
||||
styleObj.packXML(self._xAuto, styleName)
|
||||
for styleName, styleObj in self._autoText.values():
|
||||
styleObj.packXML(self._xAuto, styleName)
|
||||
|
||||
return
|
||||
|
||||
def saveFlatXML(self, savePath):
|
||||
"""Save the data to an .fodt file.
|
||||
"""
|
||||
with open(savePath, mode="wb") as outFile:
|
||||
def saveFlatXML(self, path: str | Path):
|
||||
"""Save the data to an .fodt file."""
|
||||
with open(path, mode="wb") as fObj:
|
||||
xml = ET.ElementTree(self._dFlat)
|
||||
xmlIndent(xml)
|
||||
xml.write(outFile, encoding="utf-8", xml_declaration=True)
|
||||
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
||||
return
|
||||
|
||||
def saveOpenDocText(self, savePath):
|
||||
"""Save the data to an .odt file.
|
||||
"""
|
||||
def saveOpenDocText(self, path: str | Path):
|
||||
"""Save the data to an .odt file."""
|
||||
mMani = _mkTag("manifest", "manifest")
|
||||
mVers = _mkTag("manifest", "version")
|
||||
mPath = _mkTag("manifest", "full-path")
|
||||
@@ -534,7 +527,7 @@ class ToOdt(Tokenizer):
|
||||
xml = ET.ElementTree(xObj)
|
||||
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
||||
|
||||
with ZipFile(savePath, mode="w") as outZip:
|
||||
with ZipFile(path, mode="w") as outZip:
|
||||
outZip.writestr("mimetype", X_MIME)
|
||||
putInZip("META-INF/manifest.xml", xMani, outZip)
|
||||
putInZip("settings.xml", xSett, outZip)
|
||||
@@ -548,49 +541,48 @@ class ToOdt(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatSynopsis(self, tText):
|
||||
"""Apply formatting to synopsis lines.
|
||||
"""
|
||||
def _formatSynopsis(self, text: str) -> tuple[str, str]:
|
||||
"""Apply formatting to synopsis lines."""
|
||||
sSynop = self._localLookup("Synopsis")
|
||||
rTxt = "**{0}:** {1}".format(sSynop, tText)
|
||||
rFmt = "_B{0} b_ {1}".format(" "*len(sSynop), " "*len(tText))
|
||||
rTxt = "**{0}:** {1}".format(sSynop, text)
|
||||
rFmt = "_B{0} b_ {1}".format(" "*len(sSynop), " "*len(text))
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatComments(self, tText):
|
||||
"""Apply formatting to comments.
|
||||
"""
|
||||
def _formatComments(self, text: str) -> tuple[str, str]:
|
||||
"""Apply formatting to comments."""
|
||||
sComm = self._localLookup("Comment")
|
||||
rTxt = "**{0}:** {1}".format(sComm, tText)
|
||||
rFmt = "_B{0} b_ {1}".format(" "*len(sComm), " "*len(tText))
|
||||
rTxt = "**{0}:** {1}".format(sComm, text)
|
||||
rFmt = "_B{0} b_ {1}".format(" "*len(sComm), " "*len(text))
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatKeywords(self, tText):
|
||||
"""Apply formatting to keywords.
|
||||
"""
|
||||
isValid, theBits, _ = self._project.index.scanThis("@"+tText)
|
||||
if not isValid or not theBits:
|
||||
return ""
|
||||
def _formatKeywords(self, text: str) -> tuple[str, str]:
|
||||
"""Apply formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
if not valid or not bits:
|
||||
return "", ""
|
||||
|
||||
rTxt = ""
|
||||
rFmt = ""
|
||||
if theBits[0] in nwLabels.KEY_NAME:
|
||||
tText = nwLabels.KEY_NAME[theBits[0]]
|
||||
rTxt += "**{0}:** ".format(tText)
|
||||
rFmt += "_B{0} b_ ".format(" "*len(tText))
|
||||
if len(theBits) > 1:
|
||||
if theBits[0] == nwKeyWords.TAG_KEY:
|
||||
rTxt += theBits[1]
|
||||
rFmt += " "*len(theBits[1])
|
||||
if bits[0] in nwLabels.KEY_NAME:
|
||||
text = nwLabels.KEY_NAME[bits[0]]
|
||||
rTxt += "**{0}:** ".format(text)
|
||||
rFmt += "_B{0} b_ ".format(" "*len(text))
|
||||
if len(bits) > 1:
|
||||
if bits[0] == nwKeyWords.TAG_KEY:
|
||||
rTxt += bits[1]
|
||||
rFmt += " "*len(bits[1])
|
||||
else:
|
||||
tTags = ", ".join(theBits[1:])
|
||||
tTags = ", ".join(bits[1:])
|
||||
rTxt += tTags
|
||||
rFmt += (" "*len(tTags))
|
||||
|
||||
return rTxt, rFmt
|
||||
|
||||
def _addTextPar(self, styleName, oStyle, theText, theFmt="", isHead=False, oLevel=None):
|
||||
"""Add a text paragraph to the text XML element.
|
||||
"""
|
||||
def _addTextPar(
|
||||
self, styleName: str, oStyle: ODTParagraphStyle, tText: str, tFmt: str = "",
|
||||
isHead: bool = False, oLevel: str | None = None
|
||||
):
|
||||
"""Add a text paragraph to the text XML element."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("text", "style-name")] = self._paraStyle(styleName, oStyle)
|
||||
if oLevel is not None:
|
||||
@@ -603,16 +595,16 @@ class ToOdt(Tokenizer):
|
||||
# xmlIndent will add a line break if the first subelement is a span.
|
||||
xElem.text = ""
|
||||
|
||||
if not theText:
|
||||
if not tText:
|
||||
return
|
||||
|
||||
##
|
||||
# Process Formatting
|
||||
##
|
||||
|
||||
if len(theText) != len(theFmt):
|
||||
if len(tText) != len(tFmt):
|
||||
# Generate an empty format if there isn't any or it doesn't match
|
||||
theFmt = " "*len(theText)
|
||||
tFmt = " "*len(tText)
|
||||
|
||||
# The formatting loop
|
||||
tTemp = ""
|
||||
@@ -622,23 +614,23 @@ class ToOdt(Tokenizer):
|
||||
|
||||
parProc = XMLParagraph(xElem)
|
||||
|
||||
for i, c in enumerate(theText):
|
||||
for i, c in enumerate(tText):
|
||||
|
||||
if theFmt[i] == " ":
|
||||
if tFmt[i] == " ":
|
||||
tTemp += c
|
||||
elif theFmt[i] == "_":
|
||||
elif tFmt[i] == "_":
|
||||
continue
|
||||
elif theFmt[i] == "B":
|
||||
elif tFmt[i] == "B":
|
||||
xFmt |= X_BLD
|
||||
elif theFmt[i] == "b":
|
||||
elif tFmt[i] == "b":
|
||||
xFmt &= M_BLD
|
||||
elif theFmt[i] == "I":
|
||||
elif tFmt[i] == "I":
|
||||
xFmt |= X_ITA
|
||||
elif theFmt[i] == "i":
|
||||
elif tFmt[i] == "i":
|
||||
xFmt &= M_ITA
|
||||
elif theFmt[i] == "S":
|
||||
elif tFmt[i] == "S":
|
||||
xFmt |= X_DEL
|
||||
elif theFmt[i] == "s":
|
||||
elif tFmt[i] == "s":
|
||||
xFmt &= M_DEL
|
||||
else:
|
||||
pErr += 1
|
||||
@@ -669,9 +661,8 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def _paraStyle(self, parName, oStyle):
|
||||
"""Return a name for a style object.
|
||||
"""
|
||||
def _paraStyle(self, parName: str, oStyle: ODTParagraphStyle) -> str:
|
||||
"""Return a name for a style object."""
|
||||
refStyle = self._mainPara.get(parName, None)
|
||||
if refStyle is None:
|
||||
logger.error("Unknown paragraph style '%s'", parName)
|
||||
@@ -690,29 +681,27 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return newName
|
||||
|
||||
def _textStyle(self, tFmt):
|
||||
"""Return a text style for a given style code.
|
||||
"""
|
||||
if tFmt in self._autoText:
|
||||
return self._autoText[tFmt][0]
|
||||
def _textStyle(self, hFmt: int) -> str:
|
||||
"""Return a text style for a given style code."""
|
||||
if hFmt in self._autoText:
|
||||
return self._autoText[hFmt][0]
|
||||
|
||||
newName = "T%d" % (len(self._autoText) + 1)
|
||||
newStyle = ODTTextStyle()
|
||||
if tFmt & X_BLD:
|
||||
if hFmt & X_BLD:
|
||||
newStyle.setFontWeight("bold")
|
||||
if tFmt & X_ITA:
|
||||
if hFmt & X_ITA:
|
||||
newStyle.setFontStyle("italic")
|
||||
if tFmt & X_DEL:
|
||||
if hFmt & X_DEL:
|
||||
newStyle.setStrikeStyle("solid")
|
||||
newStyle.setStrikeType("single")
|
||||
|
||||
self._autoText[tFmt] = (newName, newStyle)
|
||||
self._autoText[hFmt] = (newName, newStyle)
|
||||
|
||||
return newName
|
||||
|
||||
def _emToCm(self, emVal):
|
||||
"""Converts an em value to centimetres.
|
||||
"""
|
||||
def _emToCm(self, emVal: float) -> str:
|
||||
"""Converts an em value to centimetres."""
|
||||
return f"{emVal*2.54/72*self._textSize:.3f}cm"
|
||||
|
||||
##
|
||||
@@ -720,110 +709,107 @@ class ToOdt(Tokenizer):
|
||||
##
|
||||
|
||||
def _pageStyles(self):
|
||||
"""Set the default page style.
|
||||
"""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = "PM1"
|
||||
"""Set the default page style."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "PM1"
|
||||
if self._isFlat:
|
||||
xPage = ET.SubElement(self._xAuto, _mkTag("style", "page-layout"), attrib=theAttr)
|
||||
xPage = ET.SubElement(self._xAuto, _mkTag("style", "page-layout"), attrib=tAttr)
|
||||
else:
|
||||
xPage = ET.SubElement(self._xAut2, _mkTag("style", "page-layout"), attrib=theAttr)
|
||||
xPage = ET.SubElement(self._xAut2, _mkTag("style", "page-layout"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("fo", "margin-top")] = self._mDocTop
|
||||
theAttr[_mkTag("fo", "margin-bottom")] = self._mDocBtm
|
||||
theAttr[_mkTag("fo", "margin-left")] = self._mDocLeft
|
||||
theAttr[_mkTag("fo", "margin-right")] = self._mDocRight
|
||||
ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("fo", "margin-top")] = self._mDocTop
|
||||
tAttr[_mkTag("fo", "margin-bottom")] = self._mDocBtm
|
||||
tAttr[_mkTag("fo", "margin-left")] = self._mDocLeft
|
||||
tAttr[_mkTag("fo", "margin-right")] = self._mDocRight
|
||||
ET.SubElement(xPage, _mkTag("style", "page-layout-properties"), attrib=tAttr)
|
||||
|
||||
xHead = ET.SubElement(xPage, _mkTag("style", "header-style"))
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("fo", "min-height")] = "0.600cm"
|
||||
theAttr[_mkTag("fo", "margin-left")] = "0.000cm"
|
||||
theAttr[_mkTag("fo", "margin-right")] = "0.000cm"
|
||||
theAttr[_mkTag("fo", "margin-bottom")] = "0.500cm"
|
||||
ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("fo", "min-height")] = "0.600cm"
|
||||
tAttr[_mkTag("fo", "margin-left")] = "0.000cm"
|
||||
tAttr[_mkTag("fo", "margin-right")] = "0.000cm"
|
||||
tAttr[_mkTag("fo", "margin-bottom")] = "0.500cm"
|
||||
ET.SubElement(xHead, _mkTag("style", "header-footer-properties"), attrib=tAttr)
|
||||
|
||||
return
|
||||
|
||||
def _defaultStyles(self):
|
||||
"""Set the default styles.
|
||||
"""
|
||||
"""Set the default styles."""
|
||||
# Add Paragraph Family Style
|
||||
# ==========================
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "family")] = "paragraph"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "family")] = "paragraph"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "default-style"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "line-break")] = "strict"
|
||||
theAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm"
|
||||
theAttr[_mkTag("style", "writing-mode")] = "page"
|
||||
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "line-break")] = "strict"
|
||||
tAttr[_mkTag("style", "tab-stop-distance")] = "1.251cm"
|
||||
tAttr[_mkTag("style", "writing-mode")] = "page"
|
||||
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||
theAttr[_mkTag("fo", "language")] = self._dLanguage
|
||||
theAttr[_mkTag("fo", "country")] = self._dCountry
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
tAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
tAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||
tAttr[_mkTag("fo", "language")] = self._dLanguage
|
||||
tAttr[_mkTag("fo", "country")] = self._dCountry
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
|
||||
|
||||
# Add Standard Paragraph Style
|
||||
# ============================
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = "Standard"
|
||||
theAttr[_mkTag("style", "family")] = "paragraph"
|
||||
theAttr[_mkTag("style", "class")] = "text"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "Standard"
|
||||
tAttr[_mkTag("style", "family")] = "paragraph"
|
||||
tAttr[_mkTag("style", "class")] = "text"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
tAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
tAttr[_mkTag("fo", "font-size")] = self._fSizeText
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
|
||||
|
||||
# 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_20_body"
|
||||
theAttr[_mkTag("style", "class")] = "text"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "Heading"
|
||||
tAttr[_mkTag("style", "family")] = "paragraph"
|
||||
tAttr[_mkTag("style", "parent-style-name")] = "Standard"
|
||||
tAttr[_mkTag("style", "next-style-name")] = "Text_20_body"
|
||||
tAttr[_mkTag("style", "class")] = "text"
|
||||
xStyl = ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("fo", "margin-top")] = self._mTopHead
|
||||
theAttr[_mkTag("fo", "margin-bottom")] = self._mBotHead
|
||||
theAttr[_mkTag("fo", "keep-with-next")] = "always"
|
||||
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("fo", "margin-top")] = self._mTopHead
|
||||
tAttr[_mkTag("fo", "margin-bottom")] = self._mBotHead
|
||||
tAttr[_mkTag("fo", "keep-with-next")] = "always"
|
||||
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib=tAttr)
|
||||
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
theAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
theAttr[_mkTag("fo", "font-size")] = self._fSizeHead
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "font-name")] = self._textFont
|
||||
tAttr[_mkTag("fo", "font-family")] = self._fontFamily
|
||||
tAttr[_mkTag("fo", "font-size")] = self._fSizeHead
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib=tAttr)
|
||||
|
||||
# Add Header and Footer Styles
|
||||
# ============================
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = "Header_20_and_20_Footer"
|
||||
theAttr[_mkTag("style", "display-name")] = "Header and Footer"
|
||||
theAttr[_mkTag("style", "family")] = "paragraph"
|
||||
theAttr[_mkTag("style", "parent-style-name")] = "Standard"
|
||||
theAttr[_mkTag("style", "class")] = "extra"
|
||||
ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=theAttr)
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "Header_20_and_20_Footer"
|
||||
tAttr[_mkTag("style", "display-name")] = "Header and Footer"
|
||||
tAttr[_mkTag("style", "family")] = "paragraph"
|
||||
tAttr[_mkTag("style", "parent-style-name")] = "Standard"
|
||||
tAttr[_mkTag("style", "class")] = "extra"
|
||||
ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib=tAttr)
|
||||
|
||||
return
|
||||
|
||||
def _useableStyles(self):
|
||||
"""Set the usable styles.
|
||||
"""
|
||||
"""Set the usable styles."""
|
||||
# Add Text Body Style
|
||||
# ===================
|
||||
|
||||
@@ -977,12 +963,11 @@ class ToOdt(Tokenizer):
|
||||
return
|
||||
|
||||
def _writeHeader(self):
|
||||
"""Write the header elements.
|
||||
"""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = "Standard"
|
||||
theAttr[_mkTag("style", "page-layout-name")] = "PM1"
|
||||
xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib=theAttr)
|
||||
"""Write the header elements."""
|
||||
tAttr = {}
|
||||
tAttr[_mkTag("style", "name")] = "Standard"
|
||||
tAttr[_mkTag("style", "page-layout-name")] = "PM1"
|
||||
xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib=tAttr)
|
||||
|
||||
# Standard Page Header
|
||||
xHead = ET.SubElement(xPage, _mkTag("style", "header"))
|
||||
@@ -1062,28 +1047,28 @@ class ODTParagraphStyle:
|
||||
# Attribute Setters
|
||||
##
|
||||
|
||||
def setDisplayName(self, theValue):
|
||||
self._mAttr["display-name"][1] = str(theValue)
|
||||
def setDisplayName(self, value: str | None):
|
||||
self._mAttr["display-name"][1] = value
|
||||
return
|
||||
|
||||
def setParentStyleName(self, theValue):
|
||||
self._mAttr["parent-style-name"][1] = str(theValue)
|
||||
def setParentStyleName(self, value: str | None):
|
||||
self._mAttr["parent-style-name"][1] = value
|
||||
return
|
||||
|
||||
def setNextStyleName(self, theValue):
|
||||
self._mAttr["next-style-name"][1] = str(theValue)
|
||||
def setNextStyleName(self, value: str | None):
|
||||
self._mAttr["next-style-name"][1] = value
|
||||
return
|
||||
|
||||
def setOutlineLevel(self, theValue):
|
||||
if theValue in self.VALID_LEVEL:
|
||||
self._mAttr["default-outline-level"][1] = str(theValue)
|
||||
def setOutlineLevel(self, value: str | None):
|
||||
if value in self.VALID_LEVEL:
|
||||
self._mAttr["default-outline-level"][1] = value
|
||||
else:
|
||||
self._mAttr["default-outline-level"][1] = None
|
||||
return
|
||||
|
||||
def setClass(self, theValue):
|
||||
if theValue in self.VALID_CLASS:
|
||||
self._mAttr["class"][1] = str(theValue)
|
||||
def setClass(self, value: str | None):
|
||||
if value in self.VALID_CLASS:
|
||||
self._mAttr["class"][1] = value
|
||||
else:
|
||||
self._mAttr["class"][1] = None
|
||||
return
|
||||
@@ -1092,43 +1077,43 @@ class ODTParagraphStyle:
|
||||
# Paragraph Setters
|
||||
##
|
||||
|
||||
def setMarginTop(self, theValue):
|
||||
self._pAttr["margin-top"][1] = str(theValue)
|
||||
def setMarginTop(self, value: str | None):
|
||||
self._pAttr["margin-top"][1] = value
|
||||
return
|
||||
|
||||
def setMarginBottom(self, theValue):
|
||||
self._pAttr["margin-bottom"][1] = str(theValue)
|
||||
def setMarginBottom(self, value: str | None):
|
||||
self._pAttr["margin-bottom"][1] = value
|
||||
return
|
||||
|
||||
def setMarginLeft(self, theValue):
|
||||
self._pAttr["margin-left"][1] = str(theValue)
|
||||
def setMarginLeft(self, value: str | None):
|
||||
self._pAttr["margin-left"][1] = value
|
||||
return
|
||||
|
||||
def setMarginRight(self, theValue):
|
||||
self._pAttr["margin-right"][1] = str(theValue)
|
||||
def setMarginRight(self, value: str | None):
|
||||
self._pAttr["margin-right"][1] = value
|
||||
return
|
||||
|
||||
def setLineHeight(self, theValue):
|
||||
self._pAttr["line-height"][1] = str(theValue)
|
||||
def setLineHeight(self, value: str | None):
|
||||
self._pAttr["line-height"][1] = value
|
||||
return
|
||||
|
||||
def setTextAlign(self, theValue):
|
||||
if theValue in self.VALID_ALIGN:
|
||||
self._pAttr["text-align"][1] = str(theValue)
|
||||
def setTextAlign(self, value: str | None):
|
||||
if value in self.VALID_ALIGN:
|
||||
self._pAttr["text-align"][1] = value
|
||||
else:
|
||||
self._pAttr["text-align"][1] = None
|
||||
return
|
||||
|
||||
def setBreakBefore(self, theValue):
|
||||
if theValue in self.VALID_BREAK:
|
||||
self._pAttr["break-before"][1] = str(theValue)
|
||||
def setBreakBefore(self, value: str | None):
|
||||
if value in self.VALID_BREAK:
|
||||
self._pAttr["break-before"][1] = value
|
||||
else:
|
||||
self._pAttr["break-before"][1] = None
|
||||
return
|
||||
|
||||
def setBreakAfter(self, theValue):
|
||||
if theValue in self.VALID_BREAK:
|
||||
self._pAttr["break-after"][1] = str(theValue)
|
||||
def setBreakAfter(self, value: str | None):
|
||||
if value in self.VALID_BREAK:
|
||||
self._pAttr["break-after"][1] = value
|
||||
else:
|
||||
self._pAttr["break-after"][1] = None
|
||||
return
|
||||
@@ -1137,38 +1122,38 @@ class ODTParagraphStyle:
|
||||
# Text Setters
|
||||
##
|
||||
|
||||
def setFontName(self, theValue):
|
||||
self._tAttr["font-name"][1] = str(theValue)
|
||||
def setFontName(self, value: str | None):
|
||||
self._tAttr["font-name"][1] = value
|
||||
return
|
||||
|
||||
def setFontFamily(self, theValue):
|
||||
self._tAttr["font-family"][1] = str(theValue)
|
||||
def setFontFamily(self, value: str | None):
|
||||
self._tAttr["font-family"][1] = value
|
||||
return
|
||||
|
||||
def setFontSize(self, theValue):
|
||||
self._tAttr["font-size"][1] = str(theValue)
|
||||
def setFontSize(self, value: str | None):
|
||||
self._tAttr["font-size"][1] = value
|
||||
return
|
||||
|
||||
def setFontWeight(self, theValue):
|
||||
if theValue in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = str(theValue)
|
||||
def setFontWeight(self, value: str | None):
|
||||
if value in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = value
|
||||
else:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setColor(self, theValue):
|
||||
self._tAttr["color"][1] = str(theValue)
|
||||
def setColor(self, value: str | None):
|
||||
self._tAttr["color"][1] = value
|
||||
return
|
||||
|
||||
def setOpacity(self, theValue):
|
||||
self._tAttr["opacity"][1] = str(theValue)
|
||||
def setOpacity(self, value: str | None):
|
||||
self._tAttr["opacity"][1] = value
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def checkNew(self, refStyle):
|
||||
def checkNew(self, refStyle: ODTParagraphStyle):
|
||||
"""Check if there are new settings in refStyle that differ from
|
||||
those in the current object.
|
||||
"""
|
||||
@@ -1183,9 +1168,8 @@ class ODTParagraphStyle:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getID(self):
|
||||
"""Generate a unique ID from the settings.
|
||||
"""
|
||||
def getID(self) -> str:
|
||||
"""Generate a unique ID from the settings."""
|
||||
theString = (
|
||||
f"Paragraph:Main:{str(self._mAttr)}:"
|
||||
f"Paragraph:Para:{str(self._pAttr)}:"
|
||||
@@ -1193,11 +1177,10 @@ class ODTParagraphStyle:
|
||||
)
|
||||
return sha256(theString.encode()).hexdigest()
|
||||
|
||||
def packXML(self, xParent, xName):
|
||||
"""Pack the content into an xml element.
|
||||
"""
|
||||
def packXML(self, xParent: ET.Element, name: str):
|
||||
"""Pack the content into an xml element."""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = xName
|
||||
theAttr[_mkTag("style", "name")] = name
|
||||
theAttr[_mkTag("style", "family")] = "paragraph"
|
||||
for aName, (aNm, aVal) in self._mAttr.items():
|
||||
if aVal is not None:
|
||||
@@ -1252,30 +1235,30 @@ class ODTTextStyle:
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setFontWeight(self, theValue):
|
||||
if theValue in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = str(theValue)
|
||||
def setFontWeight(self, value: str | None):
|
||||
if value in self.VALID_WEIGHT:
|
||||
self._tAttr["font-weight"][1] = value
|
||||
else:
|
||||
self._tAttr["font-weight"][1] = None
|
||||
return
|
||||
|
||||
def setFontStyle(self, theValue):
|
||||
if theValue in self.VALID_STYLE:
|
||||
self._tAttr["font-style"][1] = str(theValue)
|
||||
def setFontStyle(self, value: str | None):
|
||||
if value in self.VALID_STYLE:
|
||||
self._tAttr["font-style"][1] = value
|
||||
else:
|
||||
self._tAttr["font-style"][1] = None
|
||||
return
|
||||
|
||||
def setStrikeStyle(self, theValue):
|
||||
if theValue in self.VALID_LSTYLE:
|
||||
self._tAttr["text-line-through-style"][1] = str(theValue)
|
||||
def setStrikeStyle(self, value: str | None):
|
||||
if value in self.VALID_LSTYLE:
|
||||
self._tAttr["text-line-through-style"][1] = value
|
||||
else:
|
||||
self._tAttr["text-line-through-style"][1] = None
|
||||
return
|
||||
|
||||
def setStrikeType(self, theValue):
|
||||
if theValue in self.VALID_LTYPE:
|
||||
self._tAttr["text-line-through-type"][1] = str(theValue)
|
||||
def setStrikeType(self, value: str | None):
|
||||
if value in self.VALID_LTYPE:
|
||||
self._tAttr["text-line-through-type"][1] = value
|
||||
else:
|
||||
self._tAttr["text-line-through-type"][1] = None
|
||||
return
|
||||
@@ -1284,11 +1267,10 @@ class ODTTextStyle:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def packXML(self, xParent, xName):
|
||||
"""Pack the content into an xml element.
|
||||
"""
|
||||
def packXML(self, xParent: ET.Element, name: str):
|
||||
"""Pack the content into an xml element."""
|
||||
theAttr = {}
|
||||
theAttr[_mkTag("style", "name")] = xName
|
||||
theAttr[_mkTag("style", "name")] = name
|
||||
theAttr[_mkTag("style", "family")] = "text"
|
||||
xEntry = ET.SubElement(xParent, _mkTag("style", "style"), attrib=theAttr)
|
||||
|
||||
@@ -1335,7 +1317,7 @@ class XMLParagraph:
|
||||
object and attribute is written to,
|
||||
"""
|
||||
|
||||
def __init__(self, xRoot):
|
||||
def __init__(self, xRoot: ET.Element):
|
||||
|
||||
self._xRoot = xRoot
|
||||
self._xTail = ET.Element("")
|
||||
@@ -1348,17 +1330,17 @@ class XMLParagraph:
|
||||
|
||||
return
|
||||
|
||||
def appendText(self, text):
|
||||
def appendText(self, tText: str):
|
||||
"""Append text to the XML element. We do this one character at
|
||||
the time in order to be able to process line breaks, tabs and
|
||||
spaces separately. Multiple spaces above one are concatenated
|
||||
into a single tag, and must therefore be processed separately.
|
||||
spaces separately. Multiple spaces are concatenated into a
|
||||
single tag, and must therefore be processed separately.
|
||||
"""
|
||||
text = stripEscape(text)
|
||||
tText = stripEscape(tText)
|
||||
nSpaces = 0
|
||||
self._rawTxt += text
|
||||
self._rawTxt += tText
|
||||
|
||||
for c in text:
|
||||
for c in tText:
|
||||
if c == " ":
|
||||
nSpaces += 1
|
||||
continue
|
||||
@@ -1395,38 +1377,36 @@ class XMLParagraph:
|
||||
|
||||
else:
|
||||
if self._nState == X_ROOT_TEXT:
|
||||
self._xRoot.text += c
|
||||
self._xRoot.text = (self._xRoot.text or "") + c
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_ROOT_TAIL:
|
||||
self._xTail.tail += c
|
||||
self._xTail.tail = (self._xTail.tail or "") + c
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_SPAN_TEXT:
|
||||
self._xTail.text += c
|
||||
self._xTail.text = (self._xTail.text or "") + c
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_SPAN_SING:
|
||||
self._xSing.tail += c
|
||||
self._xSing.tail = (self._xSing.tail or "") + c
|
||||
self._chrPos += 1
|
||||
|
||||
if nSpaces > 0:
|
||||
# Handle trailing spaces
|
||||
self._processSpaces(nSpaces)
|
||||
|
||||
return
|
||||
|
||||
def appendSpan(self, tText, tFmt):
|
||||
def appendSpan(self, tText: str, tFmt: str):
|
||||
"""Append a text span to the XML element. The span is always
|
||||
closed since we do not allow nested spans (like Libre Office).
|
||||
Therefore we return to the root element level when we're done
|
||||
processing the text of the span.
|
||||
"""
|
||||
self._xTail = ET.SubElement(self._xRoot, TAG_SPAN, attrib={
|
||||
TAG_STNM: tFmt
|
||||
})
|
||||
self._xTail = ET.SubElement(self._xRoot, TAG_SPAN, attrib={TAG_STNM: tFmt})
|
||||
self._xTail.text = "" # Defaults to None
|
||||
self._xTail.tail = "" # Defaults to None
|
||||
self._nState = X_SPAN_TEXT
|
||||
self.appendText(tText)
|
||||
self._nState = X_ROOT_TAIL
|
||||
|
||||
return
|
||||
|
||||
def checkError(self):
|
||||
@@ -1443,7 +1423,7 @@ class XMLParagraph:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _processSpaces(self, nSpaces):
|
||||
def _processSpaces(self, nSpaces: int):
|
||||
"""Add spaces to paragraph. The first space is always written
|
||||
as-is (unless it's the first character of the paragraph). The
|
||||
second space uses the dedicated tag for spaces, and from the
|
||||
@@ -1455,16 +1435,16 @@ class XMLParagraph:
|
||||
if nSpaces > 0:
|
||||
if self._chrPos > 0:
|
||||
if self._nState == X_ROOT_TEXT:
|
||||
self._xRoot.text += " "
|
||||
self._xRoot.text = (self._xRoot.text or "") + " "
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_ROOT_TAIL:
|
||||
self._xTail.tail += " "
|
||||
self._xTail.tail = (self._xTail.tail or "") + " "
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_SPAN_TEXT:
|
||||
self._xTail.text += " "
|
||||
self._xTail.text = (self._xTail.text or "") + " "
|
||||
self._chrPos += 1
|
||||
elif self._nState == X_SPAN_SING:
|
||||
self._xSing.tail += " "
|
||||
self._xSing.tail = (self._xSing.tail or "") + " "
|
||||
self._chrPos += 1
|
||||
else:
|
||||
nSpaces += 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<office:document-styles xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3">
|
||||
<office:document-styles xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3">
|
||||
<office:font-face-decls>
|
||||
<style:font-face style:name="Liberation Serif" style:font-pitch="variable" />
|
||||
</office:font-face-decls>
|
||||
@@ -22,7 +22,7 @@
|
||||
</style:style>
|
||||
<style:style style:name="Text_20_Meta" style:family="paragraph" style:display-name="Text Meta" style:parent-style-name="Standard" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0.000cm" fo:margin-bottom="0.247cm" fo:line-height="115%" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="12pt" fo:color="None" loext:opacity="None" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="12pt" />
|
||||
</style:style>
|
||||
<style:style style:name="Title" style:family="paragraph" style:display-name="Title" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:class="chapter">
|
||||
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:text-align="center" />
|
||||
@@ -30,19 +30,19 @@
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_1" style:family="paragraph" style:display-name="Heading 1" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="24pt" fo:font-weight="bold" fo:color="None" loext:opacity="None" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="24pt" fo:font-weight="bold" />
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_2" style:family="paragraph" style:display-name="Heading 2" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="2" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0.353cm" fo:margin-bottom="0.212cm" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="19pt" fo:font-weight="bold" fo:color="None" loext:opacity="None" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="19pt" fo:font-weight="bold" />
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_3" style:family="paragraph" style:display-name="Heading 3" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="3" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0.247cm" fo:margin-bottom="0.212cm" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="16pt" fo:font-weight="bold" fo:color="None" loext:opacity="None" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="16pt" fo:font-weight="bold" />
|
||||
</style:style>
|
||||
<style:style style:name="Heading_20_4" style:family="paragraph" style:display-name="Heading 4" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="4" style:class="text">
|
||||
<style:paragraph-properties fo:margin-top="0.247cm" fo:margin-bottom="0.212cm" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="14pt" fo:font-weight="bold" fo:color="None" loext:opacity="None" />
|
||||
<style:text-properties style:font-name="Liberation Serif" fo:font-family="'Liberation Serif'" fo:font-size="14pt" fo:font-weight="bold" />
|
||||
</style:style>
|
||||
<style:style style:name="Header" style:family="paragraph" style:display-name="Header" style:parent-style-name="Header_20_and_20_Footer">
|
||||
<style:paragraph-properties fo:text-align="right" />
|
||||
|
||||
@@ -43,8 +43,7 @@ XML_NS = [
|
||||
|
||||
|
||||
def xmlToText(xElem):
|
||||
"""Get the text content of an XML element.
|
||||
"""
|
||||
"""Get the text content of an XML element."""
|
||||
rTxt = ET.tostring(xElem, encoding="utf-8", xml_declaration=False).decode()
|
||||
for nSpace in XML_NS:
|
||||
rTxt = rTxt.replace(nSpace, "")
|
||||
@@ -53,8 +52,7 @@ def xmlToText(xElem):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_Init(mockGUI):
|
||||
"""Test initialisation of the ODT document.
|
||||
"""
|
||||
"""Test initialisation of the ODT document."""
|
||||
theProject = NWProject(mockGUI)
|
||||
|
||||
# Flat Doc
|
||||
@@ -109,8 +107,7 @@ def testCoreToOdt_Init(mockGUI):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_TextFormatting(mockGUI):
|
||||
"""Test formatting of paragraphs.
|
||||
"""
|
||||
"""Test formatting of paragraphs."""
|
||||
theProject = NWProject(mockGUI)
|
||||
theDoc = ToOdt(theProject, isFlat=True)
|
||||
|
||||
@@ -156,7 +153,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
# No Format
|
||||
theDoc.initDocument()
|
||||
theDoc._addTextPar("Standard", oStyle, "Hello World")
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:p text:style-name=\"Standard\">Hello World</text:p>"
|
||||
@@ -166,7 +163,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
# Heading Level None
|
||||
theDoc.initDocument()
|
||||
theDoc._addTextPar("Standard", oStyle, "Hello World", isHead=True)
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:h text:style-name=\"Standard\">Hello World</text:h>"
|
||||
@@ -176,7 +173,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
# Heading Level 1
|
||||
theDoc.initDocument()
|
||||
theDoc._addTextPar("Standard", oStyle, "Hello World", isHead=True, oLevel="1")
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:h text:style-name=\"Standard\" text:outline-level=\"1\">Hello World</text:h>"
|
||||
@@ -187,8 +184,8 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theTxt = "A **few** _words_ from ~~our~~ sponsor"
|
||||
theFmt = " _B b_ I i _S s_ "
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt)
|
||||
assert theDoc.getErrors() == []
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt)
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:p text:style-name=\"Standard\">A <text:span text:style-name=\"T1\">few</text:span> "
|
||||
@@ -201,8 +198,8 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theTxt = "A **few** _wordsXXX"
|
||||
theFmt = " _b b_ I XXX"
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt)
|
||||
assert theDoc.getErrors() == ["Unknown format tag encountered"]
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt)
|
||||
assert theDoc.errData == ["Unknown format tag encountered"]
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:p text:style-name=\"Standard\">"
|
||||
@@ -215,8 +212,8 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theTxt = "Hello\n\tWorld"
|
||||
theFmt = " "
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt)
|
||||
assert theDoc.getErrors() == []
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt)
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:p text:style-name=\"Standard\">Hello<text:line-break /><text:tab />World</text:p>"
|
||||
@@ -230,8 +227,8 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theTxt = "Test text \\**_bold_** and more."
|
||||
theFmt = " I i "
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, theFmt=theFmt)
|
||||
assert theDoc.getErrors() == []
|
||||
theDoc._addTextPar("Standard", oStyle, theTxt, tFmt=theFmt)
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
"<office:text>"
|
||||
"<text:p text:style-name=\"Standard\">Test text **<text:span text:style-name=\"T2\">"
|
||||
@@ -244,8 +241,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_Convert(mockGUI):
|
||||
"""Test the converter of the ToOdt class.
|
||||
"""
|
||||
"""Test the converter of the ToOdt class."""
|
||||
theProject = NWProject(mockGUI)
|
||||
theDoc = ToOdt(theProject, isFlat=True)
|
||||
|
||||
@@ -266,7 +262,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="P1" text:outline-level="1">Title</text:h>'
|
||||
@@ -279,7 +275,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="P2" text:outline-level="2">Chapter</text:h>'
|
||||
@@ -292,7 +288,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
@@ -305,7 +301,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_4" text:outline-level="4">Section</text:h>'
|
||||
@@ -318,7 +314,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Title">Title</text:p>'
|
||||
@@ -331,7 +327,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="P2" text:outline-level="2">Prologue</text:h>'
|
||||
@@ -347,7 +343,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Some '
|
||||
@@ -365,7 +361,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Some text.<text:line-break />Next line</text:p>'
|
||||
@@ -378,7 +374,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body"><text:tab />Item 1<text:tab />Item 2</text:p>'
|
||||
@@ -391,7 +387,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Some <text:span text:style-name="T4">'
|
||||
@@ -410,7 +406,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
@@ -434,7 +430,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
@@ -455,7 +451,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="P3">* * *</text:p>'
|
||||
@@ -473,7 +469,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body" />'
|
||||
@@ -500,7 +496,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
@@ -537,7 +533,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
@@ -559,7 +555,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
theDoc.initDocument()
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
assert theDoc.getErrors() == []
|
||||
assert theDoc.errData == []
|
||||
assert xmlToText(theDoc._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="P2" text:outline-level="2">Chapter One</text:h>'
|
||||
@@ -629,8 +625,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
||||
"""Test the document save functions.
|
||||
"""
|
||||
"""Test the document save functions."""
|
||||
theProject = NWProject(mockGUI)
|
||||
theProject.data.setAuthor("Jane Smith")
|
||||
theProject.data.setName("Test Project")
|
||||
@@ -639,8 +634,11 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
||||
|
||||
theDoc = ToOdt(theProject, isFlat=True)
|
||||
theDoc._isNovel = True
|
||||
assert theDoc.setLanguage(None) is False
|
||||
assert theDoc.setLanguage("nb_NO") is True
|
||||
theDoc._dLanguage = ""
|
||||
theDoc.setLanguage(None)
|
||||
assert theDoc._dLanguage == ""
|
||||
theDoc.setLanguage("nb_NO")
|
||||
assert theDoc._dLanguage == "nb"
|
||||
theDoc.setColourHeaders(True)
|
||||
|
||||
theDoc._text = (
|
||||
@@ -669,8 +667,7 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
||||
"""Test the document save functions.
|
||||
"""
|
||||
"""Test the document save functions."""
|
||||
theProject = NWProject(mockGUI)
|
||||
theProject.data.setAuthor("Jane Smith")
|
||||
theProject.data.setName("Test Project")
|
||||
@@ -747,8 +744,7 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_Format(mockGUI):
|
||||
"""Test the formatters for the ToOdt class.
|
||||
"""
|
||||
"""Test the formatters for the ToOdt class."""
|
||||
theProject = NWProject(mockGUI)
|
||||
theDoc = ToOdt(theProject, isFlat=True)
|
||||
|
||||
@@ -761,7 +757,7 @@ def testCoreToOdt_Format(mockGUI):
|
||||
"_B b_ "
|
||||
)
|
||||
|
||||
assert theDoc._formatKeywords("") == ""
|
||||
assert theDoc._formatKeywords("") == ("", "")
|
||||
assert theDoc._formatKeywords("tag: Jane") == (
|
||||
"**Tag:** Jane",
|
||||
"_B b_ "
|
||||
@@ -776,8 +772,7 @@ def testCoreToOdt_Format(mockGUI):
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_ODTParagraphStyle():
|
||||
"""Test the ODTParagraphStyle class.
|
||||
"""
|
||||
"""Test the ODTParagraphStyle class."""
|
||||
parStyle = ODTParagraphStyle()
|
||||
|
||||
# Set Attributes
|
||||
@@ -992,8 +987,7 @@ def testCoreToOdt_ODTParagraphStyle():
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_ODTTextStyle():
|
||||
"""Test the ODTTextStyle class.
|
||||
"""
|
||||
"""Test the ODTTextStyle class."""
|
||||
txtStyle = ODTTextStyle()
|
||||
|
||||
# Font Weight
|
||||
@@ -1065,8 +1059,7 @@ def testCoreToOdt_ODTTextStyle():
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_XMLParagraph():
|
||||
"""Test XML encoding of paragraph.
|
||||
"""
|
||||
"""Test XML encoding of paragraph."""
|
||||
# Stage 1 : Text
|
||||
# ==============
|
||||
|
||||
@@ -1257,8 +1250,7 @@ def testCoreToOdt_XMLParagraph():
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_MkTag():
|
||||
"""Test the tag maker function.
|
||||
"""
|
||||
"""Test the tag maker function."""
|
||||
assert _mkTag("office", "text") == "{urn:oasis:names:tc:opendocument:xmlns:office:1.0}text"
|
||||
assert _mkTag("style", "text") == "{urn:oasis:names:tc:opendocument:xmlns:style:1.0}text"
|
||||
assert _mkTag("blabla", "text") == "text"
|
||||
|
||||
Reference in New Issue
Block a user