Add font table, fix core.xml bug, clean up code, update tests, for DocX
This commit is contained in:
+121
-71
@@ -87,6 +87,17 @@ def _docXCol(color: QColor) -> str:
|
||||
return color.name(QtHexRgb).lstrip("#")
|
||||
|
||||
|
||||
def _wText(parent: ET.Element, text: str) -> ET.Element:
|
||||
"""Create a text element and add the preserve flag if necessary."""
|
||||
attrib = {}
|
||||
if len(text) > len(text.strip()):
|
||||
attrib[_mkTag("xml", "space")] = "preserve"
|
||||
return xmlSubElem(parent, _wTag("t"), text, attrib=attrib)
|
||||
|
||||
|
||||
# Cached
|
||||
W_VAL = _wTag("val")
|
||||
|
||||
# Formatting Codes
|
||||
X_BLD = 0x001 # Bold format
|
||||
X_ITA = 0x002 # Italic format
|
||||
@@ -145,9 +156,9 @@ class DocXParStyle(NamedTuple):
|
||||
nextStyle: str | None = None
|
||||
before: float | None = None
|
||||
after: float | None = None
|
||||
left: float | None = None
|
||||
line: float | None = None
|
||||
indentFirst: float | None = None
|
||||
hanging: float | None = None
|
||||
align: str | None = None
|
||||
default: bool = False
|
||||
level: int | None = None
|
||||
@@ -191,7 +202,7 @@ class ToDocX(Tokenizer):
|
||||
def setLanguage(self, language: str | None) -> None:
|
||||
"""Set language for the document."""
|
||||
if language:
|
||||
self._dLanguage = language
|
||||
self._dLanguage = language.replace("_", "-")
|
||||
return
|
||||
|
||||
def setPageLayout(
|
||||
@@ -296,6 +307,7 @@ class ToDocX(Tokenizer):
|
||||
self._coreXml()
|
||||
self._appXml()
|
||||
self._stylesXml()
|
||||
self._fontTableXml()
|
||||
|
||||
fId = None
|
||||
dId = None
|
||||
@@ -451,32 +463,30 @@ class ToDocX(Tokenizer):
|
||||
if fmt & X_ITA:
|
||||
xmlSubElem(rPr, _wTag("i"))
|
||||
if fmt & X_UND:
|
||||
xmlSubElem(rPr, _wTag("u"), attrib={_wTag("val"): "single"})
|
||||
xmlSubElem(rPr, _wTag("u"), attrib={W_VAL: "single"})
|
||||
if fmt & X_MRK:
|
||||
xmlSubElem(rPr, _wTag("shd"), attrib={
|
||||
_wTag("fill"): _docXCol(self._theme.highlight), _wTag("val"): "clear",
|
||||
_wTag("fill"): _docXCol(self._theme.highlight), W_VAL: "clear",
|
||||
})
|
||||
if fmt & X_DEL:
|
||||
xmlSubElem(rPr, _wTag("strike"))
|
||||
if fmt & X_SUP:
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "superscript"})
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={W_VAL: "superscript"})
|
||||
if fmt & X_SUB:
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "subscript"})
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={W_VAL: "subscript"})
|
||||
if fmt & X_COL and (color := self._classes.get(fClass)):
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): _docXCol(color)})
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={W_VAL: _docXCol(color)})
|
||||
|
||||
for segment in RX_TEXT.split(text):
|
||||
if segment == "\n":
|
||||
xmlSubElem(xR, _wTag("br"))
|
||||
elif segment == "\t":
|
||||
xmlSubElem(xR, _wTag("tab"))
|
||||
elif len(segment) != len(segment.strip()):
|
||||
xmlSubElem(xR, _wTag("t"), segment, attrib={_mkTag("xml", "space"): "preserve"})
|
||||
elif segment:
|
||||
xmlSubElem(xR, _wTag("t"), segment)
|
||||
_wText(xR, segment)
|
||||
|
||||
if fmt & X_HRF and fLink:
|
||||
xmlSubElem(rPr, _wTag("rStyle"), attrib={_wTag("val"): "InternetLink"})
|
||||
xmlSubElem(rPr, _wTag("rStyle"), attrib={W_VAL: "InternetLink"})
|
||||
rId = self._appendExternalRel(fLink)
|
||||
xH = ET.Element(_wTag("hyperlink"), attrib={_mkTag("r", "id"): rId})
|
||||
xH.append(xR)
|
||||
@@ -492,12 +502,12 @@ class ToDocX(Tokenizer):
|
||||
"""Generate a footnote XML object."""
|
||||
if key in self._footnotes:
|
||||
idx = len(self._usedNotes) + 1
|
||||
run = ET.Element(_wTag("r"))
|
||||
rPr = xmlSubElem(run, _wTag("rPr"))
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={_wTag("val"): "superscript"})
|
||||
xmlSubElem(run, _wTag("footnoteReference"), attrib={_wTag("id"): str(idx)})
|
||||
xR = ET.Element(_wTag("r"))
|
||||
rPr = xmlSubElem(xR, _wTag("rPr"))
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={W_VAL: "superscript"})
|
||||
xmlSubElem(xR, _wTag("footnoteReference"), attrib={_wTag("id"): str(idx)})
|
||||
self._usedNotes[key] = idx
|
||||
return run
|
||||
return xR
|
||||
return None
|
||||
|
||||
def _generateStyles(self) -> None:
|
||||
@@ -643,8 +653,8 @@ class ToDocX(Tokenizer):
|
||||
basedOn=S_NORM,
|
||||
before=0.0,
|
||||
after=fnSz * self._marginFoot[1],
|
||||
left=fnSz * self._marginFoot[0],
|
||||
line=fnSz * self._lineHeight,
|
||||
hanging=fnSz * self._marginFoot[0],
|
||||
))
|
||||
|
||||
# Add to Cache
|
||||
@@ -701,7 +711,7 @@ class ToDocX(Tokenizer):
|
||||
def _coreXml(self) -> str:
|
||||
"""Populate app.xml."""
|
||||
rId = self._nextRelId()
|
||||
xRoot = ET.Element("coreProperties")
|
||||
xRoot = ET.Element(_mkTag("cp", "coreProperties"))
|
||||
self._rels["core.xml"] = DocXXmlRel(
|
||||
rId=rId,
|
||||
relType=f"{OOXML_SCM}/package/2006/relationships/metadata/core-properties",
|
||||
@@ -718,7 +728,6 @@ class ToDocX(Tokenizer):
|
||||
xmlSubElem(xRoot, _mkTag("dcterms", "modified"), timeStamp, attrib=tsAttr)
|
||||
xmlSubElem(xRoot, _mkTag("dc", "creator"), self._project.data.author)
|
||||
xmlSubElem(xRoot, _mkTag("dc", "title"), self._project.data.name)
|
||||
xmlSubElem(xRoot, _mkTag("dc", "creator"), self._project.data.author)
|
||||
xmlSubElem(xRoot, _mkTag("dc", "language"), self._dLanguage)
|
||||
xmlSubElem(xRoot, _mkTag("cp", "revision"), str(self._project.data.saveCount))
|
||||
xmlSubElem(xRoot, _mkTag("cp", "lastModifiedBy"), self._project.data.author)
|
||||
@@ -754,9 +763,9 @@ class ToDocX(Tokenizer):
|
||||
_wTag("hAnsi"): self._fontFamily,
|
||||
_wTag("cs"): self._fontFamily,
|
||||
})
|
||||
xmlSubElem(xRPr, _wTag("sz"), attrib={_wTag("val"): size})
|
||||
xmlSubElem(xRPr, _wTag("szCs"), attrib={_wTag("val"): size})
|
||||
xmlSubElem(xRPr, _wTag("lang"), attrib={_wTag("val"): self._dLanguage})
|
||||
xmlSubElem(xRPr, _wTag("sz"), attrib={W_VAL: size})
|
||||
xmlSubElem(xRPr, _wTag("szCs"), attrib={W_VAL: size})
|
||||
xmlSubElem(xRPr, _wTag("lang"), attrib={W_VAL: self._dLanguage})
|
||||
xmlSubElem(xPPr, _wTag("spacing"), attrib={_wTag("line"): line})
|
||||
|
||||
# Paragraph Styles
|
||||
@@ -770,11 +779,11 @@ class ToDocX(Tokenizer):
|
||||
size = firstFloat(style.size, self._fontSize)
|
||||
|
||||
xStyl = xmlSubElem(xRoot, _wTag("style"), attrib=sAttr)
|
||||
xmlSubElem(xStyl, _wTag("name"), attrib={_wTag("val"): style.name})
|
||||
xmlSubElem(xStyl, _wTag("name"), attrib={W_VAL: style.name})
|
||||
if style.basedOn:
|
||||
xmlSubElem(xStyl, _wTag("basedOn"), attrib={_wTag("val"): style.basedOn})
|
||||
xmlSubElem(xStyl, _wTag("basedOn"), attrib={W_VAL: style.basedOn})
|
||||
if style.nextStyle:
|
||||
xmlSubElem(xStyl, _wTag("next"), attrib={_wTag("val"): style.nextStyle})
|
||||
xmlSubElem(xStyl, _wTag("next"), attrib={W_VAL: style.nextStyle})
|
||||
|
||||
# pPr Node
|
||||
pPr = xmlSubElem(xStyl, _wTag("pPr"))
|
||||
@@ -783,34 +792,33 @@ class ToDocX(Tokenizer):
|
||||
_wTag("after"): str(int(20.0 * firstFloat(style.after))),
|
||||
_wTag("line"): str(int(20.0 * firstFloat(style.line, size))),
|
||||
})
|
||||
if style.hanging is not None:
|
||||
if style.left is not None:
|
||||
xmlSubElem(pPr, _wTag("ind"), attrib={
|
||||
_wTag("left"): str(int(20.0 * style.hanging)),
|
||||
_wTag("hanging"): str(int(20.0 * style.hanging)),
|
||||
_wTag("left"): str(int(20.0 * style.left)),
|
||||
})
|
||||
if style.align:
|
||||
xmlSubElem(pPr, _wTag("jc"), attrib={_wTag("val"): style.align})
|
||||
xmlSubElem(pPr, _wTag("jc"), attrib={W_VAL: style.align})
|
||||
if style.level is not None:
|
||||
xmlSubElem(pPr, _wTag("outlineLvl"), attrib={_wTag("val"): str(style.level)})
|
||||
xmlSubElem(pPr, _wTag("outlineLvl"), attrib={W_VAL: str(style.level)})
|
||||
|
||||
# rPr Node
|
||||
rPr = xmlSubElem(xStyl, _wTag("rPr"))
|
||||
if style.bold:
|
||||
xmlSubElem(rPr, _wTag("b"))
|
||||
if style.color:
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): style.color})
|
||||
xmlSubElem(rPr, _wTag("sz"), attrib={_wTag("val"): str(int(2.0 * size))})
|
||||
xmlSubElem(rPr, _wTag("szCs"), attrib={_wTag("val"): str(int(2.0 * size))})
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={W_VAL: style.color})
|
||||
xmlSubElem(rPr, _wTag("sz"), attrib={W_VAL: str(int(2.0 * size))})
|
||||
xmlSubElem(rPr, _wTag("szCs"), attrib={W_VAL: str(int(2.0 * size))})
|
||||
|
||||
# Character Style
|
||||
xStyl = xmlSubElem(xRoot, _wTag("style"), attrib={
|
||||
_wTag("type"): "character",
|
||||
_wTag("styleId"): "InternetLink"
|
||||
})
|
||||
xmlSubElem(xStyl, _wTag("name"), attrib={_wTag("val"): "Hyperlink"})
|
||||
xmlSubElem(xStyl, _wTag("name"), attrib={W_VAL: "Hyperlink"})
|
||||
rPr = xmlSubElem(xStyl, _wTag("rPr"))
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={_wTag("val"): _docXCol(self._theme.link)})
|
||||
xmlSubElem(rPr, _wTag("u"), attrib={_wTag("val"): "single"})
|
||||
xmlSubElem(rPr, _wTag("color"), attrib={W_VAL: _docXCol(self._theme.link)})
|
||||
xmlSubElem(rPr, _wTag("u"), attrib={W_VAL: "single"})
|
||||
|
||||
return rId
|
||||
|
||||
@@ -830,8 +838,8 @@ class ToDocX(Tokenizer):
|
||||
|
||||
xP = xmlSubElem(xRoot, _wTag("p"))
|
||||
xPPr = xmlSubElem(xP, _wTag("pPr"))
|
||||
xmlSubElem(xPPr, _wTag("pStyle"), attrib={_wTag("val"): S_HEAD})
|
||||
xmlSubElem(xPPr, _wTag("jc"), attrib={_wTag("val"): "right"})
|
||||
xmlSubElem(xPPr, _wTag("pStyle"), attrib={W_VAL: S_HEAD})
|
||||
xmlSubElem(xPPr, _wTag("jc"), attrib={W_VAL: "right"})
|
||||
xmlSubElem(xPPr, _wTag("rPr"))
|
||||
|
||||
pre, page, post = self._headerFormat.partition(nwHeadFmt.DOC_PAGE)
|
||||
@@ -840,25 +848,24 @@ class ToDocX(Tokenizer):
|
||||
post = post.replace(nwHeadFmt.DOC_PROJECT, self._project.data.name)
|
||||
post = post.replace(nwHeadFmt.DOC_AUTHOR, self._project.data.author)
|
||||
|
||||
xSpace = _mkTag("xml", "space")
|
||||
wFldCT = _wTag("fldCharType")
|
||||
|
||||
parts: list[tuple[str, str | None, str, str]] = []
|
||||
if pre:
|
||||
parts.append(("t", pre, xSpace, "preserve"))
|
||||
if page:
|
||||
parts.append(("fldChar", None, wFldCT, "begin"))
|
||||
parts.append(("t", " PAGE ", xSpace, "preserve"))
|
||||
parts.append(("fldChar", None, wFldCT, "separate"))
|
||||
parts.append(("t", "2", xSpace, "preserve"))
|
||||
parts.append(("fldChar", None, wFldCT, "end"))
|
||||
if post:
|
||||
parts.append(("t", post, xSpace, "preserve"))
|
||||
|
||||
for part in parts:
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("rPr"))
|
||||
xmlSubElem(xR, _wTag(part[0]), part[1], attrib={part[2]: part[3]})
|
||||
_wText(xR, pre)
|
||||
if page:
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("fldChar"), attrib={wFldCT: "begin"})
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
_wText(xR, " PAGE ")
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("fldChar"), attrib={wFldCT: "separate"})
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
_wText(xR, "0")
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("fldChar"), attrib={wFldCT: "end"})
|
||||
if post:
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
_wText(xR, post)
|
||||
|
||||
return rId
|
||||
|
||||
@@ -878,8 +885,8 @@ class ToDocX(Tokenizer):
|
||||
|
||||
xP = xmlSubElem(xRoot, _wTag("p"))
|
||||
xPPr = xmlSubElem(xP, _wTag("pPr"))
|
||||
xmlSubElem(xPPr, _wTag("pStyle"), attrib={_wTag("val"): S_HEAD})
|
||||
xmlSubElem(xPPr, _wTag("jc"), attrib={_wTag("val"): "right"})
|
||||
xmlSubElem(xPPr, _wTag("pStyle"), attrib={W_VAL: S_HEAD})
|
||||
xmlSubElem(xPPr, _wTag("jc"), attrib={W_VAL: "right"})
|
||||
xmlSubElem(xPPr, _wTag("rPr"))
|
||||
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
@@ -891,6 +898,7 @@ class ToDocX(Tokenizer):
|
||||
"""Populate document.xml."""
|
||||
rId = self._nextRelId()
|
||||
xRoot = ET.Element(_wTag("document"))
|
||||
xRoot.set("xmlns:w14", "http://schemas.microsoft.com/office/word/2010/wordml")
|
||||
xBody = xmlSubElem(xRoot, _wTag("body"))
|
||||
self._rels["document.xml"] = DocXXmlRel(
|
||||
rId=rId,
|
||||
@@ -931,7 +939,7 @@ class ToDocX(Tokenizer):
|
||||
|
||||
xFn = xmlSubElem(xSect, _wTag("footnotePr"))
|
||||
xmlSubElem(xFn, _wTag("numFmt"), attrib={
|
||||
_wTag("val"): "decimal",
|
||||
W_VAL: "decimal",
|
||||
})
|
||||
|
||||
xmlSubElem(xSect, _wTag("pgSz"), attrib={
|
||||
@@ -972,12 +980,36 @@ class ToDocX(Tokenizer):
|
||||
|
||||
for key, idx in self._usedNotes.items():
|
||||
par = DocXParagraph()
|
||||
par.setIsFootnote(True)
|
||||
if content := self._footnotes.get(key):
|
||||
self._processFragments(par, S_FNOTE, content[0], content[1])
|
||||
par.toXml(xmlSubElem(xRoot, _wTag("footnote"), attrib={_wTag("id"): str(idx)}))
|
||||
|
||||
return rId
|
||||
|
||||
def _fontTableXml(self) -> str:
|
||||
"""Populate fontTable.xml."""
|
||||
rId = self._nextRelId()
|
||||
xRoot = ET.Element(_wTag("fonts"))
|
||||
self._rels["fontTable.xml"] = DocXXmlRel(
|
||||
rId=rId,
|
||||
relType=f"{RELS_BASE}/fontTable",
|
||||
)
|
||||
self._files["fontTable.xml"] = DocXXmlFile(
|
||||
xml=xRoot,
|
||||
path="word",
|
||||
contentType=f"{WORD_BASE}.fontTable+xml",
|
||||
)
|
||||
|
||||
xFont = xmlSubElem(xRoot, _wTag("font"), attrib={
|
||||
_wTag("name"): self._textFont.family(),
|
||||
})
|
||||
xmlSubElem(xFont, _wTag("pitch"), attrib={
|
||||
W_VAL: "fixed" if self._textFont.fixedPitch() else "variable",
|
||||
})
|
||||
|
||||
return rId
|
||||
|
||||
def _settingsXml(self) -> str:
|
||||
"""Populate settings.xml."""
|
||||
rId = self._nextRelId()
|
||||
@@ -992,15 +1024,22 @@ class ToDocX(Tokenizer):
|
||||
contentType=f"{WORD_BASE}.settings+xml",
|
||||
)
|
||||
|
||||
xFn = xmlSubElem(xRoot, _wTag("footnotePr"))
|
||||
xmlSubElem(xFn, _wTag("numFmt"), attrib={_wTag("val"): "decimal"})
|
||||
xSet = xmlSubElem(xRoot, _wTag("footnotePr"))
|
||||
xmlSubElem(xSet, _wTag("numFmt"), attrib={W_VAL: "decimal"})
|
||||
|
||||
xSet = xmlSubElem(xRoot, _wTag("compat"))
|
||||
xmlSubElem(xSet, _wTag("compatSetting"), attrib={
|
||||
_wTag("name"): "compatibilityMode",
|
||||
_wTag("uri"): "http://schemas.microsoft.com/office/word",
|
||||
W_VAL: "12",
|
||||
})
|
||||
|
||||
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),
|
||||
W_VAL: str(value),
|
||||
})
|
||||
|
||||
return rId
|
||||
@@ -1011,7 +1050,7 @@ class DocXParagraph:
|
||||
__slots__ = (
|
||||
"_content", "_style", "_textAlign",
|
||||
"_topMargin", "_bottomMargin", "_leftMargin", "_rightMargin",
|
||||
"_indentFirst", "_breakBefore", "_breakAfter",
|
||||
"_indentFirst", "_breakBefore", "_breakAfter", "_footnoteRef",
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -1025,6 +1064,7 @@ class DocXParagraph:
|
||||
self._indentFirst = False
|
||||
self._breakBefore = False
|
||||
self._breakAfter = False
|
||||
self._footnoteRef = False
|
||||
return
|
||||
|
||||
##
|
||||
@@ -1086,6 +1126,11 @@ class DocXParagraph:
|
||||
self._breakAfter = state
|
||||
return
|
||||
|
||||
def setIsFootnote(self, state: bool) -> None:
|
||||
"""Set is footnote flag."""
|
||||
self._footnoteRef = state
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -1098,7 +1143,7 @@ class DocXParagraph:
|
||||
def toXml(self, body: ET.Element) -> None:
|
||||
"""Called after all content is set."""
|
||||
if style := self._style:
|
||||
par = xmlSubElem(body, _wTag("p"))
|
||||
xP = xmlSubElem(body, _wTag("p"))
|
||||
|
||||
# Values
|
||||
indent = {}
|
||||
@@ -1110,8 +1155,8 @@ class DocXParagraph:
|
||||
indent[_wTag("right")] = str(int(20.0 * self._rightMargin))
|
||||
|
||||
# Paragraph
|
||||
pPr = xmlSubElem(par, _wTag("pPr"))
|
||||
xmlSubElem(pPr, _wTag("pStyle"), attrib={_wTag("val"): style.styleId})
|
||||
pPr = xmlSubElem(xP, _wTag("pPr"))
|
||||
xmlSubElem(pPr, _wTag("pStyle"), attrib={W_VAL: style.styleId})
|
||||
if self._topMargin is not None or self._bottomMargin is not None:
|
||||
xmlSubElem(pPr, _wTag("spacing"), attrib={
|
||||
_wTag("before"): str(int(20.0 * firstFloat(self._topMargin, style.before))),
|
||||
@@ -1121,16 +1166,21 @@ class DocXParagraph:
|
||||
if indent:
|
||||
xmlSubElem(pPr, _wTag("ind"), attrib=indent)
|
||||
if self._textAlign:
|
||||
xmlSubElem(pPr, _wTag("jc"), attrib={_wTag("val"): self._textAlign})
|
||||
xmlSubElem(pPr, _wTag("jc"), attrib={W_VAL: self._textAlign})
|
||||
|
||||
# Text
|
||||
if self._footnoteRef:
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
rPr = xmlSubElem(xR, _wTag("rPr"))
|
||||
xmlSubElem(rPr, _wTag("vertAlign"), attrib={W_VAL: "superscript"})
|
||||
xmlSubElem(xR, _wTag("footnoteRef"))
|
||||
if self._breakBefore:
|
||||
wr = xmlSubElem(par, _wTag("r"))
|
||||
xmlSubElem(wr, _wTag("br"), attrib={_wTag("type"): "page"})
|
||||
for run in self._content:
|
||||
par.append(run)
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("br"), attrib={_wTag("type"): "page"})
|
||||
for xR in self._content:
|
||||
xP.append(xR)
|
||||
if self._breakAfter:
|
||||
wr = xmlSubElem(par, _wTag("r"))
|
||||
xmlSubElem(wr, _wTag("br"), attrib={_wTag("type"): "page"})
|
||||
xR = xmlSubElem(xP, _wTag("r"))
|
||||
xmlSubElem(xR, _wTag("br"), attrib={_wTag("type"): "page"})
|
||||
|
||||
return
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
%%~name: Making a Scene
|
||||
%%~path: 6a2d6d5f4f401/636b6aa9b697b
|
||||
%%~kind: NOVEL/DOCUMENT
|
||||
%%~hash: 89d562ae05727028d74bd10cfd6953882d1cd140
|
||||
%%~date: Unknown/2024-10-25 12:41:02
|
||||
%%~hash: 8d245fa740926779d19741ff7f75ef387b55130c
|
||||
%%~date: Unknown/2024-10-25 23:54:52
|
||||
### Making a Scene
|
||||
|
||||
@pov: Jane
|
||||
@char: John, Jane
|
||||
@location: Earth
|
||||
@mention: Bob, Space
|
||||
@mention: Space
|
||||
|
||||
A scene is defined by a level three heading, like the one at the top of this page. The scene will be assigned to the chapter preceding it in the project tree. The scene document can be sorted after the chapter document, or as a child of the chapter. Both result in the same output in the end, so it is a matter of preference.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-25 23:19:07">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2122" autoCount="279" editTime="94855">
|
||||
<novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-26 16:59:09">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2132" autoCount="279" editTime="95062">
|
||||
<name>Sample Project</name>
|
||||
<author>Jane Smith</author>
|
||||
</project>
|
||||
@@ -58,7 +58,7 @@
|
||||
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
|
||||
</item>
|
||||
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="1663" />
|
||||
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="357" />
|
||||
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<ns0:Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
|
||||
<ns0:Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />
|
||||
<ns0:Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" />
|
||||
<ns0:Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" />
|
||||
<ns0:Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" />
|
||||
<ns0:Override PartName="/word/header2.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" />
|
||||
<ns0:Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" />
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<dcterms:created xsi:type="dcterms:W3CDTF">2024-10-25T19:23:34</dcterms:created>
|
||||
<dcterms:modified xsi:type="dcterms:W3CDTF">2024-10-25T19:23:34</dcterms:modified>
|
||||
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<dcterms:created xsi:type="dcterms:W3CDTF">2024-10-26T17:01:14</dcterms:created>
|
||||
<dcterms:modified xsi:type="dcterms:W3CDTF">2024-10-26T17:01:14</dcterms:modified>
|
||||
<dc:creator>lipsum.com</dc:creator>
|
||||
<dc:title>Lorem Ipsum</dc:title>
|
||||
<dc:creator>lipsum.com</dc:creator>
|
||||
<dc:language>en_GB</dc:language>
|
||||
<dc:language>en-GB</dc:language>
|
||||
<cp:revision>48</cp:revision>
|
||||
<cp:lastModifiedBy>lipsum.com</cp:lastModifiedBy>
|
||||
</coreProperties>
|
||||
</cp:coreProperties>
|
||||
|
||||
@@ -1398,8 +1398,8 @@
|
||||
</w:r>
|
||||
</w:p>
|
||||
<w:sectPr>
|
||||
<w:headerReference w:type="first" r:id="rId6" />
|
||||
<w:headerReference w:type="default" r:id="rId5" />
|
||||
<w:headerReference w:type="first" r:id="rId7" />
|
||||
<w:headerReference w:type="default" r:id="rId6" />
|
||||
<w:footnotePr>
|
||||
<w:numFmt w:val="decimal" />
|
||||
</w:footnotePr>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
<ns0:Relationships xmlns:ns0="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<ns0:Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="http://lipsum.com" TargetMode="External" />
|
||||
<ns0:Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml" />
|
||||
<ns0:Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml" />
|
||||
<ns0:Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header2.xml" />
|
||||
<ns0:Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml" />
|
||||
<ns0:Relationship Id="rId9" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml" />
|
||||
<ns0:Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml" />
|
||||
<ns0:Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml" />
|
||||
<ns0:Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header2.xml" />
|
||||
<ns0:Relationship Id="rId9" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml" />
|
||||
<ns0:Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml" />
|
||||
</ns0:Relationships>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
||||
<w:font w:name="Source Sans Pro">
|
||||
<w:pitch w:val="variable" />
|
||||
</w:font>
|
||||
</w:fonts>
|
||||
@@ -5,6 +5,12 @@
|
||||
<w:pPr>
|
||||
<w:pStyle w:val="FootnoteText" />
|
||||
</w:pPr>
|
||||
<w:r>
|
||||
<w:rPr>
|
||||
<w:vertAlign w:val="superscript" />
|
||||
</w:rPr>
|
||||
<w:footnoteRef />
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr>
|
||||
<w:i />
|
||||
|
||||
@@ -7,31 +7,24 @@
|
||||
<w:rPr />
|
||||
</w:pPr>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:t xml:space="preserve">Page </w:t>
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:fldChar w:fldCharType="begin" />
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:t xml:space="preserve"> PAGE </w:t>
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:fldChar w:fldCharType="separate" />
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:t xml:space="preserve">2</w:t>
|
||||
<w:t>0</w:t>
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:fldChar w:fldCharType="end" />
|
||||
</w:r>
|
||||
<w:r>
|
||||
<w:rPr />
|
||||
<w:t xml:space="preserve"> - Lorem Ipsum (lipsum.com)</w:t>
|
||||
</w:r>
|
||||
</w:p>
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
<ns0:Relationships xmlns:ns0="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<ns0:Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml" />
|
||||
<ns0:Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml" />
|
||||
<ns0:Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml" />
|
||||
<ns0:Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml" />
|
||||
</ns0:Relationships>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<w:footnotePr>
|
||||
<w:numFmt w:val="decimal" />
|
||||
</w:footnotePr>
|
||||
<w:compat>
|
||||
<w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="12" />
|
||||
</w:compat>
|
||||
<w:docVars>
|
||||
<w:docVar w:name="ManuscriptTitleCount" w:val="11" />
|
||||
<w:docVar w:name="ManuscriptParagraphCount" w:val="43" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<w:rFonts w:ascii="Source Sans Pro" w:hAnsi="Source Sans Pro" w:cs="Source Sans Pro" />
|
||||
<w:sz w:val="24" />
|
||||
<w:szCs w:val="24" />
|
||||
<w:lang w:val="en_GB" />
|
||||
<w:lang w:val="en-GB" />
|
||||
</w:rPr>
|
||||
</w:rPrDefault>
|
||||
<w:pPrDefault>
|
||||
@@ -142,7 +142,7 @@
|
||||
<w:basedOn w:val="Normal" />
|
||||
<w:pPr>
|
||||
<w:spacing w:before="0" w:after="90" w:line="220" />
|
||||
<w:ind w:left="272" w:hanging="272" />
|
||||
<w:ind w:left="272" />
|
||||
</w:pPr>
|
||||
<w:rPr>
|
||||
<w:sz w:val="19" />
|
||||
|
||||
@@ -556,10 +556,13 @@ def testFmtToDocX_Footnotes(mockGUI):
|
||||
assert xmlToText(doc._files["footnotes.xml"].xml) == (
|
||||
'<w:footnotes>'
|
||||
'<w:footnote w:id="1"><w:p><w:pPr><w:pStyle w:val="FootnoteText" /></w:pPr>'
|
||||
'<w:r><w:rPr><w:vertAlign w:val="superscript" /></w:rPr><w:footnoteRef /></w:r>'
|
||||
'<w:r><w:rPr /><w:t>Footnote text A.</w:t></w:r></w:p></w:footnote>'
|
||||
'<w:footnote w:id="2"><w:p><w:pPr><w:pStyle w:val="FootnoteText" /></w:pPr>'
|
||||
'<w:r><w:rPr><w:vertAlign w:val="superscript" /></w:rPr><w:footnoteRef /></w:r>'
|
||||
'<w:r><w:rPr /><w:t>Another footnote.</w:t></w:r></w:p></w:footnote>'
|
||||
'<w:footnote w:id="3"><w:p><w:pPr><w:pStyle w:val="FootnoteText" /></w:pPr>'
|
||||
'<w:r><w:rPr><w:vertAlign w:val="superscript" /></w:rPr><w:footnoteRef /></w:r>'
|
||||
'<w:r><w:rPr /><w:t>Again?</w:t></w:r></w:p></w:footnote>'
|
||||
'</w:footnotes>'
|
||||
)
|
||||
@@ -619,6 +622,7 @@ def testFmtToDocX_SaveDocument(mockGUI, prjLipsum, fncPath, tstPaths):
|
||||
fncPath / "extract" / "word" / "header2.xml",
|
||||
fncPath / "extract" / "word" / "settings.xml",
|
||||
fncPath / "extract" / "word" / "styles.xml",
|
||||
fncPath / "extract" / "word" / "fontTable.xml",
|
||||
]
|
||||
|
||||
outDir = tstPaths.outDir / "fmtToDocX_SaveDocument"
|
||||
|
||||
Reference in New Issue
Block a user