From cbd222fe309ff84a427a38fac081f61afdd31764 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Wed, 27 Jan 2021 02:35:19 +0100 Subject: [PATCH] Add code to save tabs and line breaks to ODT file --- nw/core/toodt.py | 116 +++++++++++++++++++++++++++++++++++++++++------ nw/gui/build.py | 13 ++++-- 2 files changed, 112 insertions(+), 17 deletions(-) diff --git a/nw/core/toodt.py b/nw/core/toodt.py index c89c065d..48c2765e 100644 --- a/nw/core/toodt.py +++ b/nw/core/toodt.py @@ -42,6 +42,9 @@ XML_NS = { "fo" : "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", } +X_BR = "{%s}line-break" % XML_NS["text"] +X_TAB = "{%s}tab" % XML_NS["text"] + class ToOdt(Tokenizer): def __init__(self, theProject, theParent): @@ -119,6 +122,9 @@ class ToOdt(Tokenizer): """ self.theResult = "" + thisPar = [] + parStyle = None + hasHardBreak = False for tType, tLine, tText, tFormat, tStyle in self.theTokens: # Styles @@ -139,27 +145,35 @@ class ToOdt(Tokenizer): # Process Text Type if tType == self.T_EMPTY: - continue + if hasHardBreak and parStyle is not None: + if self.doJustify: + parStyle.setTextAlign("left") + if len(thisPar) > 0: + tTemp = "".join(thisPar) + self._addTextPar("Text_Body", parStyle, tTemp.rstrip()) + thisPar = [] + parStyle = None + hasHardBreak = False elif tType == self.T_TITLE: - tHead = tText.replace(r"\\", "
") - self._addTextPar("Title", oStyle, tHead) + tHead = tText.replace(r"\\", "\n") + self._addTextPar("Title", oStyle, tHead, isHead=True) elif tType == self.T_HEAD1: - tHead = tText.replace(r"\\", "
") - self._addTextPar("Heading_1", oStyle, tHead, oLevel="1") + tHead = tText.replace(r"\\", "\n") + self._addTextPar("Heading_1", oStyle, tHead, isHead=True, oLevel="1") elif tType == self.T_HEAD2: - tHead = tText.replace(r"\\", "
") - self._addTextPar("Heading_2", oStyle, tHead, oLevel="2") + tHead = tText.replace(r"\\", "\n") + self._addTextPar("Heading_2", oStyle, tHead, isHead=True, oLevel="2") elif tType == self.T_HEAD3: - tHead = tText.replace(r"\\", "
") - self._addTextPar("Heading_3", oStyle, tHead, oLevel="3") + tHead = tText.replace(r"\\", "\n") + self._addTextPar("Heading_3", oStyle, tHead, isHead=True, oLevel="3") elif tType == self.T_HEAD4: - tHead = tText.replace(r"\\", "
") - self._addTextPar("Heading_4", oStyle, tHead, oLevel="4") + tHead = tText.replace(r"\\", "\n") + self._addTextPar("Heading_4", oStyle, tHead, isHead=True, oLevel="4") elif tType == self.T_SEP: self._addTextPar("Text_Body", oStyle, tText) @@ -167,6 +181,18 @@ class ToOdt(Tokenizer): elif tType == self.T_SKIP: self._addTextPar("Text_Body", oStyle, "") + elif tType == self.T_TEXT: + tTemp = tText + if parStyle is None: + parStyle = oStyle + # for xPos, xLen, xFmt in reversed(tFormat): + # tTemp = tTemp[:xPos]+htmlTags[xFmt]+tTemp[xPos+xLen:] + if tText.endswith(" "): + thisPar.append(tTemp.rstrip()+"\n") + hasHardBreak = True + else: + thisPar.append(tTemp.rstrip()+" ") + return def closeDocument(self): @@ -192,15 +218,51 @@ class ToOdt(Tokenizer): # Internal Functions ## - def _addTextPar(self, styleName, oStyle, theText, oLevel=None): + def _addTextPar(self, styleName, oStyle, theText, isHead=False, oLevel=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: tAttr[_mkTag("text", "outline-level")] = oLevel - xElem = etree.SubElement(self._xText, _mkTag("text", "p"), attrib=tAttr) - xElem.text = theText + + pTag = "h" if isHead else "p" + xElem = etree.SubElement(self._xText, _mkTag("text", pTag), attrib=tAttr) + + if not theText: + return + + if "\t" not in theText and "\n" not in theText: + xElem.text = theText + return + + # Process tabs and line breaks + tTemp = "" + xTail = None + for c in theText: + if c == "\t": + if xTail is None: + xElem.text = tTemp + else: + xTail.tail = tTemp + tTemp = "" + xTail = etree.SubElement(xElem, X_TAB) + elif c == "\n": + if xTail is None: + xElem.text = tTemp + else: + xTail.tail = tTemp + tTemp = "" + xTail = etree.SubElement(xElem, X_BR) + else: + tTemp += c + + if tTemp != "": + if xTail is None: + xElem.text = tTemp + else: + xTail.tail = tTemp + return def _paraStyle(self, parName, oStyle): @@ -299,6 +361,10 @@ class ToOdt(Tokenizer): oStyle.setMarginTop("0cm") oStyle.setMarginBottom("0.247cm") oStyle.setLineHeight("115%") + if self.doJustify: + oStyle.setTextAlign("justify") + else: + oStyle.setTextAlign("left") oStyle.packXML(self._xStyl, "Text_Body") self._mainPara["Text_Body"] = oStyle @@ -501,6 +567,28 @@ class ODTParagraphStyle(): self._tAttr["font-weight"][1] = str(theValue) return + ## + # Getters + ## + + def getAttr(self, attrName): + """Look through the dictionaries for the value, and return it if + we can find it, If not, return None. + """ + retVal = self._mAttr.get(attrName, None) + if retVal is not None: + return retVal + + retVal = self._pAttr.get(attrName, None) + if retVal is not None: + return retVal + + retVal = self._tAttr.get(attrName, None) + if retVal is not None: + return retVal + + return None + ## # Methods ## diff --git a/nw/gui/build.py b/nw/gui/build.py index af7d71d1..4584d44b 100644 --- a/nw/gui/build.py +++ b/nw/gui/build.py @@ -753,7 +753,7 @@ class GuiBuildNovel(QDialog): elif theFormat == self.FMT_FODT: fileExt = "fodt" textFmt = "Flat Open Document" - outTool = "NW2" + outTool = "NW_ODT" elif theFormat == self.FMT_PDF: fileExt = "pdf" @@ -898,12 +898,19 @@ class GuiBuildNovel(QDialog): except Exception as e: errMsg = str(e) - elif outTool == "NW2": + elif outTool == "NW_ODT": if theFormat == self.FMT_FODT: makeOdt = ToOdt(self.theProject, self.theParent) self._doBuild(makeOdt) - wSuccess = True + try: + with open(savePath, mode="wb") as outFile: + outFile.write(makeOdt.theResult) + + wSuccess = True + + except Exception as e: + errMsg = str(e) elif outTool == "QtPrint" and theFormat == self.FMT_PDF: try: