Merge branch 'main' into feature/preview_generator

This commit is contained in:
Veronica Berglyd Olsen
2024-05-21 23:16:27 +02:00
9 changed files with 239 additions and 369 deletions
+8 -24
View File
@@ -171,9 +171,7 @@ class ToHtml(Tokenizer):
h3 = "h3"
h4 = "h4"
para = []
lines = []
pStyle = None
tHandle = self._handle
for tType, nHead, tText, tFormat, tStyle in self._tokens:
@@ -240,37 +238,27 @@ class ToHtml(Tokenizer):
aNm = ""
# Process Text Type
if tType == self.T_EMPTY:
if pStyle is None:
pStyle = ""
if len(para) > 1 and self._cssStyles:
pClass = " class='break'"
else:
pClass = ""
if len(para) > 0:
tTemp = "<br/>".join(para)
lines.append(f"<p{pClass+pStyle}>{tTemp.rstrip()}</p>\n")
para = []
pStyle = None
if tType == self.T_TEXT:
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat, hTags)}</p>\n")
elif tType == self.T_TITLE:
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
elif tType == self.T_HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
elif tType == self.T_HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
elif tType == self.T_HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
elif tType == self.T_HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
tHead = tText.replace(nwHeadFmt.BR, "<br>")
lines.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
elif tType == self.T_SEP:
@@ -279,11 +267,6 @@ class ToHtml(Tokenizer):
elif tType == self.T_SKIP:
lines.append(f"<p class='skip'{hStyle}>&nbsp;</p>\n")
elif tType == self.T_TEXT:
if pStyle is None:
pStyle = hStyle
para.append(self._formatText(tText, tFormat, hTags).rstrip())
elif tType == self.T_SYNOPSIS and self._doSynopsis:
lines.append(self._formatSynopsis(self._formatText(tText, tFormat, hTags), True))
@@ -491,6 +474,7 @@ class ToHtml(Tokenizer):
else:
html = tags.get(fmt, "ERR")
temp = f"{temp[:pos]}{html}{temp[pos:]}"
temp = temp.replace("\n", "<br>")
return stripEscape(temp)
def _formatSynopsis(self, text: str, synopsis: bool) -> str:
+86 -52
View File
@@ -50,6 +50,7 @@ RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.D
T_Formats = list[tuple[int, int, str]]
T_Comment = tuple[str, T_Formats]
T_Token = tuple[int, int, str, T_Formats, int]
def stripEscape(text: str) -> str:
@@ -129,7 +130,7 @@ class Tokenizer(ABC):
self._keepMD = False # Whether to keep the markdown text
# Tokens and Meta Data (Per Document)
self._tokens: list[tuple[int, int, str, T_Formats, int]] = []
self._tokens: list[T_Token] = []
self._footnotes: dict[str, T_Comment] = {}
# Tokens and Meta Data (Per Instance)
@@ -410,6 +411,11 @@ class Tokenizer(ABC):
self._skipKeywords = set(x.lower().strip() for x in keywords.split(","))
return
def setKeepLineBreaks(self, state: bool) -> None:
"""Keep line breaks in paragraphs."""
self._keepBreaks = state
return
def setKeepMarkdown(self, state: bool) -> None:
"""Keep original markdown during build."""
self._keepMD = state
@@ -491,7 +497,6 @@ class Tokenizer(ABC):
4: The internal formatting map of the text, self.FMT_*
5: The style of the block, self.A_*
"""
self._tokens = []
if self._isNovel:
self._hFormatter.setHandle(self._handle)
@@ -499,12 +504,13 @@ class Tokenizer(ABC):
breakNext = False
tmpMarkdown = []
tHandle = self._handle or ""
tokens: list[T_Token] = []
for aLine in self._text.splitlines():
sLine = aLine.strip().lower()
# Check for blank lines
if len(sLine) == 0:
self._tokens.append((
tokens.append((
self.T_EMPTY, nHead, "", [], self.A_NONE
))
if self._keepMD:
@@ -533,7 +539,7 @@ class Tokenizer(ABC):
continue
elif sLine == "[vspace]":
self._tokens.append(
tokens.append(
(self.T_SKIP, nHead, "", [], sAlign)
)
continue
@@ -541,11 +547,11 @@ class Tokenizer(ABC):
elif sLine.startswith("[vspace:") and sLine.endswith("]"):
nSkip = checkInt(sLine[8:-1], 0)
if nSkip >= 1:
self._tokens.append(
tokens.append(
(self.T_SKIP, nHead, "", [], sAlign)
)
if nSkip > 1:
self._tokens += (nSkip - 1) * [
tokens += (nSkip - 1) * [
(self.T_SKIP, nHead, "", [], self.A_NONE)
]
continue
@@ -562,14 +568,14 @@ class Tokenizer(ABC):
cStyle, cKey, cText, _, _ = processComment(aLine)
if cStyle == nwComment.SYNOPSIS:
tLine, tFmt = self._extractFormats(cText)
self._tokens.append((
tokens.append((
self.T_SYNOPSIS, nHead, tLine, tFmt, sAlign
))
if self._doSynopsis and self._keepMD:
tmpMarkdown.append(f"{aLine}\n")
elif cStyle == nwComment.SHORT:
tLine, tFmt = self._extractFormats(cText)
self._tokens.append((
tokens.append((
self.T_SHORT, nHead, tLine, tFmt, sAlign
))
if self._doSynopsis and self._keepMD:
@@ -581,7 +587,7 @@ class Tokenizer(ABC):
tmpMarkdown.append(f"{aLine}\n")
else:
tLine, tFmt = self._extractFormats(cText)
self._tokens.append((
tokens.append((
self.T_COMMENT, nHead, tLine, tFmt, sAlign
))
if self._doComments and self._keepMD:
@@ -595,7 +601,7 @@ class Tokenizer(ABC):
valid, bits, _ = self._project.index.scanThis(aLine)
if valid and bits and bits[0] not in self._skipKeywords:
self._tokens.append((
tokens.append((
self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign
))
if self._doKeywords and self._keepMD:
@@ -631,7 +637,7 @@ class Tokenizer(ABC):
self._hFormatter.resetAll()
self._noSep = True
self._tokens.append((
tokens.append((
tType, nHead, tText, [], tStyle
))
if self._keepMD:
@@ -666,7 +672,7 @@ class Tokenizer(ABC):
self._hFormatter.resetScene()
self._noSep = True
self._tokens.append((
tokens.append((
tType, nHead, tText, [], tStyle
))
if self._keepMD:
@@ -707,7 +713,7 @@ class Tokenizer(ABC):
tStyle = self.A_NONE if self._noSep else self.A_CENTRE
self._noSep = False
self._tokens.append((
tokens.append((
tType, nHead, tText, [], tStyle
))
if self._keepMD:
@@ -737,7 +743,7 @@ class Tokenizer(ABC):
tType = self.T_SEP
tStyle = self.A_CENTRE
self._tokens.append((
tokens.append((
tType, nHead, tText, [], tStyle
))
if self._keepMD:
@@ -785,26 +791,26 @@ class Tokenizer(ABC):
# Process formats
tLine, tFmt = self._extractFormats(aLine)
self._tokens.append((
tokens.append((
self.T_TEXT, nHead, tLine, tFmt, sAlign
))
if self._keepMD:
tmpMarkdown.append(f"{aLine}\n")
# If we have content, turn off the first page flag
if self._isFirst and self._tokens:
if self._isFirst and tokens:
self._isFirst = False # First document has been processed
# Make sure the token array doesn't start with a page break
# on the very first page, adding a blank first page.
if self._tokens[0][4] & self.A_PBB:
token = self._tokens[0]
self._tokens[0] = (
token[0], token[1], token[2], token[3], token[4] & ~self.A_PBB
if tokens[0][4] & self.A_PBB:
cToken = tokens[0]
tokens[0] = (
cToken[0], cToken[1], cToken[2], cToken[3], cToken[4] & ~self.A_PBB
)
# Always add an empty line at the end of the file
self._tokens.append((
tokens.append((
self.T_EMPTY, nHead, "", [], self.A_NONE
))
if self._keepMD:
@@ -813,27 +819,62 @@ class Tokenizer(ABC):
# Second Pass
# ===========
# Some items need a second pass
# This second pass strips away consecutive blank lines, and
# combines consecutive text lines into the same paragraph.
# It also ensures that there isn't paragraph spacing between
# meta data lines for formats that has spacing.
pToken = (self.T_EMPTY, 0, "", [], self.A_NONE)
nToken = (self.T_EMPTY, 0, "", [], self.A_NONE)
tCount = len(self._tokens)
for n, token in enumerate(self._tokens):
self._tokens = []
pToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
nToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
lineSep = "\n" if self._keepBreaks else " "
pLines: list[T_Token] = []
tCount = len(tokens)
for n, cToken in enumerate(tokens):
if n > 0:
pToken = self._tokens[n-1]
pToken = tokens[n-1] # Look behind
if n < tCount - 1:
nToken = self._tokens[n+1]
nToken = tokens[n+1] # Look ahead
if token[0] == self.T_KEYWORD:
aStyle = token[4]
if cToken[0] == self.T_EMPTY:
# We don't need to keep the empty lines after this pass
pass
elif cToken[0] == self.T_KEYWORD:
# Adjust margins for lines in a list of keyword lines
aStyle = cToken[4]
if pToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_TOPMRG
if nToken[0] == self.T_KEYWORD:
aStyle |= self.A_Z_BTMMRG
self._tokens[n] = (
token[0], token[1], token[2], token[3], aStyle
)
self._tokens.append((
cToken[0], cToken[1], cToken[2], cToken[3], aStyle
))
elif cToken[0] == self.T_TEXT:
# Combine lines from the same paragraph
pLines.append(cToken)
if nToken[0] != self.T_TEXT:
nLines = len(pLines)
if nLines == 1:
self._tokens.append(pLines[0])
elif nLines > 1:
tTxt = ""
tFmt: T_Formats = []
for aToken in pLines:
tLen = len(tTxt)
tTxt += f"{aToken[2]}{lineSep}"
tFmt.extend((p+tLen, fmt, key) for p, fmt, key in aToken[3])
self._tokens.append((
self.T_TEXT, pLines[0][1], tTxt[:-1], tFmt, pLines[0][4]
))
pLines = []
else:
self._tokens.append(cToken)
return
@@ -876,7 +917,6 @@ class Tokenizer(ABC):
textWordChars = self._counts.get("textWordChars", 0)
titleWordChars = self._counts.get("titleWordChars", 0)
para = []
for tType, _, tText, _, _ in self._tokens:
tText = tText.replace(nwUnicode.U_ENDASH, " ")
tText = tText.replace(nwUnicode.U_EMDASH, " ")
@@ -886,22 +926,19 @@ class Tokenizer(ABC):
nChars = len(tText)
nWChars = len("".join(tWords))
if tType == self.T_EMPTY:
if len(para) > 0:
tTemp = "\n".join(para)
tPWords = tTemp.split()
nPWords = len(tPWords)
nPChars = len(tTemp)
nPWChars = len("".join(tPWords))
if tType == self.T_TEXT:
tPWords = tText.split()
nPWords = len(tPWords)
nPChars = len(tText)
nPWChars = len("".join(tPWords))
paragraphCount += 1
allWords += nPWords
textWords += nPWords
allChars += nPChars
textChars += nPChars
allWordChars += nPWChars
textWordChars += nPWChars
para = []
paragraphCount += 1
allWords += nPWords
textWords += nPWords
allChars += nPChars
textChars += nPChars
allWordChars += nPWChars
textWordChars += nPWChars
elif tType in self.L_HEADINGS:
titleCount += 1
@@ -917,9 +954,6 @@ class Tokenizer(ABC):
allChars += nChars
allWordChars += nWChars
elif tType == self.T_TEXT:
para.append(tText.rstrip())
elif tType == self.T_SYNOPSIS and self._doSynopsis:
text = "{0}: {1}".format(self._localLookup("Synopsis"), tText)
words = text.split()
+3 -11
View File
@@ -139,17 +139,12 @@ class ToMarkdown(Tokenizer):
mTags = EXT_MD
cSkip = nwUnicode.U_MMSP
para = []
lines = []
lineSep = " \n" if self._preserveBreaks else " "
for tType, _, tText, tFormat, tStyle in self._tokens:
if tType == self.T_EMPTY:
if para:
tTemp = (lineSep.join(para)).rstrip(" ")
lines.append(f"{tTemp}\n\n")
para = []
if tType == self.T_TEXT:
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
lines.append(f"{tTemp}\n\n")
elif tType == self.T_TITLE:
tHead = tText.replace(nwHeadFmt.BR, "\n")
@@ -177,9 +172,6 @@ class ToMarkdown(Tokenizer):
elif tType == self.T_SKIP:
lines.append(f"{cSkip}\n\n")
elif tType == self.T_TEXT:
para.append(self._formatText(tText, tFormat, mTags).rstrip())
elif tType == self.T_SYNOPSIS and self._doSynopsis:
label = self._localLookup("Synopsis")
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
+49 -64
View File
@@ -96,6 +96,18 @@ M_MRK = ~X_MRK
M_SUP = ~X_SUP
M_SUB = ~X_SUB
# ODT Styles
S_TITLE = "Title"
S_HEAD1 = "Heading_20_1"
S_HEAD2 = "Heading_20_2"
S_HEAD3 = "Heading_20_3"
S_HEAD4 = "Heading_20_4"
S_SEP = "Separator"
S_FIND = "First_20_line_20_indent"
S_TEXT = "Text_20_body"
S_META = "Text_20_Meta"
S_HNF = "Header_20_and_20_Footer"
class ToOdt(Tokenizer):
"""Core: Open Document Writer
@@ -406,11 +418,8 @@ class ToOdt(Tokenizer):
"""Convert the list of text tokens into XML elements."""
self._result = "" # Not used, but cleared just in case
pFmt: list[T_Formats] = []
pText = []
pStyle = None
pIndent = True
xText = self._xText
pIndent = True
for tType, _, tText, tFormat, tStyle in self._tokens:
# Styles
@@ -445,79 +454,55 @@ class ToOdt(Tokenizer):
pIndent = False
# Process Text Types
if tType == self.T_EMPTY:
if len(pText) > 1 and pStyle is not None:
if self._doJustify:
pStyle.setTextAlign("left")
if len(pText) > 0 and pStyle is not None:
tTxt = ""
tFmt: T_Formats = []
for nText, nFmt in zip(pText, pFmt):
tLen = len(tTxt)
tTxt += f"{nText}\n"
tFmt.extend((p+tLen, fmt, key) for p, fmt, key in nFmt)
# Don't indent a paragraph if it has alignment set
tIndent = self._firstIndent and pIndent and pStyle.isUnaligned()
self._addTextPar(
xText, "First_20_line_20_indent" if tIndent else "Text_20_body",
pStyle, tTxt.rstrip(), tFmt=tFmt
)
pIndent = True
pFmt = []
pText = []
pStyle = None
if tType == self.T_TEXT:
if self._firstIndent and pIndent and oStyle.isUnaligned():
self._addTextPar(xText, S_FIND, oStyle, tText, tFmt=tFormat)
else:
self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
pIndent = True
elif tType == self.T_TITLE:
# Title must be text:p
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, "Title", oStyle, tHead, isHead=False)
self._addTextPar(xText, S_TITLE, oStyle, tHead, isHead=False)
elif tType == self.T_HEAD1:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, "Heading_20_1", oStyle, tHead, isHead=True, oLevel="1")
self._addTextPar(xText, S_HEAD1, oStyle, tHead, isHead=True, oLevel="1")
elif tType == self.T_HEAD2:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, "Heading_20_2", oStyle, tHead, isHead=True, oLevel="2")
self._addTextPar(xText, S_HEAD2, oStyle, tHead, isHead=True, oLevel="2")
elif tType == self.T_HEAD3:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, "Heading_20_3", oStyle, tHead, isHead=True, oLevel="3")
self._addTextPar(xText, S_HEAD3, oStyle, tHead, isHead=True, oLevel="3")
elif tType == self.T_HEAD4:
tHead = tText.replace(nwHeadFmt.BR, "\n")
self._addTextPar(xText, "Heading_20_4", oStyle, tHead, isHead=True, oLevel="4")
self._addTextPar(xText, S_HEAD4, oStyle, tHead, isHead=True, oLevel="4")
elif tType == self.T_SEP:
self._addTextPar(xText, "Separator", oStyle, tText)
self._addTextPar(xText, S_SEP, oStyle, tText)
elif tType == self.T_SKIP:
self._addTextPar(xText, "Separator", oStyle, "")
elif tType == self.T_TEXT:
if pStyle is None:
pStyle = oStyle
pText.append(tText)
pFmt.append(tFormat)
self._addTextPar(xText, S_SEP, oStyle, "")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
tTemp, tFmt = self._formatSynopsis(tText, tFormat, True)
self._addTextPar(xText, "Text_20_Meta", oStyle, tTemp, tFmt=tFmt)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
elif tType == self.T_SHORT and self._doSynopsis:
tTemp, tFmt = self._formatSynopsis(tText, tFormat, False)
self._addTextPar(xText, "Text_20_Meta", oStyle, tTemp, tFmt=tFmt)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
elif tType == self.T_COMMENT and self._doComments:
tTemp, tFmt = self._formatComments(tText, tFormat)
self._addTextPar(xText, "Text_20_Meta", oStyle, tTemp, tFmt=tFmt)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
elif tType == self.T_KEYWORD and self._doKeywords:
tTemp, tFmt = self._formatKeywords(tText)
self._addTextPar(xText, "Text_20_Meta", oStyle, tTemp, tFmt=tFmt)
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
return
@@ -847,7 +832,7 @@ class ToOdt(Tokenizer):
_mkTag("style", "name"): "Heading",
_mkTag("style", "family"): "paragraph",
_mkTag("style", "parent-style-name"): "Standard",
_mkTag("style", "next-style-name"): "Text_20_body",
_mkTag("style", "next-style-name"): S_TEXT,
_mkTag("style", "class"): "text",
})
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib={
@@ -863,7 +848,7 @@ class ToOdt(Tokenizer):
# Add Header and Footer Styles
ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib={
_mkTag("style", "name"): "Header_20_and_20_Footer",
_mkTag("style", "name"): S_HNF,
_mkTag("style", "display-name"): "Header and Footer",
_mkTag("style", "family"): "paragraph",
_mkTag("style", "parent-style-name"): "Standard",
@@ -875,7 +860,7 @@ class ToOdt(Tokenizer):
def _useableStyles(self) -> None:
"""Set the usable styles."""
# Add Text Body Style
style = ODTParagraphStyle("Text_20_body")
style = ODTParagraphStyle(S_TEXT)
style.setDisplayName("Text body")
style.setParentStyleName("Standard")
style.setClass("text")
@@ -890,16 +875,16 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add First Line Indent Style
style = ODTParagraphStyle("First_20_line_20_indent")
style = ODTParagraphStyle(S_FIND)
style.setDisplayName("First line indent")
style.setParentStyleName("Text_20_body")
style.setParentStyleName(S_TEXT)
style.setClass("text")
style.setTextIndent(self._fTextIndent)
style.packXML(self._xStyl)
self._mainPara[style.name] = style
# Add Text Meta Style
style = ODTParagraphStyle("Text_20_Meta")
style = ODTParagraphStyle(S_META)
style.setDisplayName("Text Meta")
style.setParentStyleName("Standard")
style.setClass("text")
@@ -915,10 +900,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Title Style
style = ODTParagraphStyle("Title")
style = ODTParagraphStyle(S_TITLE)
style.setDisplayName("Title")
style.setParentStyleName("Heading")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setClass("chapter")
style.setMarginTop(self._mTopTitle)
style.setMarginBottom(self._mBotTitle)
@@ -931,10 +916,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Separator Style
style = ODTParagraphStyle("Separator")
style = ODTParagraphStyle(S_SEP)
style.setDisplayName("Separator")
style.setParentStyleName("Standard")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setClass("text")
style.setMarginTop(self._mTopText)
style.setMarginBottom(self._mBotText)
@@ -947,10 +932,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Heading 1 Style
style = ODTParagraphStyle("Heading_20_1")
style = ODTParagraphStyle(S_HEAD1)
style.setDisplayName("Heading 1")
style.setParentStyleName("Heading")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setOutlineLevel("1")
style.setClass("text")
style.setMarginTop(self._mTopHead1)
@@ -965,10 +950,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Heading 2 Style
style = ODTParagraphStyle("Heading_20_2")
style = ODTParagraphStyle(S_HEAD2)
style.setDisplayName("Heading 2")
style.setParentStyleName("Heading")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setOutlineLevel("2")
style.setClass("text")
style.setMarginTop(self._mTopHead2)
@@ -983,10 +968,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Heading 3 Style
style = ODTParagraphStyle("Heading_20_3")
style = ODTParagraphStyle(S_HEAD3)
style.setDisplayName("Heading 3")
style.setParentStyleName("Heading")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setOutlineLevel("3")
style.setClass("text")
style.setMarginTop(self._mTopHead3)
@@ -1001,10 +986,10 @@ class ToOdt(Tokenizer):
self._mainPara[style.name] = style
# Add Heading 4 Style
style = ODTParagraphStyle("Heading_20_4")
style = ODTParagraphStyle(S_HEAD4)
style.setDisplayName("Heading 4")
style.setParentStyleName("Heading")
style.setNextStyleName("Text_20_body")
style.setNextStyleName(S_TEXT)
style.setOutlineLevel("4")
style.setClass("text")
style.setMarginTop(self._mTopHead4)
@@ -1021,7 +1006,7 @@ class ToOdt(Tokenizer):
# Add Header Style
style = ODTParagraphStyle("Header")
style.setDisplayName("Header")
style.setParentStyleName("Header_20_and_20_Footer")
style.setParentStyleName(S_HNF)
style.setTextAlign("right")
style.packXML(self._xStyl)
self._mainPara[style.name] = style