Added note root headings, changed some formatting, and improved export
This commit is contained in:
+3
-3
@@ -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
@@ -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
@@ -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(" "," "*4)
|
||||||
self.setHtml("".join(theText))
|
self.setHtml(theText)
|
||||||
return
|
return
|
||||||
|
|
||||||
def setStyleSheet(self, theStyles=[]):
|
def setStyleSheet(self, theStyles=[]):
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user