Remove HTML preview mode and manuscript cache
This commit is contained in:
@@ -55,7 +55,7 @@ class NWBuildDocument:
|
||||
|
||||
__slots__ = (
|
||||
"_project", "_build", "_queue", "_error", "_cache", "_count",
|
||||
"_outline", "_preview"
|
||||
"_outline",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject, build: BuildSettings) -> None:
|
||||
@@ -66,7 +66,6 @@ class NWBuildDocument:
|
||||
self._cache = None
|
||||
self._count = False
|
||||
self._outline = False
|
||||
self._preview = False
|
||||
return
|
||||
|
||||
##
|
||||
@@ -100,15 +99,6 @@ class NWBuildDocument:
|
||||
self._outline = state
|
||||
return
|
||||
|
||||
def setPreviewMode(self, state: bool) -> None:
|
||||
"""Set the preview mode of the build. This also enables stats
|
||||
count and outline mode.
|
||||
"""
|
||||
self._preview = state
|
||||
self._outline = state
|
||||
self._count = state
|
||||
return
|
||||
|
||||
##
|
||||
# Special Methods
|
||||
##
|
||||
@@ -140,10 +130,12 @@ class NWBuildDocument:
|
||||
makeObj = ToQTextDocument(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
self._outline = True
|
||||
self._count = True
|
||||
|
||||
font = QFont()
|
||||
font.fromString(self._build.getStr("format.textFont"))
|
||||
|
||||
makeObj.setLinkHeadings(self._preview)
|
||||
makeObj.initDocument(font, theme)
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
@@ -207,8 +199,6 @@ class NWBuildDocument:
|
||||
makeObj = ToHtml(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
makeObj.setPreview(self._preview)
|
||||
makeObj.setLinkHeadings(self._preview)
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
@@ -218,7 +208,7 @@ class NWBuildDocument:
|
||||
|
||||
makeObj.appendFootnotes()
|
||||
|
||||
if not (self._build.getBool("html.preserveTabs") or self._preview):
|
||||
if not self._build.getBool("html.preserveTabs"):
|
||||
makeObj.replaceTabs()
|
||||
|
||||
self._error = None
|
||||
|
||||
+14
-55
@@ -38,24 +38,6 @@ from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
HTML4_TAGS = {
|
||||
Tokenizer.FMT_B_B: "<b>",
|
||||
Tokenizer.FMT_B_E: "</b>",
|
||||
Tokenizer.FMT_I_B: "<i>",
|
||||
Tokenizer.FMT_I_E: "</i>",
|
||||
Tokenizer.FMT_D_B: "<span style='text-decoration: line-through;'>",
|
||||
Tokenizer.FMT_D_E: "</span>",
|
||||
Tokenizer.FMT_U_B: "<u>",
|
||||
Tokenizer.FMT_U_E: "</u>",
|
||||
Tokenizer.FMT_M_B: "<mark>",
|
||||
Tokenizer.FMT_M_E: "</mark>",
|
||||
Tokenizer.FMT_SUP_B: "<sup>",
|
||||
Tokenizer.FMT_SUP_E: "</sup>",
|
||||
Tokenizer.FMT_SUB_B: "<sub>",
|
||||
Tokenizer.FMT_SUB_E: "</sub>",
|
||||
Tokenizer.FMT_STRIP: "",
|
||||
}
|
||||
|
||||
HTML5_TAGS = {
|
||||
Tokenizer.FMT_B_B: "<strong>",
|
||||
Tokenizer.FMT_B_E: "</strong>",
|
||||
@@ -82,14 +64,9 @@ class ToHtml(Tokenizer):
|
||||
also used by the Document Viewer, and Manuscript Build Preview.
|
||||
"""
|
||||
|
||||
M_PREVIEW = 0 # Tweak output for the DocViewer
|
||||
M_EXPORT = 1 # Tweak output for saving to HTML or printing
|
||||
M_EBOOK = 2 # Tweak output for converting to epub
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
|
||||
self._genMode = self.M_EXPORT
|
||||
self._cssStyles = True
|
||||
self._fullHTML: list[str] = []
|
||||
|
||||
@@ -112,11 +89,6 @@ class ToHtml(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setPreview(self, state: bool) -> None:
|
||||
"""Set to preview generator mode."""
|
||||
self._genMode = self.M_PREVIEW if state else self.M_EXPORT
|
||||
return
|
||||
|
||||
def setStyles(self, cssStyles: bool) -> None:
|
||||
"""Enable or disable CSS styling. Some elements may still have
|
||||
class tags.
|
||||
@@ -157,8 +129,7 @@ class ToHtml(Tokenizer):
|
||||
"""Convert the list of text tokens into an HTML document."""
|
||||
self._result = ""
|
||||
|
||||
hTags = HTML4_TAGS if self._genMode == self.M_PREVIEW else HTML5_TAGS
|
||||
if self._isNovel and self._genMode != self.M_PREVIEW:
|
||||
if self._isNovel:
|
||||
# For story files, we bump the titles one level up
|
||||
h1Cl = " class='title'"
|
||||
h1 = "h1"
|
||||
@@ -240,7 +211,7 @@ class ToHtml(Tokenizer):
|
||||
|
||||
# Process Text Type
|
||||
if tType == self.T_TEXT:
|
||||
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat, hTags)}</p>\n")
|
||||
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat)}</p>\n")
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
@@ -269,13 +240,13 @@ class ToHtml(Tokenizer):
|
||||
lines.append(f"<p class='skip'{hStyle}> </p>\n")
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat, hTags), True))
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), True))
|
||||
|
||||
elif tType == self.T_SHORT and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat, hTags), False))
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), False))
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
lines.append(self._formatComments(self._formatText(tText, tFormat, hTags)))
|
||||
lines.append(self._formatComments(self._formatText(tText, tFormat)))
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
tag, text = self._formatKeywords(tText)
|
||||
@@ -291,7 +262,6 @@ class ToHtml(Tokenizer):
|
||||
def appendFootnotes(self) -> None:
|
||||
"""Append the footnotes in the buffer."""
|
||||
if self._usedNotes:
|
||||
tags = HTML4_TAGS if self._genMode == self.M_PREVIEW else HTML5_TAGS
|
||||
footnotes = self._localLookup("Footnotes")
|
||||
|
||||
lines = []
|
||||
@@ -299,7 +269,7 @@ class ToHtml(Tokenizer):
|
||||
lines.append("<ol>\n")
|
||||
for key, index in self._usedNotes.items():
|
||||
if content := self._footnotes.get(key):
|
||||
text = self._formatText(*content, tags)
|
||||
text = self._formatText(*content)
|
||||
lines.append(f"<li id='footnote_{index}'><p>{text}</p></li>\n")
|
||||
lines.append("</ol>\n")
|
||||
|
||||
@@ -468,7 +438,7 @@ class ToHtml(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[int, str]) -> str:
|
||||
def _formatText(self, text: str, tFmt: T_Formats) -> str:
|
||||
"""Apply formatting tags to text."""
|
||||
temp = text
|
||||
for pos, fmt, data in reversed(tFmt):
|
||||
@@ -481,7 +451,7 @@ class ToHtml(Tokenizer):
|
||||
else:
|
||||
html = "<sup>ERR</sup>"
|
||||
else:
|
||||
html = tags.get(fmt, "ERR")
|
||||
html = HTML5_TAGS.get(fmt, "ERR")
|
||||
temp = f"{temp[:pos]}{html}{temp[pos:]}"
|
||||
temp = temp.replace("\n", "<br>")
|
||||
return stripEscape(temp)
|
||||
@@ -492,18 +462,12 @@ class ToHtml(Tokenizer):
|
||||
sSynop = self._localLookup("Synopsis")
|
||||
else:
|
||||
sSynop = self._localLookup("Short Description")
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
return f"<p class='note'><span class='modifier'>{sSynop}:</span> {text}</p>\n"
|
||||
else:
|
||||
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
|
||||
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatComments(self, text: str) -> str:
|
||||
"""Apply HTML formatting to comments."""
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
return f"<p class='comment'>{text}</p>\n"
|
||||
else:
|
||||
sComm = self._localLookup("Comment")
|
||||
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
|
||||
sComm = self._localLookup("Comment")
|
||||
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, str]:
|
||||
"""Apply HTML formatting to keywords."""
|
||||
@@ -519,13 +483,8 @@ class ToHtml(Tokenizer):
|
||||
if two:
|
||||
result += f" | <span class='optional'>{two}</a>"
|
||||
else:
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
result += ", ".join(
|
||||
f"<a class='tag' href='#{bits[0][1:]}={t}'>{t}</a>" for t in bits[1:]
|
||||
)
|
||||
else:
|
||||
result += ", ".join(
|
||||
f"<a class='tag' href='#tag_{t}'>{t}</a>" for t in bits[1:]
|
||||
)
|
||||
result += ", ".join(
|
||||
f"<a class='tag' href='#tag_{t}'>{t}</a>" for t in bits[1:]
|
||||
)
|
||||
|
||||
return bits[0][1:], result
|
||||
|
||||
@@ -23,10 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -41,12 +39,11 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import checkInt, fuzzyTime
|
||||
from novelwriter.common import fuzzyTime
|
||||
from novelwriter.core.buildsettings import BuildCollection, BuildSettings
|
||||
from novelwriter.core.docbuild import NWBuildDocument
|
||||
from novelwriter.core.tokenizer import HeadingFormatter
|
||||
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.extensions.circularprogress import NProgressCircle
|
||||
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
|
||||
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
|
||||
@@ -250,20 +247,6 @@ class GuiManuscript(NToolDialog):
|
||||
if selected in self._buildMap:
|
||||
self.buildList.setCurrentItem(self._buildMap[selected])
|
||||
|
||||
# logger.debug("Loading build cache")
|
||||
# cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
|
||||
# if cache.is_file():
|
||||
# try:
|
||||
# with open(cache, mode="r", encoding="utf-8") as fObj:
|
||||
# data = json.load(fObj)
|
||||
# build = self._builds.getBuild(data.get("uuid", ""))
|
||||
# if isinstance(build, BuildSettings):
|
||||
# self._updatePreview(data, build)
|
||||
# except Exception:
|
||||
# logger.error("Failed to load build cache")
|
||||
# logException()
|
||||
# return
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -342,7 +325,6 @@ class GuiManuscript(NToolDialog):
|
||||
SHARED.saveDocument()
|
||||
|
||||
docBuild = NWBuildDocument(SHARED.project, build)
|
||||
docBuild.setPreviewMode(True)
|
||||
docBuild.queueAll()
|
||||
|
||||
theme = TextDocumentTheme()
|
||||
@@ -364,23 +346,17 @@ class GuiManuscript(NToolDialog):
|
||||
|
||||
buildObj = docBuild.lastBuild
|
||||
assert isinstance(buildObj, ToQTextDocument)
|
||||
data = {
|
||||
"uuid": build.buildID,
|
||||
"time": int(time()),
|
||||
"stats": buildObj.textStats,
|
||||
"outline": buildObj.textOutline,
|
||||
}
|
||||
self._updatePreview(data, build, buildObj.document)
|
||||
|
||||
logger.debug("Saving build cache")
|
||||
cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
|
||||
try:
|
||||
with open(cache, mode="w+", encoding="utf-8") as outFile:
|
||||
outFile.write(json.dumps(data, indent=2))
|
||||
except Exception:
|
||||
logger.error("Failed to save build cache")
|
||||
logException()
|
||||
return
|
||||
font = QFont()
|
||||
font.fromString(build.getStr("format.textFont"))
|
||||
|
||||
self.docPreview.setTextFont(font)
|
||||
self.docPreview.setContent(buildObj.document)
|
||||
self.docPreview.setBuildName(build.name)
|
||||
self.docPreview.setJustify(build.getBool("format.justifyText"))
|
||||
|
||||
self.docStats.updateStats(buildObj.textStats)
|
||||
self.buildOutline.updateOutline(buildObj.textOutline)
|
||||
|
||||
return
|
||||
|
||||
@@ -409,18 +385,6 @@ class GuiManuscript(NToolDialog):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _updatePreview(self, data: dict, build: BuildSettings, document: QTextDocument) -> None:
|
||||
"""Update the preview widget and set relevant values."""
|
||||
font = QFont()
|
||||
font.fromString(build.getStr("format.textFont"))
|
||||
self.docPreview.setTextFont(font)
|
||||
self.docPreview.setContent(data, document)
|
||||
self.docPreview.setBuildName(build.name)
|
||||
self.docPreview.setJustify(build.getBool("format.justifyText"))
|
||||
self.docStats.updateStats(data.get("stats", {}))
|
||||
self.buildOutline.updateOutline(data.get("outline", {}))
|
||||
return
|
||||
|
||||
def _getSelectedBuild(self) -> BuildSettings | None:
|
||||
"""Get the currently selected build. If none are selected,
|
||||
automatically select the first one.
|
||||
@@ -854,23 +818,19 @@ class _PreviewWidget(QTextBrowser):
|
||||
QApplication.processEvents()
|
||||
return
|
||||
|
||||
def setContent(self, data: dict, doc: QTextDocument) -> None:
|
||||
def setContent(self, document: QTextDocument) -> None:
|
||||
"""Set the content of the preview widget."""
|
||||
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
||||
|
||||
self.buildProgress.setCentreText(self.tr("Processing ..."))
|
||||
QApplication.processEvents()
|
||||
|
||||
doc.setDocumentMargin(CONFIG.getTextMargin())
|
||||
self.setDocument(doc)
|
||||
document.setDocumentMargin(CONFIG.getTextMargin())
|
||||
self.setDocument(document)
|
||||
|
||||
self._docTime = checkInt(data.get("time"), 0)
|
||||
self._docTime = int(time())
|
||||
self._updateBuildAge()
|
||||
|
||||
# Since we change the content while it may still be rendering, we mark
|
||||
# the document as dirty again to make sure it's re-rendered properly.
|
||||
# self.document().markContentsDirty(0, self.document().characterCount())
|
||||
|
||||
self.buildProgress.setCentreText(self.tr("Done"))
|
||||
QApplication.restoreOverrideCursor()
|
||||
QApplication.processEvents()
|
||||
@@ -915,17 +875,14 @@ class _PreviewWidget(QTextBrowser):
|
||||
@pyqtSlot()
|
||||
def _updateBuildAge(self) -> None:
|
||||
"""Update the build time and the fuzzy age."""
|
||||
if self._docTime > 0:
|
||||
strBuildTime = "%s (%s)" % (
|
||||
CONFIG.localDateTime(datetime.fromtimestamp(self._docTime)),
|
||||
fuzzyTime(int(time()) - self._docTime)
|
||||
)
|
||||
if self._buildName and self._docTime > 0:
|
||||
self.ageLabel.setText("<b>{0}</b><br>{1}: {2}".format(
|
||||
self._buildName,
|
||||
self.tr("Built"),
|
||||
fuzzyTime(int(time()) - self._docTime),
|
||||
))
|
||||
else:
|
||||
strBuildTime = self.tr("Unknown")
|
||||
text = "{0}: {1}".format(self.tr("Built"), strBuildTime)
|
||||
if self._buildName:
|
||||
text = "<b>{0}</b><br>{1}".format(self._buildName, text)
|
||||
self.ageLabel.setText(text)
|
||||
self.ageLabel.setText("<b>{0}</b>".format(self.tr("No Preview")))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
|
||||
@@ -284,21 +284,6 @@ def testCoreToHtml_ConvertParagraphs(mockGUI):
|
||||
"</ol>\n"
|
||||
)
|
||||
|
||||
# Preview Mode
|
||||
# ============
|
||||
|
||||
html.setPreview(True)
|
||||
|
||||
# Text (HTML4)
|
||||
html._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||
html.tokenizeText()
|
||||
html.doConvert()
|
||||
assert html.result == (
|
||||
"<p>Some <b>nested bold and <i>italic</i> and "
|
||||
"<span style='text-decoration: line-through;'>strikethrough</span> "
|
||||
"text</b> here</p>\n"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToHtml_ConvertDirect(mockGUI):
|
||||
@@ -682,29 +667,3 @@ def testCoreToHtml_Format(mockGUI):
|
||||
"<a class='tag' href='#tag_Bod'>Bod</a>, "
|
||||
"<a class='tag' href='#tag_Jane'>Jane</a>"
|
||||
)
|
||||
|
||||
# Preview Mode
|
||||
# ============
|
||||
|
||||
html.setPreview(True)
|
||||
|
||||
assert html._formatSynopsis("synopsis text", True) == (
|
||||
"<p class='note'><span class='modifier'>Synopsis:</span> synopsis text</p>\n"
|
||||
)
|
||||
assert html._formatSynopsis("short text", False) == (
|
||||
"<p class='note'><span class='modifier'>Short Description:</span> short text</p>\n"
|
||||
)
|
||||
assert html._formatComments("comment text") == (
|
||||
"<p class='comment'>comment text</p>\n"
|
||||
)
|
||||
|
||||
assert html._formatKeywords("") == ("", "")
|
||||
assert html._formatKeywords("tag: Jane") == (
|
||||
"tag", "<span class='keyword'>Tag:</span> <a class='tag' name='tag_Jane'>Jane</a>"
|
||||
)
|
||||
assert html._formatKeywords("char: Bod, Jane") == (
|
||||
"char",
|
||||
"<span class='keyword'>Characters:</span> "
|
||||
"<a class='tag' href='#char=Bod'>Bod</a>, "
|
||||
"<a class='tag' href='#char=Jane'>Jane</a>"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user