Added note root headings, changed some formatting, and improved export

This commit is contained in:
Veronica K. B. Olsen
2020-05-23 21:15:08 +02:00
parent cf58823f37
commit fd27f8d1e8
4 changed files with 110 additions and 75 deletions
+3 -3
View File
@@ -119,9 +119,9 @@ class ToHtml(Tokenizer):
if self.isNovel and self.genMode != self.M_PREVIEW: if self.isNovel and self.genMode != self.M_PREVIEW:
# For novel files for export, we bump the titles one level # 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. # imports.
h1 = "h1 class=\"title\"" h1 = "h1 class='title'"
h2 = "h1" h2 = "h1"
h3 = "h2" h3 = "h2"
h4 = "h3" h4 = "h3"
@@ -254,7 +254,7 @@ class ToHtml(Tokenizer):
theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}") theStyles.append(r"h1, h2 {color: rgb(66, 113, 174);}")
theStyles.append(r"h3, h4 {color: rgb(50, 50, 50);}") 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, 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".tags {color: rgb(245, 135, 31); font-weight: bold;}")
theStyles.append(r".break {text-align: left;}") theStyles.append(r".break {text-align: left;}")
theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}") theStyles.append(r".sep {text-align: center; margin-top: 1em; margin-bottom: 1em;}")
+26 -5
View File
@@ -34,7 +34,7 @@ from PyQt5.QtCore import QRegularExpression
from nw.core.document import NWDoc from nw.core.document import NWDoc
from nw.core.tools import numberToWord from nw.core.tools import numberToWord
from nw.constants import nwItemLayout from nw.constants import nwItemLayout, nwItemType
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -198,6 +198,25 @@ class Tokenizer():
# Class Methods # 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): def setText(self, theHandle, theText=None):
"""Set the text for the tokenizer from a handle. If theText is """Set the text for the tokenizer from a handle. If theText is
not set, load it from the file. not set, load it from the file.
@@ -205,6 +224,8 @@ class Tokenizer():
self.theHandle = theHandle self.theHandle = theHandle
self.theItem = self.theProject.projTree[theHandle] self.theItem = self.theProject.projTree[theHandle]
if self.theItem is None:
return
if theText is not None: if theText is not None:
# If the text is set, just use that # If the text is set, just use that
@@ -319,7 +340,7 @@ class Tokenizer():
elif aLine[:2] == "# ": elif aLine[:2] == "# ":
self.theTokens.append(( 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) tmpMarkdown.append("%s\n" % aLine)
@@ -386,8 +407,8 @@ class Tokenizer():
if self.isNone or self.isNote: if self.isNone or self.isNote:
return return
# For novel files, we need to handle chapter numbering and scene # For novel files, we need to handle chapter numbering, scene
# breaks # numbering, and scene breaks
if self.isNovel: if self.isNovel:
for n in range(len(self.theTokens)): for n in range(len(self.theTokens)):
@@ -504,7 +525,7 @@ class Tokenizer():
) )
else: else:
self.theTokens[n] = ( self.theTokens[n] = (
tType, tText, tFormat, self.A_PBB | self.A_CENTRE tType, tText, tFormat, self.A_PBB | self.A_CENTRE
) )
else: else:
self.theTokens[n] = ( self.theTokens[n] = (
+77 -63
View File
@@ -34,7 +34,7 @@ from time import time
from PyQt5.QtCore import Qt, QByteArray from PyQt5.QtCore import Qt, QByteArray
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QTextOption, QPalette, QColor, QTextDocumentWriter QTextOption, QPalette, QColor, QTextDocumentWriter, QFont
) )
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel, QDialog, QVBoxLayout, QHBoxLayout, QTextBrowser, QPushButton, QLabel,
@@ -44,7 +44,7 @@ from PyQt5.QtWidgets import (
from nw.gui.additions import QSwitch from nw.gui.additions import QSwitch
from nw.core import ToHtml from nw.core import ToHtml
from nw.constants import ( from nw.constants import (
nwConst, nwFiles, nwAlert, nwItemType, nwItemLayout, nwItemClass nwAlert, nwItemType, nwItemLayout, nwItemClass
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -69,10 +69,9 @@ class GuiBuildNovel(QDialog):
self.theTheme = theParent.theTheme self.theTheme = theParent.theTheme
self.optState = self.theProject.optState self.optState = self.theProject.optState
self.htmlText = [] # List of html document self.htmlText = [] # List of html document
self.htmlStyle = [] # List of html styles self.htmlStyle = [] # List of html styles
self.nwdText = [] # List of markdown documents self.nwdText = [] # List of markdown documents
self.textLayout = [] # List of nwItemLayout entries
self.setWindowTitle("Build Novel Project") self.setWindowTitle("Build Novel Project")
self.setMinimumWidth(800) self.setMinimumWidth(800)
@@ -323,10 +322,21 @@ class GuiBuildNovel(QDialog):
self.htmlText = [] self.htmlText = []
self.htmlStyle = [] self.htmlStyle = []
self.nwdText = [] self.nwdText = []
self.textLayout = []
for nItt, tItem in enumerate(self.theProject.projTree): 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.setText(tItem.itemHandle)
makeHtml.doAutoReplace() makeHtml.doAutoReplace()
makeHtml.tokenizeText() makeHtml.tokenizeText()
@@ -335,7 +345,6 @@ class GuiBuildNovel(QDialog):
makeHtml.doPostProcessing() makeHtml.doPostProcessing()
self.htmlText.append(makeHtml.getResult()) self.htmlText.append(makeHtml.getResult())
self.nwdText.append(makeHtml.getFilteredMarkdown()) self.nwdText.append(makeHtml.getFilteredMarkdown())
self.textLayout.append(tItem.itemLayout)
# Update progress bar, also for skipped items # Update progress bar, also for skipped items
self.buildProgress.setValue(nItt+1) self.buildProgress.setValue(nItt+1)
@@ -461,61 +470,53 @@ class GuiBuildNovel(QDialog):
return False return False
# Do the actual writing # Do the actual writing
wSuccess = False
errMsg = ""
if outTool == "Qt": if outTool == "Qt":
docWriter = QTextDocumentWriter() docWriter = QTextDocumentWriter()
docWriter.setFileName(savePath) docWriter.setFileName(savePath)
docWriter.setFormat(byteFmt) docWriter.setFormat(byteFmt)
if docWriter.write(self.docView.qDocument): wSuccess = 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
)
elif outTool == "NW": elif outTool == "NW":
try: try:
with open(savePath, mode="w", encoding="utf8") as outFile: with open(savePath, mode="w", encoding="utf8") as outFile:
if theFormat == self.FMT_HTM: if theFormat == self.FMT_HTM:
# Write novelWriter HTML data # Write novelWriter HTML data
outFile.write("<!DOCTYPE html>\n") theStyle = self.htmlStyle.copy()
outFile.write("<html>\n") theStyle.append(r"article {width: 800px; margin: 40px auto;}")
outFile.write("<head>\n") theHtml = (
outFile.write("<meta charset='utf-8'>\n") "<!DOCTYPE html>\n"
outFile.write("</head>\n") "<html>\n"
outFile.write("<style>\n") "<head>\n"
outFile.write("%s\n" % "\n".join(self.htmlStyle)) "<meta charset='utf-8'>\n"
outFile.write("</style>\n") "<title>{projTitle:s}</title>\n"
outFile.write("<body>\n") "</head>\n"
outFile.write("<article style='width: 800px; margin: 40px auto'>\n") "<style>\n"
for aLine in self.htmlText: "{htmlStyle:s}\n"
outFile.write(aLine) "</style>\n"
outFile.write("</article>\n") "<body>\n"
outFile.write("</body>\n") "<article>\n"
outFile.write("</html>\n") "{bodyText:s}\n"
"</article>\n"
"</body>\n"
"</html>\n"
).format(
projTitle = self.theProject.projName,
htmlStyle = "\n".join(theStyle),
bodyText = "".join(self.htmlText),
)
outFile.write(theHtml)
elif theFormat == self.FMT_NWD: elif theFormat == self.FMT_NWD:
# Write novelWriter markdown data # Write novelWriter markdown data
for aLine in self.nwdText: for aLine in self.nwdText:
outFile.write(aLine) outFile.write(aLine)
self.theParent.makeAlert( wSuccess = True
"Document successfully written in %s format to file: %s" % (
textFmt, savePath
), nwAlert.INFO
)
except Exception as e: except Exception as e:
self.theParent.makeAlert( errMsg = str(e)
"Failed to write document in %s format to file: %s" % (
textFmt, str(e)
), nwAlert.ERROR
)
elif outTool == "QtPrint" and theFormat == self.FMT_PDF: elif outTool == "QtPrint" and theFormat == self.FMT_PDF:
try: try:
@@ -527,23 +528,29 @@ class GuiBuildNovel(QDialog):
thePrinter.setColorMode(QPrinter.Color) thePrinter.setColorMode(QPrinter.Color)
thePrinter.setOutputFileName(savePath) thePrinter.setOutputFileName(savePath)
self.docView.qDocument.print(thePrinter) self.docView.qDocument.print(thePrinter)
self.theParent.makeAlert( wSuccess = True
"Document successfully written in %s format to file: %s" % (
textFmt, savePath
), nwAlert.INFO
)
except Exception as e: except Exception as e:
self.theParent.makeAlert( errMsg - str(e)
"Failed to write document in %s format to file: %s" % (
textFmt, str(e)
), nwAlert.ERROR
)
else: else:
return False errMsg = "Unknown format"
return True # Report to user
if wSuccess:
self.theParent.makeAlert(
"%s file successfully written to:<br> %s" % (
textFmt, savePath
), nwAlert.INFO
)
else:
self.theParent.makeAlert(
"Failed to write %s file. %s" % (
textFmt, errMsg
), nwAlert.ERROR
)
return wSuccess
def _printDocument(self): def _printDocument(self):
"""Open the print preview dialog. """Open the print preview dialog.
@@ -557,7 +564,6 @@ class GuiBuildNovel(QDialog):
"""Connect the print preview painter to the document viewer. """Connect the print preview painter to the document viewer.
""" """
thePrinter.setOrientation(QPrinter.Portrait) thePrinter.setOrientation(QPrinter.Portrait)
thePrinter.setOutputFormat(QPrinter.NativeFormat | QPrinter.PdfFormat)
self.docView.qDocument.print(thePrinter) self.docView.qDocument.print(thePrinter)
return return
@@ -646,6 +652,14 @@ class GuiBuildNovelDocView(QTextBrowser):
self.qDocument = self.document() self.qDocument = self.document()
self.qDocument.setDocumentMargin(self.mainConf.textMargin) 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() theOpt = QTextOption()
if self.mainConf.doJustify: if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify) theOpt.setAlignment(Qt.AlignJustify)
@@ -667,10 +681,10 @@ class GuiBuildNovelDocView(QTextBrowser):
def setContent(self, theText): def setContent(self, theText):
"""Set the content, either from text or list of text. """Set the content, either from text or list of text.
""" """
if isinstance(theText, str): if isinstance(theText, list):
self.setHtml(theText) theText = "".join(theText)
else: theText = theText.replace("&emsp;","&nbsp;"*4)
self.setHtml("".join(theText)) self.setHtml(theText)
return return
def setStyleSheet(self, theStyles=[]): def setStyleSheet(self, theStyles=[]):
+4 -4
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.5.2" hexVersion="0x000502f0" fileVersion="1.0" saveCount="145" autoCount="18" timeStamp="2020-05-23 19:28:41"> <novelWriterXML appVersion="0.5.2" hexVersion="0x000502f0" fileVersion="1.0" saveCount="158" autoCount="21" timeStamp="2020-05-23 21:12:53">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
@@ -20,12 +20,12 @@
</autoReplace> </autoReplace>
<titleFormat> <titleFormat>
<title>%title%</title> <title>%title%</title>
<chapter>Chapter %chnum%.\\%title%</chapter> <chapter>Chapter %chnum%: %title%</chapter>
<unnumbered>%title%</unnumbered> <unnumbered>%title%</unnumbered>
<scene>Scene %chnum%.%scnum%: %title%</scene> <scene>* * *</scene>
<section></section> <section></section>
<withSynopsis>True</withSynopsis> <withSynopsis>True</withSynopsis>
<withComments>False</withComments> <withComments>True</withComments>
<withKeywords>False</withKeywords> <withKeywords>False</withKeywords>
</titleFormat> </titleFormat>
<status> <status>