Skip to content

Commit

Permalink
Add DocX support (#2056)
Browse files Browse the repository at this point in the history
  • Loading branch information
vkbo authored Oct 21, 2024
2 parents 464454e + ec7781f commit ce3f6da
Show file tree
Hide file tree
Showing 29 changed files with 3,369 additions and 150 deletions.
26 changes: 26 additions & 0 deletions novelwriter/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ def checkIntTuple(value: int, valid: tuple | list | set, default: int) -> int:
return default


def firstFloat(*args: Any) -> float:
"""Return the first value that is a float."""
for arg in args:
if isinstance(arg, float):
return arg
return 0.0


##
# Formatting Functions
##
Expand Down Expand Up @@ -515,6 +523,24 @@ def indentChildren(elem: ET.Element, level: int) -> None:
return


def xmlSubElem(
parent: ET.Element,
tag: str,
text: str | int | float | bool | None = None,
attrib: dict | None = None
) -> ET.Element:
"""A custom implementation of SubElement that takes text as an
argument.
"""
xSub = ET.SubElement(parent, tag, attrib=attrib or {})
if text is not None:
if isinstance(text, bool):
xSub.text = str(text).lower()
else:
xSub.text = str(text)
return xSub


##
# File and File System Functions
##
Expand Down
12 changes: 7 additions & 5 deletions novelwriter/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ class nwLabels:
BUILD_FMT = {
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
nwBuildFmt.FODT: QT_TRANSLATE_NOOP("Constant", "Flat Open Document (.fodt)"),
nwBuildFmt.DOCX: QT_TRANSLATE_NOOP("Constant", "Microsoft Word Document (.docx)"),
nwBuildFmt.HTML: QT_TRANSLATE_NOOP("Constant", "novelWriter HTML (.html)"),
nwBuildFmt.NWD: QT_TRANSLATE_NOOP("Constant", "novelWriter Markup (.txt)"),
nwBuildFmt.STD_MD: QT_TRANSLATE_NOOP("Constant", "Standard Markdown (.md)"),
Expand All @@ -278,6 +279,7 @@ class nwLabels:
BUILD_EXT = {
nwBuildFmt.ODT: ".odt",
nwBuildFmt.FODT: ".fodt",
nwBuildFmt.DOCX: ".docx",
nwBuildFmt.HTML: ".html",
nwBuildFmt.NWD: ".txt",
nwBuildFmt.STD_MD: ".md",
Expand Down Expand Up @@ -367,11 +369,11 @@ class nwHeadFmt:
CHAR_POV, CHAR_FOCUS
]

# ODT Document Page Header
ODT_PROJECT = "{Project}"
ODT_AUTHOR = "{Author}"
ODT_PAGE = "{Page}"
ODT_AUTO = "{Project} / {Author} / {Page}"
# Document Page Header
DOC_PROJECT = "{Project}"
DOC_AUTHOR = "{Author}"
DOC_PAGE = "{Page}"
DOC_AUTO = "{Project} / {Author} / {Page}"


class nwQuotes:
Expand Down
30 changes: 18 additions & 12 deletions novelwriter/core/buildsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@
"format.bottomMargin": (float, 2.0),
"format.leftMargin": (float, 2.0),
"format.rightMargin": (float, 2.0),
"odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
"odt.pageCountOffset": (int, 0),
"odt.colorHeadings": (bool, True),
"odt.scaleHeadings": (bool, True),
"odt.boldHeadings": (bool, True),
"doc.pageHeader": (str, nwHeadFmt.DOC_AUTO),
"doc.pageCountOffset": (int, 0),
"doc.colorHeadings": (bool, True),
"doc.scaleHeadings": (bool, True),
"doc.boldHeadings": (bool, True),
"html.addStyles": (bool, True),
"html.preserveTabs": (bool, False),
}
Expand Down Expand Up @@ -165,18 +165,24 @@
"format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
"format.pageMargins": QT_TRANSLATE_NOOP("Builds", "Page Margins"),

"odt": QT_TRANSLATE_NOOP("Builds", "Document Options"),
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
"odt.colorHeadings": QT_TRANSLATE_NOOP("Builds", "Add Colours to Headings"),
"odt.scaleHeadings": QT_TRANSLATE_NOOP("Builds", "Increase Size of Headings"),
"odt.boldHeadings": QT_TRANSLATE_NOOP("Builds", "Bold Headings"),
"doc": QT_TRANSLATE_NOOP("Builds", "Document Style"),
"doc.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
"doc.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
"doc.colorHeadings": QT_TRANSLATE_NOOP("Builds", "Add Colours to Headings"),
"doc.scaleHeadings": QT_TRANSLATE_NOOP("Builds", "Increase Size of Headings"),
"doc.boldHeadings": QT_TRANSLATE_NOOP("Builds", "Bold Headings"),

"html": QT_TRANSLATE_NOOP("Builds", "HTML Options"),
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
}

