Extended the style formatting of tokenizer and tohtml to allow multiple styles for a block

This commit is contained in:
Veronica K. B. Olsen
2020-05-11 18:18:19 +02:00
parent 3ad4e26dbc
commit 4dead91af2
3 changed files with 219 additions and 64 deletions
+26 -10
View File
@@ -102,19 +102,35 @@ class ToHtml(Tokenizer):
self.theResult = "" self.theResult = ""
thisPar = [] thisPar = []
for tType, tText, tFormat, tAlign in self.theTokens: for tType, tText, tFormat, tStyle in self.theTokens:
# Styles # Styles
aStyle = [] aStyle = []
if tAlign == self.A_CENTRE: if tStyle is not None:
aStyle.append("text-align: center;") if tStyle & self.A_LEFT:
elif tAlign == self.A_RIGHT: aStyle.append("text-align: left;")
aStyle.append("text-align: right;") if tStyle & self.A_RIGHT:
elif tAlign == self.A_JUSTIFY: aStyle.append("text-align: right;")
aStyle.append("text-align: justify;") if tStyle & self.A_CENTRE:
aStyle.append("text-align: center;")
if tType == self.T_HEAD2: if tStyle & self.A_JUSTIFY:
aStyle.append("page-break-before: always;") aStyle.append("text-align: justify;")
if tStyle & self.A_PBB:
aStyle.append("page-break-before: always;")
if tStyle & self.A_PBB_L:
aStyle.append("page-break-before: left;")
if tStyle & self.A_PBB_R:
aStyle.append("page-break-before: right;")
if tStyle & self.A_PBB_AV:
aStyle.append("page-break-before: avoid;")
if tStyle & self.A_PBA:
aStyle.append("page-break-after: always;")
if tStyle & self.A_PBA_L:
aStyle.append("page-break-after: left;")
if tStyle & self.A_PBA_R:
aStyle.append("page-break-after: right;")
if tStyle & self.A_PBA_AV:
aStyle.append("page-break-after: avoid;")
if len(aStyle) > 0: if len(aStyle) > 0:
hStyle = " style='%s'" % (" ".join(aStyle)) hStyle = " style='%s'" % (" ".join(aStyle))
+171 -33
View File
@@ -60,10 +60,18 @@ class Tokenizer():
T_SKIP = 11 # Paragraph break T_SKIP = 11 # Paragraph break
T_PBREAK = 12 # Page break T_PBREAK = 12 # Page break
A_LEFT = 1 # Left aligned A_LEFT = 1 # Left aligned
A_RIGHT = 2 # Right aligned A_RIGHT = 2 # Right aligned
A_CENTRE = 3 # Centred A_CENTRE = 4 # Centred
A_JUSTIFY = 4 # Justified A_JUSTIFY = 8 # Justified
A_PBB = 16 # Page break before
A_PBB_L = 32 # Page break before, left
A_PBB_R = 64 # Page break before, right
A_PBB_AV = 128 # Page break, avoid
A_PBA = 256 # Page break after
A_PBA_L = 512 # Page break after, left
A_PBA_R = 1024 # Page break after, right
A_PBA_AV = 2048 # Page break, avoid
def __init__(self, theProject, theParent): def __init__(self, theProject, theParent):
@@ -208,6 +216,13 @@ class Tokenizer():
just contains plain text. in the case of plain text, apply the just contains plain text. in the case of plain text, apply the
same RegExes that the syntax highlighter uses and save the same RegExes that the syntax highlighter uses and save the
locations of these formatting tags into the token array. locations of these formatting tags into the token array.
The format of the token list is an entry with a four-tuple for
each line in the file. The tuple is as follows:
1: The type of the block, self.T_*
2: The text content of the block, without leading tags
3: The internal formatting map of the text, self.FMT_*
4: The style of the block, self.A_*
""" """
# RegExes for adding formatting tags within text lines # RegExes for adding formatting tags within text lines
@@ -233,23 +248,63 @@ class Tokenizer():
# Tag lines starting with specific characters # Tag lines starting with specific characters
if len(aLine.strip()) == 0: if len(aLine.strip()) == 0:
self.theTokens.append((self.T_EMPTY, "", None, self.A_LEFT)) self.theTokens.append((
self.T_EMPTY,
"",
None,
None
))
elif aLine[0] == "%": elif aLine[0] == "%":
cLine = aLine[1:].strip() cLine = aLine[1:].strip()
if cLine.lower().startswith("synopsis:"): if cLine.lower().startswith("synopsis:"):
self.theTokens.append((self.T_SYNOPSIS, cLine[9:].strip(), None, defAlign)) self.theTokens.append((
self.T_SYNOPSIS,
cLine[9:].strip(),
None,
defAlign
))
else: else:
self.theTokens.append((self.T_COMMENT, aLine[1:].strip(), None, defAlign)) self.theTokens.append((
self.T_COMMENT,
aLine[1:].strip(),
None,
defAlign
))
elif aLine[0] == "@": elif aLine[0] == "@":
self.theTokens.append((self.T_KEYWORD, aLine[1:].strip(), None, self.A_LEFT)) self.theTokens.append((
self.T_KEYWORD,
aLine[1:].strip(),
None,
self.A_LEFT
))
elif aLine[:2] == "# ": elif aLine[:2] == "# ":
self.theTokens.append((self.T_HEAD1, aLine[2:].strip(), None, self.A_LEFT)) self.theTokens.append((
self.T_HEAD1,
aLine[2:].strip(),
None,
self.A_LEFT | self.A_PBB
))
elif aLine[:3] == "## ": elif aLine[:3] == "## ":
self.theTokens.append((self.T_HEAD2, aLine[3:].strip(), None, self.A_LEFT)) self.theTokens.append((
self.T_HEAD2,
aLine[3:].strip(),
None,
self.A_LEFT | self.A_PBA_AV
))
elif aLine[:4] == "### ": elif aLine[:4] == "### ":
self.theTokens.append((self.T_HEAD3, aLine[4:].strip(), None, self.A_LEFT)) self.theTokens.append((
self.T_HEAD3,
aLine[4:].strip(),
None,
self.A_LEFT | self.A_PBA_AV
))
elif aLine[:5] == "#### ": elif aLine[:5] == "#### ":
self.theTokens.append((self.T_HEAD4, aLine[5:].strip(), None, self.A_LEFT)) self.theTokens.append((
self.T_HEAD4,
aLine[5:].strip(),
None,
self.A_LEFT | self.A_PBA_AV
))
else: else:
if not self.doBodyText: if not self.doBodyText:
# Skip all body text # Skip all body text
@@ -270,10 +325,20 @@ class Tokenizer():
# Save the line as is, but append the array of formatting locations # Save the line as is, but append the array of formatting locations
# sorted by position # sorted by position
fmtPos = sorted(fmtPos, key=itemgetter(0)) fmtPos = sorted(fmtPos, key=itemgetter(0))
self.theTokens.append((self.T_TEXT, aLine, fmtPos, defAlign)) self.theTokens.append((
self.T_TEXT,
aLine,
fmtPos,
defAlign
))
# Always add an empty line at the end # Always add an empty line at the end
self.theTokens.append((self.T_EMPTY, "", None, self.A_LEFT)) self.theTokens.append((
self.T_EMPTY,
"",
None,
None
))
return return
@@ -308,53 +373,126 @@ class Tokenizer():
if tType == self.T_TEXT: if tType == self.T_TEXT:
self.firstScene = False self.firstScene = False
elif tType == self.T_HEAD2: elif tType == self.T_HEAD2: # Novel Chapter
if not isUnNum: if not isUnNum:
self.numChapter += 1 self.numChapter += 1
tText = self._formatChapter(tText,isUnNum) tText = self._formatChapter(tText,isUnNum)
self.theTokens[n] = (tType, tText, None, self.A_LEFT) self.theTokens[n] = (
tType,
tText,
None,
self.A_LEFT | self.A_PBB_R
)
self.firstScene = True self.firstScene = True
elif tType == self.T_HEAD3: elif tType == self.T_HEAD3: # Novel Scene
tTemp = self._formatScene(tText) tTemp = self._formatScene(tText)
if tTemp == "" and self.hideScene: if tTemp == "" and self.hideScene:
self.theTokens[n] = (self.T_EMPTY, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_EMPTY,
"",
None,
None
)
elif tTemp == "" and not self.hideScene: elif tTemp == "" and not self.hideScene:
if self.firstScene: if self.firstScene:
self.theTokens[n] = (self.T_EMPTY, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_EMPTY,
"",
None,
None
)
else: else:
self.theTokens[n] = (self.T_SKIP, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_SKIP,
"",
None,
None
)
elif tTemp == self.fmtScene: elif tTemp == self.fmtScene:
if self.firstScene: if self.firstScene:
self.theTokens[n] = (self.T_EMPTY, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_EMPTY,
"",
None,
None
)
else: else:
self.theTokens[n] = (self.T_SEP, tTemp, None, self.A_CENTRE) self.theTokens[n] = (
self.T_SEP,
tTemp,
None,
self.A_CENTRE
)
else: else:
self.theTokens[n] = (tType, tTemp, None, self.A_LEFT) self.theTokens[n] = (
tType,
tTemp,
None,
self.A_LEFT | self.A_PBA_AV
)
self.firstScene = False self.firstScene = False
elif tType == self.T_HEAD4: elif tType == self.T_HEAD4: # Novel Section
tTemp = self._formatSection(tText) tTemp = self._formatSection(tText)
if tTemp == "" and self.hideSection: if tTemp == "" and self.hideSection:
self.theTokens[n] = (self.T_EMPTY, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_EMPTY,
"",
None,
None
)
elif tTemp == "" and not self.hideSection: elif tTemp == "" and not self.hideSection:
self.theTokens[n] = (self.T_SKIP, "", None, self.A_LEFT) self.theTokens[n] = (
self.T_SKIP,
"",
None,
None
)
elif tTemp == self.fmtSection: elif tTemp == self.fmtSection:
self.theTokens[n] = (self.T_SEP, tTemp, None, self.A_CENTRE) self.theTokens[n] = (
self.T_SEP,
tTemp,
None,
self.A_CENTRE
)
else: else:
self.theTokens[n] = (tType, tTemp, None, self.A_LEFT) self.theTokens[n] = (
tType,
tTemp,
None,
self.A_LEFT | self.A_PBA_AV
)
# For title page and partitions, we need to centre all text # For title page and partitions, we need to centre all text.
# and for some formats, we need a page break # For partition, we also add a page break before, and for
# both types we always add a page break after the content.
if isTitle or isPart: if isTitle or isPart:
for n in range(len(self.theTokens)): for n in range(len(self.theTokens)):
tToken = self.theTokens[n] tToken = self.theTokens[n]
tType = tToken[0] tType = tToken[0]
tText = tToken[1] tText = tToken[1]
tFormat = tToken[2] tFormat = tToken[2]
self.theTokens[n] = (tType, tText, tFormat, self.A_CENTRE) if isTitle:
self.theTokens[n] = (
self.theTokens.append((self.T_PBREAK, "", None, self.A_LEFT)) tType,
tText,
tFormat,
self.A_CENTRE
)
else:
self.theTokens[n] = (
tType,
tText,
tFormat,
self.A_CENTRE | self.A_PBB_R
)
self.theTokens.append((
self.T_PBREAK,
"",
None,
None
))
return return
+22 -21
View File
@@ -129,21 +129,6 @@ class GuiBuildNovel(QDialog):
self.titleForm.setColumnStretch(0, 1) self.titleForm.setColumnStretch(0, 1)
self.titleForm.setColumnStretch(1, 0) self.titleForm.setColumnStretch(1, 0)
# Text Options
# =============
self.textGroup = QGroupBox("Text Options", self)
self.textForm = QGridLayout(self)
self.textGroup.setLayout(self.textForm)
self.justifyText = QSwitch()
self.justifyText.setChecked(self.optState.getBool("GuiBuildNovel", "justifyText", False))
self.textForm.addWidget(QLabel("Justify text"), 0, 0)
self.textForm.addWidget(self.justifyText, 0, 1)
self.textForm.setColumnStretch(0, 1)
self.textForm.setColumnStretch(1, 0)
# Build Settings # Build Settings
# ============== # ==============
self.buildGroup = QGroupBox("Build Overrides", self) self.buildGroup = QGroupBox("Build Overrides", self)
@@ -159,6 +144,21 @@ class GuiBuildNovel(QDialog):
self.buildForm.setColumnStretch(0, 1) self.buildForm.setColumnStretch(0, 1)
self.buildForm.setColumnStretch(1, 0) self.buildForm.setColumnStretch(1, 0)
# Text Options
# =============
self.textGroup = QGroupBox("Text Options", self)
self.textForm = QGridLayout(self)
self.textGroup.setLayout(self.textForm)
self.justifyText = QSwitch()
self.justifyText.setChecked(self.optState.getBool("GuiBuildNovel", "justifyText", False))
self.textForm.addWidget(QLabel("Justify text"), 0, 0)
self.textForm.addWidget(self.justifyText, 0, 1)
self.textForm.setColumnStretch(0, 1)
self.textForm.setColumnStretch(1, 0)
# Include Switches # Include Switches
# ================ # ================
self.includeGroup = QGroupBox("Include Non-Text Elements", self) self.includeGroup = QGroupBox("Include Non-Text Elements", self)
@@ -230,7 +230,7 @@ class GuiBuildNovel(QDialog):
self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT)) self.saveODT.triggered.connect(lambda: self._saveDocument(self.FMT_ODT))
self.saveMenu.addAction(self.saveODT) self.saveMenu.addAction(self.saveODT)
# self.savePDF = QAction("Portable Document (.pdf)") # self.savePDF = QAction("Portable Document Format (.pdf)")
# self.savePDF.triggered.connect(lambda: self._saveDocument(self.FMT_PDF)) # self.savePDF.triggered.connect(lambda: self._saveDocument(self.FMT_PDF))
# self.saveMenu.addAction(self.savePDF) # self.saveMenu.addAction(self.savePDF)
@@ -238,13 +238,14 @@ class GuiBuildNovel(QDialog):
self.saveHTM1.triggered.connect(lambda: self._saveDocument(self.FMT_HTM1)) self.saveHTM1.triggered.connect(lambda: self._saveDocument(self.FMT_HTM1))
self.saveMenu.addAction(self.saveHTM1) self.saveMenu.addAction(self.saveHTM1)
self.saveHTM2 = QAction("Plain HTML (.htm)") self.saveHTM2 = QAction("%s HTML (.htm)" % nw.__package__)
self.saveHTM2.triggered.connect(lambda: self._saveDocument(self.FMT_HTM2)) self.saveHTM2.triggered.connect(lambda: self._saveDocument(self.FMT_HTM2))
self.saveMenu.addAction(self.saveHTM2) self.saveMenu.addAction(self.saveHTM2)
# self.saveMD = QAction("Markdown (.md)") if self.mainConf.verQtValue >= 51400:
# self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD)) self.saveMD = QAction("Markdown (.md)")
# self.saveMenu.addAction(self.saveMD) self.saveMD.triggered.connect(lambda: self._saveDocument(self.FMT_MD))
self.saveMenu.addAction(self.saveMD)
self.saveTXT = QAction("Plain Text (.txt)") self.saveTXT = QAction("Plain Text (.txt)")
self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT)) self.saveTXT.triggered.connect(lambda: self._saveDocument(self.FMT_TXT))
@@ -261,8 +262,8 @@ class GuiBuildNovel(QDialog):
# Assemble GUI # Assemble GUI
# ============ # ============
self.toolsBox.addWidget(self.titleGroup) self.toolsBox.addWidget(self.titleGroup)
self.toolsBox.addWidget(self.textGroup)
self.toolsBox.addWidget(self.buildGroup) self.toolsBox.addWidget(self.buildGroup)
self.toolsBox.addWidget(self.textGroup)
self.toolsBox.addWidget(self.includeGroup) self.toolsBox.addWidget(self.includeGroup)
self.toolsBox.addWidget(self.addsGroup) self.toolsBox.addWidget(self.addsGroup)
self.toolsBox.addStretch(1) self.toolsBox.addStretch(1)