From 2d2974a4af1b1e03c66f9d1765d3292bc0fae7b1 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Thu, 21 May 2020 23:23:43 +0200
Subject: [PATCH 1/6] Added a bugfix that was missing in the changelog
---
CHANGELOG.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index daf37221..dacddfba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
## Version 0.6 [2020-xx-xx]
+**Bugfixes**
+
+* Fixed a bug in validation of `@tag:` meta tags where one or more spaces before the `:` would still pass as valid tags, but the keyword index array would be missing those spaces in its counter. This mainly affected the highlighting of keywords, which would be misaligned. PR #206
+
**User Interface**
* The Export Tool has been removed and replaced by a new tool called "Build Novel Project". The new tool has the same filtering options as the Export Tool, but with more formatting options for titles. It also has a preview window to display the generated document. A Save As button provides exports to HTML, novelWriter Markdown. plain text, PDF and Open Document format. LaTeX export has not been ported over, and interfacing with Pandoc is no longer supported either. Although, as before, the HTML export can be converted with Pandoc to other formats outside of novelWriter. The new tool also supports printing. PR #204
From dd9ec4772b55c9aeb3a04b2ef2629c41d796edc7 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 23 May 2020 14:35:41 +0200
Subject: [PATCH 2/6] Lines with hard line breaks should not have a justify
property
---
nw/core/tohtml.py | 9 ++++++---
nw/core/tokenizer.py | 11 ++++++++---
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index f10ee1e3..33c247a9 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -119,7 +119,7 @@ class ToHtml(Tokenizer):
self.theResult = ""
thisPar = []
- parStyle = ""
+ parStyle = None
tmpResult = []
for tType, tText, tFormat, tStyle in self.theTokens:
@@ -158,11 +158,13 @@ class ToHtml(Tokenizer):
# Process TextType
if tType == self.T_EMPTY:
+ if parStyle is None:
+ parStyle = ""
if len(thisPar) > 0:
tTemp = "".join(thisPar)
tmpResult.append("
%s
\n" % (parStyle, tTemp.rstrip()))
thisPar = []
- parStyle = ""
+ parStyle = None
elif tType == self.T_HEAD1:
tHead = tText.replace(r"\\", "
")
@@ -188,7 +190,8 @@ class ToHtml(Tokenizer):
elif tType == self.T_TEXT:
tTemp = tText
- parStyle = hStyle
+ if parStyle is None:
+ parStyle = hStyle
for xPos, xLen, xFmt in reversed(tFormat):
tTemp = tTemp[:xPos]+htmlTags[xFmt]+tTemp[xPos+xLen:]
if tText.endswith(" "):
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index 80cc216d..a3c04bd8 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -366,9 +366,14 @@ class Tokenizer():
# Save the line as is, but append the array of formatting locations
# sorted by position
fmtPos = sorted(fmtPos, key=itemgetter(0))
- self.theTokens.append((
- self.T_TEXT, aLine, fmtPos, defAlign
- ))
+ if aLine.endswith(" "):
+ self.theTokens.append((
+ self.T_TEXT, aLine, fmtPos, self.A_LEFT
+ ))
+ else:
+ self.theTokens.append((
+ self.T_TEXT, aLine, fmtPos, defAlign
+ ))
tmpMarkdown.append("%s\n" % aLine)
# Always add an empty line at the end
From fabcd1e631d6b71ee6d34e7540d54a2eb004d73d Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 23 May 2020 15:25:39 +0200
Subject: [PATCH 3/6] As the ToHTML class now can be reused, move the regex
stuff to the contructor
---
nw/core/tohtml.py | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index 33c247a9..12d34404 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -54,6 +54,14 @@ class ToHtml(Tokenizer):
nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
nwUnicode.U_NBSP : nwUnicode.H_NBSP,
}
+ self.revDict = dict(map(reversed, self.repDict.items()))
+
+ self.reReplace = re.compile(
+ "|".join([re.escape(k) for k in self.repDict.keys()]), flags=re.DOTALL
+ )
+ self.reReverse = re.compile(
+ "|".join([re.escape(k) for k in self.revDict.keys()]), flags=re.DOTALL
+ )
return
@@ -82,10 +90,9 @@ class ToHtml(Tokenizer):
characters into their respective HTML entities.
"""
Tokenizer.doAutoReplace(self)
-
- xRep = re.compile("|".join([re.escape(k) for k in self.repDict.keys()]), flags=re.DOTALL)
- self.theText = xRep.sub(lambda x: self.repDict[x.group(0)], self.theText)
-
+ self.theText = self.reReplace.sub(
+ lambda x: self.repDict[x.group(0)], self.theText
+ )
return
def doPostProcessing(self):
@@ -95,18 +102,15 @@ class ToHtml(Tokenizer):
if self.genMode == self.M_PREVIEW:
# Doesn't matter for preview as we don't use the markdown
return
-
- revDict = dict(map(reversed, self.repDict.items()))
- xRep = re.compile("|".join([re.escape(k) for k in revDict.keys()]), flags=re.DOTALL)
- self.theMarkdown = xRep.sub(lambda x: revDict[x.group(0)], self.theMarkdown)
-
+ self.theMarkdown = self.reReverse.sub(
+ lambda x: self.revDict[x.group(0)], self.theMarkdown
+ )
return
def doConvert(self):
"""Convert the list of text tokens into a HTML document saved
to theResult.
"""
-
htmlTags = {
self.FMT_B_B : "",
self.FMT_B_E : "",
From a5729cf0a9a8bda6544e8f1254cb1e016a39556a Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 23 May 2020 17:59:07 +0200
Subject: [PATCH 4/6] Cleaned up html export
---
nw/core/tohtml.py | 141 +++++++++++++++++++++++++++++++------------
nw/core/tokenizer.py | 82 +++++++++++--------------
nw/gui/build.py | 57 +++++++++--------
3 files changed, 166 insertions(+), 114 deletions(-)
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index 12d34404..0fb517b8 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -48,20 +48,16 @@ class ToHtml(Tokenizer):
"<" : "<",
">" : ">",
"&" : "&",
- "\t" : " ",
+ "\t" : " "*2,
nwUnicode.U_ENDASH : nwUnicode.H_ENDASH,
nwUnicode.U_EMDASH : nwUnicode.H_EMDASH,
nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
nwUnicode.U_NBSP : nwUnicode.H_NBSP,
}
- self.revDict = dict(map(reversed, self.repDict.items()))
-
- self.reReplace = re.compile(
- "|".join([re.escape(k) for k in self.repDict.keys()]), flags=re.DOTALL
- )
- self.reReverse = re.compile(
- "|".join([re.escape(k) for k in self.revDict.keys()]), flags=re.DOTALL
- )
+ self.revDict = {}
+ self.reReplace = []
+ self.reReverse = []
+ self._buildRegEx()
return
@@ -79,6 +75,7 @@ class ToHtml(Tokenizer):
self.doKeywords = True
self.doComments = doComments
self.repDict["\t"] = " "*8
+ self._buildRegEx()
return
##
@@ -120,40 +117,61 @@ class ToHtml(Tokenizer):
self.FMT_U_E : "",
}
+ if self.isNovel and self.genMode != self.M_PREVIEW:
+ # For novel files for export, we bump the titles one level
+ # up, as this is more useful for printing and word processor
+ # imports.
+ h1 = "h1 class=\"title\""
+ h2 = "h1"
+ h3 = "h2"
+ h4 = "h3"
+ else:
+ h1 = "h1"
+ h2 = "h2"
+ h3 = "h3"
+ h4 = "h4"
+
+ alignHead = self.A_LEFT
+ if self.doJustify:
+ alignPar = self.A_JUSTIFY
+ else:
+ alignPar = self.A_LEFT
+
self.theResult = ""
thisPar = []
parStyle = None
tmpResult = []
+ hasHardBreak = False
for tType, tText, tFormat, tStyle in self.theTokens:
# Styles
aStyle = []
if tStyle is not None:
- if tStyle & self.A_LEFT:
- aStyle.append("text-align: left;")
- if tStyle & self.A_RIGHT:
- aStyle.append("text-align: right;")
+ # if tStyle & self.A_LEFT:
+ # aStyle.append("text-align: left;")
+ # if tStyle & self.A_RIGHT:
+ # aStyle.append("text-align: right;")
if tStyle & self.A_CENTRE:
aStyle.append("text-align: center;")
- if tStyle & self.A_JUSTIFY:
- 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 tStyle & self.A_JUSTIFY:
+ # 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:
hStyle = " style='%s'" % (" ".join(aStyle))
@@ -164,33 +182,42 @@ class ToHtml(Tokenizer):
if tType == self.T_EMPTY:
if parStyle is None:
parStyle = ""
+ if hasHardBreak:
+ parClass = " class='break'"
+ else:
+ parClass = ""
if len(thisPar) > 0:
tTemp = "".join(thisPar)
- tmpResult.append("%s
\n" % (parStyle, tTemp.rstrip()))
+ tmpResult.append("%s
\n" % (parStyle, parClass, tTemp.rstrip()))
thisPar = []
parStyle = None
+ hasHardBreak = False
+
+ elif tType == self.T_TITLE:
+ tHead = tText.replace(r"\\", "
")
+ tmpResult.append("\n" % (hStyle, tHead))
elif tType == self.T_HEAD1:
tHead = tText.replace(r"\\", "
")
- tmpResult.append("%s
\n" % (hStyle, tHead))
+ tmpResult.append("<%s%s>%s%s>\n" % (h1, hStyle, tHead, h1))
elif tType == self.T_HEAD2:
tHead = tText.replace(r"\\", "
")
- tmpResult.append("%s
\n" % (hStyle, tHead))
+ tmpResult.append("<%s%s>%s%s>\n" % (h2, hStyle, tHead, h2))
elif tType == self.T_HEAD3:
tHead = tText.replace(r"\\", "
")
- tmpResult.append("%s
\n" % (hStyle, tHead))
+ tmpResult.append("<%s%s>%s%s>\n" % (h3, hStyle, tHead, h3))
elif tType == self.T_HEAD4:
tHead = tText.replace(r"\\", "
")
- tmpResult.append("%s
\n" % (hStyle, tHead))
+ tmpResult.append("<%s%s>%s%s>\n" % (h4, hStyle, tHead, h4))
elif tType == self.T_SEP:
- tmpResult.append("%s
\n" % (hStyle, tText))
+ tmpResult.append("%s
\n" % tText)
elif tType == self.T_SKIP:
- tmpResult.append("
\n" % hStyle)
+ tmpResult.append("
\n")
elif tType == self.T_TEXT:
tTemp = tText
@@ -200,6 +227,7 @@ class ToHtml(Tokenizer):
tTemp = tTemp[:xPos]+htmlTags[xFmt]+tTemp[xPos+xLen:]
if tText.endswith(" "):
thisPar.append(tTemp.rstrip()+"
")
+ hasHardBreak = True
else:
thisPar.append(tTemp.rstrip()+" ")
@@ -217,6 +245,30 @@ class ToHtml(Tokenizer):
return
+ def getStylesheet(self):
+ """Generate a stylesheet appropriate for the current settings.
+ """
+ theStyles = []
+
+ if self.doJustify:
+ theStyles.append(r"p {text-align: justify;}")
+ else:
+ theStyles.append(r"p {text-align: left;}")
+
+ theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
+ theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
+ theStyles.append(r"h1, h2, h3, h4 {page-break-after: avoid;}")
+ theStyles.append(r"h1 {page-break-before: always;}")
+ theStyles.append(r".title {font-size: 2.5em; font-weight: bold; page-break-before: never;}")
+ theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
+ theStyles.append(r".break {text-align: left;}")
+ theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}")
+ theStyles.append(r".skip {margin-top: 1em; margin-bottom: 1em;}")
+ theStyles.append(r".synopsis {font-style: italic;}")
+ theStyles.append(r".comment {font-style: italic; color: rgb(100, 100, 100);}")
+
+ return theStyles
+
##
# Internal Functions
##
@@ -240,7 +292,6 @@ class ToHtml(Tokenizer):
def _formatKeywords(self, tText):
"""Apply HTML formatting to keywords.
"""
-
tText = "@"+tText
isValid, theBits, thePos = self.theParent.theIndex.scanThis(tText)
if not isValid or not theBits:
@@ -270,4 +321,16 @@ class ToHtml(Tokenizer):
return "%s
" % retText
+ def _buildRegEx(self):
+ """Build the regular expressions
+ """
+ self.revDict = dict(map(reversed, self.repDict.items()))
+ self.reReplace = re.compile(
+ "|".join([re.escape(k) for k in self.repDict.keys()]), flags=re.DOTALL
+ )
+ self.reReverse = re.compile(
+ "|".join([re.escape(k) for k in self.revDict.keys()]), flags=re.DOTALL
+ )
+ return
+
# END Class ToHtml
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index a3c04bd8..8773cdb1 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -51,26 +51,23 @@ class Tokenizer():
T_SYNOPSIS = 2 # Synopsis comment
T_COMMENT = 3 # Comment line
T_KEYWORD = 4 # Command line
- T_HEAD1 = 5 # Header 1 (title)
- T_HEAD2 = 6 # Header 2 (chapter)
- T_HEAD3 = 7 # Header 3 (scene)
- T_HEAD4 = 8 # Header 4
- T_TEXT = 9 # Text line
- T_SEP = 10 # Scene separator
- T_SKIP = 11 # Paragraph break
+ T_TITLE = 5 # Title
+ T_HEAD1 = 6 # Header 1
+ T_HEAD2 = 7 # Header 2
+ T_HEAD3 = 8 # Header 3
+ T_HEAD4 = 9 # Header 4
+ T_TEXT = 10 # Text line
+ T_SEP = 11 # Scene separator
+ T_SKIP = 12 # Paragraph break
- A_LEFT = 1 # Left aligned
- A_RIGHT = 2 # Right aligned
- A_CENTRE = 4 # Centred
- 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
+ A_LEFT = 1 # Left aligned
+ A_RIGHT = 2 # Right aligned
+ A_CENTRE = 4 # Centred
+ A_JUSTIFY = 8 # Justified
+ A_PBB = 16 # Page break before
+ A_PBB_AV = 32 # Page break, avoid
+ A_PBA = 64 # Page break after
+ A_PBA_AV = 128 # Page break, avoid
def __init__(self, theProject, theParent):
@@ -283,11 +280,6 @@ class Tokenizer():
[None, self.FMT_U_B, None, self.FMT_U_E]
)]
- if self.doJustify:
- defAlign = self.A_JUSTIFY
- else:
- defAlign = self.A_LEFT
-
self.theTokens = []
self.theMarkdown = ""
tmpMarkdown = []
@@ -304,45 +296,45 @@ class Tokenizer():
cLine = aLine[1:].strip()
if cLine.lower().startswith("synopsis:"):
self.theTokens.append((
- self.T_SYNOPSIS, cLine[9:].strip(), None, defAlign
+ self.T_SYNOPSIS, cLine[9:].strip(), None, None
))
if self.doSynopsis:
tmpMarkdown.append("%s\n" % aLine)
else:
self.theTokens.append((
- self.T_COMMENT, aLine[1:].strip(), None, defAlign
+ self.T_COMMENT, aLine[1:].strip(), None, None
))
if self.doComments:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[0] == "@":
self.theTokens.append((
- self.T_KEYWORD, aLine[1:].strip(), None, self.A_LEFT
+ self.T_KEYWORD, aLine[1:].strip(), None, None
))
if self.doKeywords:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:2] == "# ":
self.theTokens.append((
- self.T_HEAD1, aLine[2:].strip(), None, self.A_LEFT | self.A_PBB
+ self.T_HEAD1, aLine[2:].strip(), None, None
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:3] == "## ":
self.theTokens.append((
- self.T_HEAD2, aLine[3:].strip(), None, self.A_LEFT | self.A_PBA_AV
+ self.T_HEAD2, aLine[3:].strip(), None, None
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:4] == "### ":
self.theTokens.append((
- self.T_HEAD3, aLine[4:].strip(), None, self.A_LEFT | self.A_PBA_AV
+ self.T_HEAD3, aLine[4:].strip(), None, None
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:5] == "#### ":
self.theTokens.append((
- self.T_HEAD4, aLine[5:].strip(), None, self.A_LEFT | self.A_PBA_AV
+ self.T_HEAD4, aLine[5:].strip(), None, None
))
tmpMarkdown.append("%s\n" % aLine)
@@ -366,14 +358,9 @@ class Tokenizer():
# Save the line as is, but append the array of formatting locations
# sorted by position
fmtPos = sorted(fmtPos, key=itemgetter(0))
- if aLine.endswith(" "):
- self.theTokens.append((
- self.T_TEXT, aLine, fmtPos, self.A_LEFT
- ))
- else:
- self.theTokens.append((
- self.T_TEXT, aLine, fmtPos, defAlign
- ))
+ self.theTokens.append((
+ self.T_TEXT, aLine, fmtPos, None
+ ))
tmpMarkdown.append("%s\n" % aLine)
# Always add an empty line at the end
@@ -415,7 +402,7 @@ class Tokenizer():
tText = self._formatHeading(self.fmtTitle, tText)
self.theTokens[n] = (
- tType, tText, None, self.A_LEFT | self.A_PBB_R
+ tType, tText, None, None
)
elif tType == self.T_HEAD2:
@@ -431,7 +418,7 @@ class Tokenizer():
# Format the chapter header
self.theTokens[n] = (
- tType, tText, None, self.A_LEFT | self.A_PBB_R
+ tType, tText, None, None
)
# Set scene variables
@@ -470,7 +457,7 @@ class Tokenizer():
)
else:
self.theTokens[n] = (
- tType, tTemp, None, self.A_LEFT | self.A_PBA_AV
+ tType, tTemp, None, None
)
# Definitely no longer the first scene
@@ -495,21 +482,24 @@ class Tokenizer():
)
else:
self.theTokens[n] = (
- tType, tTemp, None, self.A_LEFT | self.A_PBA_AV
+ tType, tTemp, None, None
)
# For title page and partitions, we need to centre all text.
# For partition, we also add a page break before, and for
# both types we always add a page break after the content.
+ # We also swap header level 1 with a title type instead.
if self.isTitle or self.isPart:
for n, tToken in enumerate(self.theTokens):
tType = tToken[0]
tText = tToken[1]
tFormat = tToken[2]
if self.isTitle:
- self.theTokens[n] = (
- tType, tText, tFormat, self.A_CENTRE
- )
+ if tType == self.T_HEAD1:
+ tType = self.T_TITLE
+ self.theTokens[n] = (
+ tType, tText, tFormat, self.A_CENTRE
+ )
# Add a page break after the last entry
n = len(self.theTokens) - 1
diff --git a/nw/gui/build.py b/nw/gui/build.py
index 737a13c4..8baf00fc 100644
--- a/nw/gui/build.py
+++ b/nw/gui/build.py
@@ -70,6 +70,7 @@ class GuiBuildNovel(QDialog):
self.optState = self.theProject.optState
self.htmlText = [] # List of html document
+ self.htmlStyle = [] # List of html styles
self.nwdText = [] # List of markdown documents
self.textLayout = [] # List of nwItemLayout entries
@@ -320,6 +321,7 @@ class GuiBuildNovel(QDialog):
tStart = time()
self.htmlText = []
+ self.htmlStyle = []
self.nwdText = []
self.textLayout = []
@@ -340,9 +342,11 @@ class GuiBuildNovel(QDialog):
tEnd = time()
logger.debug("Built project in %.3f ms" % (1000*(tEnd-tStart)))
+ self.htmlStyle = makeHtml.getStylesheet()
# Load the preview document with the html data
- self.docView.setHtml("".join(self.htmlText))
+ self.docView.setStyleSheet(self.htmlStyle)
+ self.docView.setContent(self.htmlText)
return
@@ -484,6 +488,9 @@ class GuiBuildNovel(QDialog):
outFile.write("\n")
outFile.write("\n")
outFile.write("\n")
+ outFile.write("\n")
outFile.write("\n")
outFile.write("\n")
for aLine in self.htmlText:
@@ -612,7 +619,8 @@ class GuiBuildNovel(QDialog):
if path.isfile(docPath):
with open(docPath, mode="r", encoding="utf8") as inFile:
helpText = inFile.read()
- self.docView.setText(helpText)
+ self.docView.setStyleSheet()
+ self.docView.setContent(helpText)
else:
self.theParent.makeAlert(
"Could not open help text file for Build Project.", nwAlert.ERROR
@@ -648,7 +656,7 @@ class GuiBuildNovelDocView(QTextBrowser):
docPalette.setColor(QPalette.Text, QColor( 0, 0, 0))
self.setPalette(docPalette)
- self._makeStyleSheet()
+ self.setStyleSheet()
self.show()
@@ -656,35 +664,26 @@ class GuiBuildNovelDocView(QTextBrowser):
return
- def setText(self, theText):
- self.setHtml(theText)
+ def setContent(self, theText):
+ """Set the content, either from text or list of text.
+ """
+ if isinstance(theText, str):
+ self.setHtml(theText)
+ else:
+ self.setHtml("".join(theText))
return
- ##
- # Internal Functions
- ##
+ def setStyleSheet(self, theStyles=[]):
+ """Set the stylesheet for the preview document.
+ """
+ if not theStyles:
+ theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
+ theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
+ theStyles.append(r"a {color: rgb(137, 89, 168);}")
+ theStyles.append(r"mark {background-color: rgb(240, 198, 116);}")
+ theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
- def _makeStyleSheet(self):
-
- styleSheet = (
- "h1, h2 {"
- " color: rgb(66, 113, 174);"
- "}\n"
- "h3, h4 {"
- " color: rgb(50, 50, 50);"
- "}\n"
- "a {"
- " color: rgb(137, 89, 168);"
- "}\n"
- "mark {"
- " background-color: rgb(240, 198, 116);"
- "}\n"
- ".tags {"
- " color: rgb(245, 135, 31);"
- " font-wright: bold;"
- "}\n"
- )
- self.qDocument.setDefaultStyleSheet(styleSheet)
+ self.qDocument.setDefaultStyleSheet("\n".join(theStyles))
return
From cf58823f375d1843bb95857dc7bb1c62d1f9e179 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 23 May 2020 19:30:01 +0200
Subject: [PATCH 5/6] Now the page breaks render properly on print
---
nw/core/tohtml.py | 45 ++++++------
nw/core/tokenizer.py | 70 +++++++++++--------
.../sampleNovel/data_e/dca4be2fcaf8_main.nwd | 4 ++
sample/sampleNovel/nwProject.nwx | 21 ++++--
4 files changed, 81 insertions(+), 59 deletions(-)
create mode 100644 sample/sampleNovel/data_e/dca4be2fcaf8_main.nwd
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index 0fb517b8..9b5eb425 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -148,30 +148,26 @@ class ToHtml(Tokenizer):
# Styles
aStyle = []
if tStyle is not None:
- # if tStyle & self.A_LEFT:
- # aStyle.append("text-align: left;")
- # if tStyle & self.A_RIGHT:
- # aStyle.append("text-align: right;")
+ if tStyle & self.A_LEFT:
+ aStyle.append("text-align: left;")
+ if tStyle & self.A_RIGHT:
+ aStyle.append("text-align: right;")
if tStyle & self.A_CENTRE:
aStyle.append("text-align: center;")
- # if tStyle & self.A_JUSTIFY:
- # 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 tStyle & self.A_JUSTIFY:
+ aStyle.append("text-align: justify;")
+ if tStyle & self.A_PBB:
+ aStyle.append("page-break-before: always;")
+ if tStyle & self.A_PBB_AV:
+ aStyle.append("page-break-before: avoid;")
+ if tStyle & self.A_PBB_NO:
+ aStyle.append("page-break-before: never;")
+ if tStyle & self.A_PBA:
+ aStyle.append("page-break-after: always;")
+ if tStyle & self.A_PBA_AV:
+ aStyle.append("page-break-after: avoid;")
+ if tStyle & self.A_PBA_NO:
+ aStyle.append("page-break-after: never;")
if len(aStyle) > 0:
hStyle = " style='%s'" % (" ".join(aStyle))
@@ -195,7 +191,7 @@ class ToHtml(Tokenizer):
elif tType == self.T_TITLE:
tHead = tText.replace(r"\\", "
")
- tmpResult.append("\n" % (hStyle, tHead))
+ tmpResult.append("%s
\n" % (hStyle, tHead))
elif tType == self.T_HEAD1:
tHead = tText.replace(r"\\", "
")
@@ -258,8 +254,7 @@ class ToHtml(Tokenizer):
theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
theStyles.append(r"h1, h2, h3, h4 {page-break-after: avoid;}")
- theStyles.append(r"h1 {page-break-before: always;}")
- theStyles.append(r".title {font-size: 2.5em; font-weight: bold; page-break-before: never;}")
+ theStyles.append(r".title {font-size: 2.5em; font-weight: bold;}")
theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(r".break {text-align: left;}")
theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}")
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index 8773cdb1..d4e001f5 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -60,14 +60,17 @@ class Tokenizer():
T_SEP = 11 # Scene separator
T_SKIP = 12 # Paragraph break
+ A_NONE = 0 # No special style
A_LEFT = 1 # Left aligned
A_RIGHT = 2 # Right aligned
A_CENTRE = 4 # Centred
A_JUSTIFY = 8 # Justified
- A_PBB = 16 # Page break before
- A_PBB_AV = 32 # Page break, avoid
- A_PBA = 64 # Page break after
- A_PBA_AV = 128 # Page break, avoid
+ A_PBB = 16 # Page break before always
+ A_PBB_AV = 32 # Page break before avoid
+ A_PBB_NO = 64 # Page break before never
+ A_PBA = 128 # Page break after always
+ A_PBA_AV = 256 # Page break after avoid
+ A_PBA_NO = 512 # Page break after avoid
def __init__(self, theProject, theParent):
@@ -288,7 +291,7 @@ class Tokenizer():
# Tag lines starting with specific characters
if len(aLine.strip()) == 0:
self.theTokens.append((
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
))
tmpMarkdown.append("\n")
@@ -296,45 +299,45 @@ class Tokenizer():
cLine = aLine[1:].strip()
if cLine.lower().startswith("synopsis:"):
self.theTokens.append((
- self.T_SYNOPSIS, cLine[9:].strip(), None, None
+ self.T_SYNOPSIS, cLine[9:].strip(), None, self.A_NONE
))
if self.doSynopsis:
tmpMarkdown.append("%s\n" % aLine)
else:
self.theTokens.append((
- self.T_COMMENT, aLine[1:].strip(), None, None
+ self.T_COMMENT, aLine[1:].strip(), None, self.A_NONE
))
if self.doComments:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[0] == "@":
self.theTokens.append((
- self.T_KEYWORD, aLine[1:].strip(), None, None
+ self.T_KEYWORD, aLine[1:].strip(), None, self.A_NONE
))
if self.doKeywords:
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:2] == "# ":
self.theTokens.append((
- self.T_HEAD1, aLine[2:].strip(), None, None
+ self.T_HEAD1, aLine[2:].strip(), None, self.A_PBB
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:3] == "## ":
self.theTokens.append((
- self.T_HEAD2, aLine[3:].strip(), None, None
+ self.T_HEAD2, aLine[3:].strip(), None, self.A_NONE
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:4] == "### ":
self.theTokens.append((
- self.T_HEAD3, aLine[4:].strip(), None, None
+ self.T_HEAD3, aLine[4:].strip(), None, self.A_NONE
))
tmpMarkdown.append("%s\n" % aLine)
elif aLine[:5] == "#### ":
self.theTokens.append((
- self.T_HEAD4, aLine[5:].strip(), None, None
+ self.T_HEAD4, aLine[5:].strip(), None, self.A_NONE
))
tmpMarkdown.append("%s\n" % aLine)
@@ -359,13 +362,13 @@ class Tokenizer():
# sorted by position
fmtPos = sorted(fmtPos, key=itemgetter(0))
self.theTokens.append((
- self.T_TEXT, aLine, fmtPos, None
+ self.T_TEXT, aLine, fmtPos, self.A_NONE
))
tmpMarkdown.append("%s\n" % aLine)
# Always add an empty line at the end
self.theTokens.append((
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
))
tmpMarkdown.append("\n")
@@ -402,7 +405,7 @@ class Tokenizer():
tText = self._formatHeading(self.fmtTitle, tText)
self.theTokens[n] = (
- tType, tText, None, None
+ tType, tText, None, self.A_NONE
)
elif tType == self.T_HEAD2:
@@ -418,7 +421,7 @@ class Tokenizer():
# Format the chapter header
self.theTokens[n] = (
- tType, tText, None, None
+ tType, tText, None, self.A_PBB
)
# Set scene variables
@@ -435,21 +438,21 @@ class Tokenizer():
tTemp = self._formatHeading(self.fmtScene, tText)
if tTemp == "" and self.hideScene:
self.theTokens[n] = (
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
)
elif tTemp == "" and not self.hideScene:
if self.firstScene:
self.theTokens[n] = (
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
)
else:
self.theTokens[n] = (
- self.T_SKIP, "", None, None
+ self.T_SKIP, "", None, self.A_NONE
)
elif tTemp == self.fmtScene:
if self.firstScene:
self.theTokens[n] = (
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
)
else:
self.theTokens[n] = (
@@ -457,7 +460,7 @@ class Tokenizer():
)
else:
self.theTokens[n] = (
- tType, tTemp, None, None
+ tType, tTemp, None, self.A_NONE
)
# Definitely no longer the first scene
@@ -470,11 +473,11 @@ class Tokenizer():
tTemp = self._formatHeading(self.fmtSection, tText)
if tTemp == "" and self.hideSection:
self.theTokens[n] = (
- self.T_EMPTY, "", None, None
+ self.T_EMPTY, "", None, self.A_NONE
)
elif tTemp == "" and not self.hideSection:
self.theTokens[n] = (
- self.T_SKIP, "", None, None
+ self.T_SKIP, "", None, self.A_NONE
)
elif tTemp == self.fmtSection:
self.theTokens[n] = (
@@ -482,7 +485,7 @@ class Tokenizer():
)
else:
self.theTokens[n] = (
- tType, tTemp, None, None
+ tType, tTemp, None, self.A_NONE
)
# For title page and partitions, we need to centre all text.
@@ -494,12 +497,19 @@ class Tokenizer():
tType = tToken[0]
tText = tToken[1]
tFormat = tToken[2]
- if self.isTitle:
- if tType == self.T_HEAD1:
- tType = self.T_TITLE
- self.theTokens[n] = (
- tType, tText, tFormat, self.A_CENTRE
- )
+ if tType == self.T_HEAD1:
+ if self.isTitle:
+ self.theTokens[n] = (
+ self.T_TITLE, tText, tFormat, self.A_PBB_NO | self.A_CENTRE
+ )
+ else:
+ self.theTokens[n] = (
+ tType, tText, tFormat, self.A_PBB | self.A_CENTRE
+ )
+ else:
+ self.theTokens[n] = (
+ tType, tText, tFormat, self.A_CENTRE
+ )
# Add a page break after the last entry
n = len(self.theTokens) - 1
diff --git a/sample/sampleNovel/data_e/dca4be2fcaf8_main.nwd b/sample/sampleNovel/data_e/dca4be2fcaf8_main.nwd
new file mode 100644
index 00000000..679e4e27
--- /dev/null
+++ b/sample/sampleNovel/data_e/dca4be2fcaf8_main.nwd
@@ -0,0 +1,4 @@
+%%~ edca4be2fcaf8:7031beac91f75:Part 1
+# Part One
+
+The first part.
\ No newline at end of file
diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx
index 9e0468e6..d0405ad5 100644
--- a/sample/sampleNovel/nwProject.nwx
+++ b/sample/sampleNovel/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -10,7 +10,7 @@
True
True
- 96b68994dfa3d
+ 636b6aa9b697b
6a2d6d5f4f401
875
@@ -44,7 +44,7 @@
Main
-
+
-
Novel
ROOT
@@ -65,7 +65,20 @@
2
78
- -
+
-
+ Part 1
+ FILE
+ NOVEL
+ New
+ False
+ True
+ PARTITION
+ 0
+ 0
+ 0
+ 0
+
+ -
A Folder
FOLDER
NOVEL
From fd27f8d1e8b6d8ef2cbc55082035560c30e8dff4 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Sat, 23 May 2020 21:15:08 +0200
Subject: [PATCH 6/6] Added note root headings, changed some formatting, and
improved export
---
nw/core/tohtml.py | 6 +-
nw/core/tokenizer.py | 31 +++++--
nw/gui/build.py | 140 +++++++++++++++++--------------
sample/sampleNovel/nwProject.nwx | 8 +-
4 files changed, 110 insertions(+), 75 deletions(-)
diff --git a/nw/core/tohtml.py b/nw/core/tohtml.py
index 9b5eb425..ba099335 100644
--- a/nw/core/tohtml.py
+++ b/nw/core/tohtml.py
@@ -119,9 +119,9 @@ class ToHtml(Tokenizer):
if self.isNovel and self.genMode != self.M_PREVIEW:
# For novel files for export, we bump the titles one level
- # up, as this is more useful for printing and word processor
+ # up as this is more useful for printing and word processor
# imports.
- h1 = "h1 class=\"title\""
+ h1 = "h1 class='title'"
h2 = "h1"
h3 = "h2"
h4 = "h3"
@@ -254,7 +254,7 @@ class ToHtml(Tokenizer):
theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}")
theStyles.append(r"h1, h2, h3, h4 {page-break-after: avoid;}")
- theStyles.append(r".title {font-size: 2.5em; font-weight: bold;}")
+ theStyles.append(r".title {font-size: 2.5em;}")
theStyles.append(r".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(r".break {text-align: left;}")
theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}")
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index d4e001f5..c94f418f 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -34,7 +34,7 @@ from PyQt5.QtCore import QRegularExpression
from nw.core.document import NWDoc
from nw.core.tools import numberToWord
-from nw.constants import nwItemLayout
+from nw.constants import nwItemLayout, nwItemType
logger = logging.getLogger(__name__)
@@ -198,6 +198,25 @@ class Tokenizer():
# Class Methods
##
+ def addRootHeading(self, theHandle):
+ """Add a heading at the start if a new root folder.
+ """
+ theItem = self.theProject.projTree[theHandle]
+ if theItem is None:
+ return False
+
+ if theItem.itemType != nwItemType.ROOT:
+ return False
+
+ theTitle = "Notes: %s" % theItem.itemName
+ self.theTokens = []
+ self.theTokens.append((
+ self.T_TITLE, theTitle, None, self.A_PBB | self.A_CENTRE
+ ))
+ self.theMarkdown = "# %s\n\n" % theTitle
+
+ return True
+
def setText(self, theHandle, theText=None):
"""Set the text for the tokenizer from a handle. If theText is
not set, load it from the file.
@@ -205,6 +224,8 @@ class Tokenizer():
self.theHandle = theHandle
self.theItem = self.theProject.projTree[theHandle]
+ if self.theItem is None:
+ return
if theText is not None:
# If the text is set, just use that
@@ -319,7 +340,7 @@ class Tokenizer():
elif aLine[:2] == "# ":
self.theTokens.append((
- self.T_HEAD1, aLine[2:].strip(), None, self.A_PBB
+ self.T_HEAD1, aLine[2:].strip(), None, self.A_NONE
))
tmpMarkdown.append("%s\n" % aLine)
@@ -386,8 +407,8 @@ class Tokenizer():
if self.isNone or self.isNote:
return
- # For novel files, we need to handle chapter numbering and scene
- # breaks
+ # For novel files, we need to handle chapter numbering, scene
+ # numbering, and scene breaks
if self.isNovel:
for n in range(len(self.theTokens)):
@@ -504,7 +525,7 @@ class Tokenizer():
)
else:
self.theTokens[n] = (
- tType, tText, tFormat, self.A_PBB | self.A_CENTRE
+ tType, tText, tFormat, self.A_PBB | self.A_CENTRE
)
else:
self.theTokens[n] = (
diff --git a/nw/gui/build.py b/nw/gui/build.py
index 8baf00fc..1bf268eb 100644
--- a/nw/gui/build.py
+++ b/nw/gui/build.py
@@ -34,7 +34,7 @@ from time import time
from PyQt5.QtCore import Qt, QByteArray
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtGui import (
- QTextOption, QPalette, QColor, QTextDocumentWriter
+ QTextOption, QPalette, QColor, QTextDocumentWriter, QFont
)
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
@@ -44,7 +44,7 @@ from PyQt5.QtWidgets import (
from nw.gui.additions import QSwitch
from nw.core import ToHtml
from nw.constants import (
- nwConst, nwFiles, nwAlert, nwItemType, nwItemLayout, nwItemClass
+ nwAlert, nwItemType, nwItemLayout, nwItemClass
)
logger = logging.getLogger(__name__)
@@ -69,10 +69,9 @@ class GuiBuildNovel(QDialog):
self.theTheme = theParent.theTheme
self.optState = self.theProject.optState
- self.htmlText = [] # List of html document
- self.htmlStyle = [] # List of html styles
- self.nwdText = [] # List of markdown documents
- self.textLayout = [] # List of nwItemLayout entries
+ self.htmlText = [] # List of html document
+ self.htmlStyle = [] # List of html styles
+ self.nwdText = [] # List of markdown documents
self.setWindowTitle("Build Novel Project")
self.setMinimumWidth(800)
@@ -323,10 +322,21 @@ class GuiBuildNovel(QDialog):
self.htmlText = []
self.htmlStyle = []
self.nwdText = []
- self.textLayout = []
for nItt, tItem in enumerate(self.theProject.projTree):
- if self._checkInclude(tItem, noteFiles, novelFiles, ignoreFlag):
+
+ noteRoot = noteFiles
+ noteRoot &= tItem.itemType == nwItemType.ROOT
+ noteRoot &= tItem.itemClass != nwItemClass.NOVEL
+
+ if noteRoot:
+ # Add headers for root folders of notes
+ makeHtml.addRootHeading(tItem.itemHandle)
+ makeHtml.doConvert()
+ self.htmlText.append(makeHtml.getResult())
+ self.nwdText.append(makeHtml.getFilteredMarkdown())
+
+ elif self._checkInclude(tItem, noteFiles, novelFiles, ignoreFlag):
makeHtml.setText(tItem.itemHandle)
makeHtml.doAutoReplace()
makeHtml.tokenizeText()
@@ -335,7 +345,6 @@ class GuiBuildNovel(QDialog):
makeHtml.doPostProcessing()
self.htmlText.append(makeHtml.getResult())
self.nwdText.append(makeHtml.getFilteredMarkdown())
- self.textLayout.append(tItem.itemLayout)
# Update progress bar, also for skipped items
self.buildProgress.setValue(nItt+1)
@@ -461,61 +470,53 @@ class GuiBuildNovel(QDialog):
return False
# Do the actual writing
+ wSuccess = False
+ errMsg = ""
if outTool == "Qt":
docWriter = QTextDocumentWriter()
docWriter.setFileName(savePath)
docWriter.setFormat(byteFmt)
- if docWriter.write(self.docView.qDocument):
- self.theParent.makeAlert(
- "Document successfully written in %s format to file: %s" % (
- textFmt, savePath
- ), nwAlert.INFO
- )
- else:
- self.theParent.makeAlert(
- "Failed to write document in %s format to file: %s" % (
- textFmt, savePath
- ), nwAlert.ERROR
- )
+ wSuccess = docWriter.write(self.docView.qDocument)
elif outTool == "NW":
try:
with open(savePath, mode="w", encoding="utf8") as outFile:
if theFormat == self.FMT_HTM:
# Write novelWriter HTML data
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
- for aLine in self.htmlText:
- outFile.write(aLine)
- outFile.write("\n")
- outFile.write("\n")
- outFile.write("\n")
+ theStyle = self.htmlStyle.copy()
+ theStyle.append(r"article {width: 800px; margin: 40px auto;}")
+ theHtml = (
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "{projTitle:s}\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "{bodyText:s}\n"
+ "\n"
+ "\n"
+ "\n"
+ ).format(
+ projTitle = self.theProject.projName,
+ htmlStyle = "\n".join(theStyle),
+ bodyText = "".join(self.htmlText),
+ )
+ outFile.write(theHtml)
elif theFormat == self.FMT_NWD:
# Write novelWriter markdown data
for aLine in self.nwdText:
outFile.write(aLine)
- self.theParent.makeAlert(
- "Document successfully written in %s format to file: %s" % (
- textFmt, savePath
- ), nwAlert.INFO
- )
+ wSuccess = True
except Exception as e:
- self.theParent.makeAlert(
- "Failed to write document in %s format to file: %s" % (
- textFmt, str(e)
- ), nwAlert.ERROR
- )
+ errMsg = str(e)
elif outTool == "QtPrint" and theFormat == self.FMT_PDF:
try:
@@ -527,23 +528,29 @@ class GuiBuildNovel(QDialog):
thePrinter.setColorMode(QPrinter.Color)
thePrinter.setOutputFileName(savePath)
self.docView.qDocument.print(thePrinter)
- self.theParent.makeAlert(
- "Document successfully written in %s format to file: %s" % (
- textFmt, savePath
- ), nwAlert.INFO
- )
+ wSuccess = True
except Exception as e:
- self.theParent.makeAlert(
- "Failed to write document in %s format to file: %s" % (
- textFmt, str(e)
- ), nwAlert.ERROR
- )
+ errMsg - str(e)
else:
- return False
+ errMsg = "Unknown format"
- return True
+ # Report to user
+ if wSuccess:
+ self.theParent.makeAlert(
+ "%s file successfully written to:
%s" % (
+ textFmt, savePath
+ ), nwAlert.INFO
+ )
+ else:
+ self.theParent.makeAlert(
+ "Failed to write %s file. %s" % (
+ textFmt, errMsg
+ ), nwAlert.ERROR
+ )
+
+ return wSuccess
def _printDocument(self):
"""Open the print preview dialog.
@@ -557,7 +564,6 @@ class GuiBuildNovel(QDialog):
"""Connect the print preview painter to the document viewer.
"""
thePrinter.setOrientation(QPrinter.Portrait)
- thePrinter.setOutputFormat(QPrinter.NativeFormat | QPrinter.PdfFormat)
self.docView.qDocument.print(thePrinter)
return
@@ -646,6 +652,14 @@ class GuiBuildNovelDocView(QTextBrowser):
self.qDocument = self.document()
self.qDocument.setDocumentMargin(self.mainConf.textMargin)
+ theFont = QFont()
+ if self.mainConf.textFont is None:
+ # If none is defined, set the default back to config
+ self.mainConf.textFont = self.qDocument.defaultFont().family()
+ theFont.setFamily(self.mainConf.textFont)
+ theFont.setPointSize(self.mainConf.textSize)
+ self.setFont(theFont)
+
theOpt = QTextOption()
if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify)
@@ -667,10 +681,10 @@ class GuiBuildNovelDocView(QTextBrowser):
def setContent(self, theText):
"""Set the content, either from text or list of text.
"""
- if isinstance(theText, str):
- self.setHtml(theText)
- else:
- self.setHtml("".join(theText))
+ if isinstance(theText, list):
+ theText = "".join(theText)
+ theText = theText.replace(" "," "*4)
+ self.setHtml(theText)
return
def setStyleSheet(self, theStyles=[]):
diff --git a/sample/sampleNovel/nwProject.nwx b/sample/sampleNovel/nwProject.nwx
index d0405ad5..b4b7b117 100644
--- a/sample/sampleNovel/nwProject.nwx
+++ b/sample/sampleNovel/nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Sample Project
Sample Project
@@ -20,12 +20,12 @@
%title%
- Chapter %chnum%.\\%title%
+ Chapter %chnum%: %title%
%title%
- Scene %chnum%.%scnum%: %title%
+ * * *
True
- False
+ True
False