RENAMED = {
"odt.addColours": "doc.addColours",
"odt.pageHeader": "doc.pageHeader",
"odt.pageCountOffset": "doc.pageCountOffset",
}


class FilterMode(Enum):
"""The decision reason for an item in a filtered project."""
Expand Down Expand Up @@ -490,7 +496,7 @@ def unpack(self, data: dict) -> None:
self._settings = {k: v[1] for k, v in SETTINGS_TEMPLATE.items()}
if isinstance(settings, dict):
for key, value in settings.items():
self.setValue(key, value)
self.setValue(RENAMED.get(key, key), value)

self._changed = False

Expand Down
24 changes: 17 additions & 7 deletions novelwriter/core/docbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from novelwriter.core.project import NWProject
from novelwriter.enum import nwBuildFmt
from novelwriter.error import formatException, logException
from novelwriter.formats.todocx import ToDocX
from novelwriter.formats.tohtml import ToHtml
from novelwriter.formats.tokenizer import Tokenizer
from novelwriter.formats.tomarkdown import ToMarkdown
Expand Down Expand Up @@ -185,6 +186,15 @@ def iterBuildDocument(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[i
if self._build.getBool("format.replaceTabs"):
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")

elif bFormat == nwBuildFmt.DOCX:
makeObj = ToDocX(self._project)
filtered = self._setupBuild(makeObj)
makeObj.initDocument()

yield from self._iterBuild(makeObj, filtered)

makeObj.closeDocument()

elif bFormat == nwBuildFmt.PDF:
makeObj = ToQTextDocument(self._project)
filtered = self._setupBuild(makeObj)
Expand Down Expand Up @@ -282,9 +292,9 @@ def _setupBuild(self, bldObj: Tokenizer) -> dict:
self._build.getBool("format.indentFirstPar"),
)
bldObj.setHeadingStyles(
self._build.getBool("odt.colorHeadings"),
self._build.getBool("odt.scaleHeadings"),
self._build.getBool("odt.boldHeadings"),
self._build.getBool("doc.colorHeadings"),
self._build.getBool("doc.scaleHeadings"),
self._build.getBool("doc.boldHeadings"),
)

bldObj.setTitleMargins(
Expand Down Expand Up @@ -326,14 +336,14 @@ def _setupBuild(self, bldObj: Tokenizer) -> dict:
bldObj.setStyles(self._build.getBool("html.addStyles"))
bldObj.setReplaceUnicode(self._build.getBool("format.stripUnicode"))

if isinstance(bldObj, ToOdt):
if isinstance(bldObj, (ToOdt, ToDocX)):
bldObj.setLanguage(self._project.data.language)
bldObj.setHeaderFormat(
self._build.getStr("odt.pageHeader"),
self._build.getInt("odt.pageCountOffset"),
self._build.getStr("doc.pageHeader"),
self._build.getInt("doc.pageCountOffset"),
)

if isinstance(bldObj, (ToOdt, ToQTextDocument)):
if isinstance(bldObj, (ToOdt, ToDocX, ToQTextDocument)):
scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
bldObj.setPageLayout(
Expand Down
15 changes: 8 additions & 7 deletions novelwriter/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,14 @@ class nwBuildFmt(Enum):

ODT = 0
FODT = 1
HTML = 2
NWD = 3
STD_MD = 4
EXT_MD = 5
PDF = 6
J_HTML = 7
J_NWD = 8
DOCX = 2
HTML = 3
NWD = 4
STD_MD = 5
EXT_MD = 6
PDF = 7
J_HTML = 8
J_NWD = 9


class nwStatusShape(Enum):
Expand Down
Loading

0 comments on commit ce3f6da

Please sign in to comment.