Add settings to DocX and compression to ODT and DocX
This commit is contained in:
@@ -31,12 +31,12 @@ import xml.etree.ElementTree as ET
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from zipfile import ZipFile
|
from zipfile import ZIP_DEFLATED, ZipFile
|
||||||
|
|
||||||
from PyQt5.QtCore import QMarginsF, QSizeF
|
from PyQt5.QtCore import QMarginsF, QSizeF
|
||||||
|
|
||||||
from novelwriter import __version__
|
from novelwriter import __version__
|
||||||
from novelwriter.common import firstFloat, xmlIndent, xmlSubElem
|
from novelwriter.common import firstFloat, xmlSubElem
|
||||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles
|
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles
|
||||||
from novelwriter.core.project import NWProject
|
from novelwriter.core.project import NWProject
|
||||||
from novelwriter.formats.tokenizer import T_Formats, Tokenizer
|
from novelwriter.formats.tokenizer import T_Formats, Tokenizer
|
||||||
@@ -174,7 +174,7 @@ class ToDocX(Tokenizer):
|
|||||||
self._pars: list[DocXParagraph] = []
|
self._pars: list[DocXParagraph] = []
|
||||||
self._files: dict[str, DocXXmlFile] = {}
|
self._files: dict[str, DocXXmlFile] = {}
|
||||||
self._styles: dict[str, DocXParStyle] = {}
|
self._styles: dict[str, DocXParStyle] = {}
|
||||||
self._usedNotes: list[str] = []
|
self._usedNotes: dict[str, int] = {}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ class ToDocX(Tokenizer):
|
|||||||
fId = self._firstHeaderXml()
|
fId = self._firstHeaderXml()
|
||||||
|
|
||||||
self._documentXml(fId, dId)
|
self._documentXml(fId, dId)
|
||||||
|
self._settingsXml()
|
||||||
if self._usedNotes:
|
if self._usedNotes:
|
||||||
self._footnotesXml()
|
self._footnotesXml()
|
||||||
|
|
||||||
@@ -360,10 +360,9 @@ class ToDocX(Tokenizer):
|
|||||||
def xmlToZip(name: str, xObj: ET.Element, zipObj: ZipFile) -> None:
|
def xmlToZip(name: str, xObj: ET.Element, zipObj: ZipFile) -> None:
|
||||||
with zipObj.open(name, mode="w") as fObj:
|
with zipObj.open(name, mode="w") as fObj:
|
||||||
xml = ET.ElementTree(xObj)
|
xml = ET.ElementTree(xObj)
|
||||||
xmlIndent(xml)
|
|
||||||
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
with ZipFile(path, mode="w") as outZip:
|
with ZipFile(path, mode="w", compression=ZIP_DEFLATED, compresslevel=3) as outZip:
|
||||||
xmlToZip("_rels/.rels", rRels, outZip)
|
xmlToZip("_rels/.rels", rRels, outZip)
|
||||||
xmlToZip("word/_rels/document.xml.rels", wRels, outZip)
|
xmlToZip("word/_rels/document.xml.rels", wRels, outZip)
|
||||||
for name, entry in self._files.items():
|
for name, entry in self._files.items():
|
||||||
@@ -522,12 +521,12 @@ class ToDocX(Tokenizer):
|
|||||||
def _generateFootnote(self, key: str) -> ET.Element | None:
|
def _generateFootnote(self, key: str) -> ET.Element | None:
|
||||||
"""Generate a footnote XML object."""
|
"""Generate a footnote XML object."""
|
||||||
if self._footnotes.get(key):
|
if self._footnotes.get(key):
|
||||||
idx = len(self._usedNotes)
|
idx = len(self._usedNotes) + 1
|
||||||
run = ET.Element(_wTag("r"))
|
run = ET.Element(_wTag("r"))
|
||||||
rPr = xmlSubElem(run, _wTag("rPr"))
|
rPr = xmlSubElem(run, _wTag("rPr"))
|
||||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "superscript"})
|
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "superscript"})
|
||||||
xmlSubElem(run, _wTag("footnoteReference"), attrib={_wTag("id"): str(idx)})
|
xmlSubElem(run, _wTag("footnoteReference"), attrib={_wTag("id"): str(idx)})
|
||||||
self._usedNotes.append(key)
|
self._usedNotes[key] = idx
|
||||||
return run
|
return run
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -974,11 +973,36 @@ class ToDocX(Tokenizer):
|
|||||||
contentType=f"{WORD_BASE}.footnotes+xml",
|
contentType=f"{WORD_BASE}.footnotes+xml",
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, key in enumerate(self._usedNotes):
|
for key, idx in self._usedNotes.items():
|
||||||
par = DocXParagraph()
|
par = DocXParagraph()
|
||||||
if content := self._footnotes.get(key):
|
if content := self._footnotes.get(key):
|
||||||
self._processFragments(par, S_FNOTE, content[0], content[1])
|
self._processFragments(par, S_FNOTE, content[0], content[1])
|
||||||
par.toXml(xmlSubElem(xRoot, _wTag("footnote"), attrib={_wTag("id"): str(i)}))
|
par.toXml(xmlSubElem(xRoot, _wTag("footnote"), attrib={_wTag("id"): str(idx)}))
|
||||||
|
|
||||||
|
return rId
|
||||||
|
|
||||||
|
def _settingsXml(self) -> str:
|
||||||
|
"""Populate settings.xml."""
|
||||||
|
rId = self._nextRelId()
|
||||||
|
xRoot = ET.Element(_wTag("settings"))
|
||||||
|
self._files["settings.xml"] = DocXXmlFile(
|
||||||
|
xml=xRoot,
|
||||||
|
rId=rId,
|
||||||
|
path="word",
|
||||||
|
relType=f"{RELS_BASE}/settings",
|
||||||
|
contentType=f"{WORD_BASE}.settings+xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
xFn = xmlSubElem(xRoot, _wTag("footnotePr"))
|
||||||
|
xmlSubElem(xFn, _wTag("numFmt"), attrib={_wTag("val"): "decimal"})
|
||||||
|
|
||||||
|
if self._counts:
|
||||||
|
xVars = xmlSubElem(xRoot, _wTag("docVars"))
|
||||||
|
for key, value in self._counts.items():
|
||||||
|
xmlSubElem(xVars, _wTag("docVar"), attrib={
|
||||||
|
_wTag("name"): f"Manuscript{key[:1].upper()}{key[1:]}",
|
||||||
|
_wTag("val"): str(value),
|
||||||
|
})
|
||||||
|
|
||||||
return rId
|
return rId
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from collections.abc import Sequence
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from zipfile import ZipFile
|
from zipfile import ZIP_DEFLATED, ZipFile
|
||||||
|
|
||||||
from PyQt5.QtGui import QFont
|
from PyQt5.QtGui import QFont
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ class ToOdt(Tokenizer):
|
|||||||
xml = ET.ElementTree(xObj)
|
xml = ET.ElementTree(xObj)
|
||||||
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
xml.write(fObj, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
with ZipFile(path, mode="w") as outZip:
|
with ZipFile(path, mode="w", compression=ZIP_DEFLATED, compresslevel=3) as outZip:
|
||||||
outZip.writestr("mimetype", X_MIME)
|
outZip.writestr("mimetype", X_MIME)
|
||||||
xmlToZip("META-INF/manifest.xml", xMani, outZip)
|
xmlToZip("META-INF/manifest.xml", xMani, outZip)
|
||||||
xmlToZip("settings.xml", xSett, outZip)
|
xmlToZip("settings.xml", xSett, outZip)
|
||||||
|
|||||||
Reference in New Issue
Block a user