Use preview document class for manuscript preview

This commit is contained in:
Veronica Berglyd Olsen
2024-05-24 18:52:18 +02:00
parent c97a070e98
commit 6cc046c65c
6 changed files with 160 additions and 101 deletions
+1 -1
View File
@@ -99,7 +99,7 @@ class nwHeaders:
H_VALID = ("H0", "H1", "H2", "H3", "H4") H_VALID = ("H0", "H1", "H2", "H3", "H4")
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4} H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
H_SIZES = {0: 1.00, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25} H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
class nwFiles: class nwFiles:
+25
View File
@@ -39,6 +39,7 @@ from novelwriter.core.tohtml import ToHtml
from novelwriter.core.tokenizer import Tokenizer from novelwriter.core.tokenizer import Tokenizer
from novelwriter.core.tomarkdown import ToMarkdown from novelwriter.core.tomarkdown import ToMarkdown
from novelwriter.core.toodt import ToOdt from novelwriter.core.toodt import ToOdt
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.enum import nwBuildFmt from novelwriter.enum import nwBuildFmt
from novelwriter.error import formatException, logException from novelwriter.error import formatException, logException
@@ -134,6 +135,30 @@ class NWBuildDocument:
self._queue.append(item.itemHandle) self._queue.append(item.itemHandle)
return return
def iterBuildPreview(self, theme: TextDocumentTheme) -> Iterable[tuple[int, bool]]:
"""Build a preview QTextDocument."""
makeObj = ToQTextDocument(self._project)
filtered = self._setupBuild(makeObj)
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
if filtered.get(tHandle, (False, 0))[0]:
yield i, self._doBuild(makeObj, tHandle)
else:
yield i, False
makeObj.appendFootnotes()
self._error = None
self._cache = makeObj
return
def iterBuild(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]: def iterBuild(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]:
"""Wrapper for builders based on format.""" """Wrapper for builders based on format."""
if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT): if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT):
+77 -53
View File
@@ -26,18 +26,17 @@ from __future__ import annotations
import logging import logging
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QFont, QFontMetrics, QTextBlockFormat, QTextCharFormat, QTextCursor, QColor, QFont, QFontMetrics, QTextBlockFormat, QTextCharFormat,
QTextDocument QTextCursor, QTextDocument
) )
from novelwriter import SHARED
from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nwUnicode from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nwUnicode
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import T_Formats, Tokenizer from novelwriter.core.tokenizer import T_Formats, Tokenizer
from novelwriter.types import ( from novelwriter.types import (
QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, QtPageBreakAfter, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, QtBlack,
QtPageBreakBefore, QtTransparent, QtVAlignNormal, QtVAlignSub, QtPageBreakAfter, QtPageBreakBefore, QtTransparent, QtVAlignNormal,
QtVAlignSuper QtVAlignSub, QtVAlignSuper
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -45,6 +44,19 @@ logger = logging.getLogger(__name__)
T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat] T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
class TextDocumentTheme:
text: QColor = QtBlack
highlight: QColor = QtTransparent
head: QColor = QtBlack
comment: QColor = QtBlack
note: QColor = QtBlack
code: QColor = QtBlack
modifier: QColor = QtBlack
keyword: QColor = QtBlack
tag: QColor = QtBlack
optional: QColor = QtBlack
def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None: def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None:
if cursor.position() > 0: if cursor.position() > 0:
cursor.insertBlock(bFmt) cursor.insertBlock(bFmt)
@@ -64,6 +76,7 @@ class ToQTextDocument(Tokenizer):
self._document = QTextDocument() self._document = QTextDocument()
self._document.setUndoRedoEnabled(False) self._document.setUndoRedoEnabled(False)
self._theme = TextDocumentTheme()
self._styles: dict[int, T_TextStyle] = {} self._styles: dict[int, T_TextStyle] = {}
self._usedNotes: dict[str, int] = {} self._usedNotes: dict[str, int] = {}
@@ -73,9 +86,10 @@ class ToQTextDocument(Tokenizer):
return return
def initDocument(self, font: QFont) -> None: def initDocument(self, font: QFont, theme: TextDocumentTheme) -> None:
"""Initialise all computed values of the document.""" """Initialise all computed values of the document."""
self._textFont = font self._textFont = font
self._theme = theme
self._document.setUndoRedoEnabled(False) self._document.setUndoRedoEnabled(False)
self._document.blockSignals(True) self._document.blockSignals(True)
@@ -95,7 +109,7 @@ class ToQTextDocument(Tokenizer):
} }
self._sHead = { self._sHead = {
self.T_TITLE: nwHeaders.H_SIZES.get(1, 1.0) * fPt, self.T_TITLE: nwHeaders.H_SIZES.get(0, 1.0) * fPt,
self.T_HEAD1: nwHeaders.H_SIZES.get(1, 1.0) * fPt, self.T_HEAD1: nwHeaders.H_SIZES.get(1, 1.0) * fPt,
self.T_HEAD2: nwHeaders.H_SIZES.get(2, 1.0) * fPt, self.T_HEAD2: nwHeaders.H_SIZES.get(2, 1.0) * fPt,
self.T_HEAD3: nwHeaders.H_SIZES.get(3, 1.0) * fPt, self.T_HEAD3: nwHeaders.H_SIZES.get(3, 1.0) * fPt,
@@ -107,33 +121,41 @@ class ToQTextDocument(Tokenizer):
self._mIndent = mScale * 2.0 self._mIndent = mScale * 2.0
self._defaultChar = QTextCharFormat() self._cText = QTextCharFormat()
self._defaultChar.setForeground(SHARED.theme.colText) self._cText.setForeground(self._theme.text)
self._comChar = QTextCharFormat() self._cHead = QTextCharFormat()
self._comChar.setForeground(SHARED.theme.colHidden) self._cHead.setForeground(self._theme.head)
self._noteChar = QTextCharFormat() self._cComment = QTextCharFormat()
self._noteChar.setForeground(SHARED.theme.colNote) self._cComment.setForeground(self._theme.comment)
self._codeChar = QTextCharFormat() self._cCommentMod = QTextCharFormat()
self._codeChar.setForeground(SHARED.theme.colCode) self._cCommentMod.setForeground(self._theme.comment)
self._cCommentMod.setFontWeight(self._bold)
self._modChar = QTextCharFormat() self._cNote = QTextCharFormat()
self._modChar.setForeground(SHARED.theme.colMod) self._cNote.setForeground(self._theme.note)
self._keyChar = QTextCharFormat() self._cCode = QTextCharFormat()
self._keyChar.setForeground(SHARED.theme.colKey) self._cCode.setForeground(self._theme.code)
self._tagChar = QTextCharFormat() self._cModifier = QTextCharFormat()
self._tagChar.setForeground(SHARED.theme.colTag) self._cModifier.setForeground(self._theme.modifier)
self._cModifier.setFontWeight(self._bold)
self._optChar = QTextCharFormat() self._cKeyword = QTextCharFormat()
self._optChar.setForeground(SHARED.theme.colOpt) self._cKeyword.setForeground(self._theme.keyword)
self._defaultBlock = QTextBlockFormat() self._cTag = QTextCharFormat()
self._defaultBlock.setTopMargin(self._mText[0]) self._cTag.setForeground(self._theme.tag)
self._defaultBlock.setBottomMargin(self._mText[1])
self._cOptional = QTextCharFormat()
self._cOptional.setForeground(self._theme.optional)
self._blockFmt = QTextBlockFormat()
self._blockFmt.setTopMargin(self._mText[0])
self._blockFmt.setBottomMargin(self._mText[1])
self._init = True self._init = True
@@ -159,11 +181,12 @@ class ToQTextDocument(Tokenizer):
self._document.blockSignals(True) self._document.blockSignals(True)
cursor = QTextCursor(self._document) cursor = QTextCursor(self._document)
cursor.movePosition(QTextCursor.MoveOperation.End)
for tType, nHead, tText, tFormat, tStyle in self._tokens: for tType, nHead, tText, tFormat, tStyle in self._tokens:
# Styles # Styles
bFmt = QTextBlockFormat(self._defaultBlock) bFmt = QTextBlockFormat(self._blockFmt)
if tStyle is not None: if tStyle is not None:
if tStyle & self.A_LEFT: if tStyle & self.A_LEFT:
bFmt.setAlignment(QtAlignLeft) bFmt.setAlignment(QtAlignLeft)
@@ -191,7 +214,7 @@ class ToQTextDocument(Tokenizer):
if tType == self.T_TEXT: if tType == self.T_TEXT:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
self._insertFragments(tText, tFormat, cursor, self._defaultChar) self._insertFragments(tText, tFormat, cursor, self._cText)
elif tType in self.L_HEADINGS: elif tType in self.L_HEADINGS:
bFmt, cFmt = self._genHeadStyle(tType, nHead, bFmt) bFmt, cFmt = self._genHeadStyle(tType, nHead, bFmt)
@@ -200,23 +223,25 @@ class ToQTextDocument(Tokenizer):
elif tType == self.T_SEP: elif tType == self.T_SEP:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
cursor.insertText(tText, self._defaultChar) cursor.insertText(tText, self._cText)
elif tType == self.T_SKIP: elif tType == self.T_SKIP:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
cursor.insertText(nwUnicode.U_NBSP, self._defaultChar) cursor.insertText(nwUnicode.U_NBSP, self._cText)
elif tType in self.L_SUMMARY and self._doSynopsis: elif tType in self.L_SUMMARY and self._doSynopsis:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
prefix = self._localLookup( modifier = self._localLookup(
"Short Description" if tType == self.T_SHORT else "Synopsis" "Short Description" if tType == self.T_SHORT else "Synopsis"
) )
cursor.insertText(f"{prefix}: ", self._modChar) cursor.insertText(f"{modifier}: ", self._cModifier)
self._insertFragments(tText, tFormat, cursor, self._noteChar) self._insertFragments(tText, tFormat, cursor, self._cNote)
elif tType == self.T_COMMENT and self._doComments: elif tType == self.T_COMMENT and self._doComments:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
self._insertFragments(tText, tFormat, cursor, self._comChar) modifier = self._localLookup("Comment")
cursor.insertText(f"{modifier}: ", self._cCommentMod)
self._insertFragments(tText, tFormat, cursor, self._cComment)
elif tType == self.T_KEYWORD and self._doKeywords: elif tType == self.T_KEYWORD and self._doKeywords:
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
@@ -234,18 +259,18 @@ class ToQTextDocument(Tokenizer):
cursor = QTextCursor(self._document) cursor = QTextCursor(self._document)
cursor.movePosition(QTextCursor.MoveOperation.End) cursor.movePosition(QTextCursor.MoveOperation.End)
bFmt, cFmt = self._genHeadStyle(self.T_HEAD3, -1, self._defaultBlock) bFmt, cFmt = self._genHeadStyle(self.T_HEAD3, -1, self._blockFmt)
newBlock(cursor, bFmt) newBlock(cursor, bFmt)
cursor.insertText(self._localLookup("Footnotes"), cFmt) cursor.insertText(self._localLookup("Footnotes"), cFmt)
for key, index in self._usedNotes.items(): for key, index in self._usedNotes.items():
if content := self._footnotes.get(key): if content := self._footnotes.get(key):
cFmt = QTextCharFormat(self._codeChar) cFmt = QTextCharFormat(self._cCode)
cFmt.setAnchor(True) cFmt.setAnchor(True)
cFmt.setAnchorNames([f"footnote_{index}"]) cFmt.setAnchorNames([f"footnote_{index}"])
newBlock(cursor, self._defaultBlock) newBlock(cursor, self._blockFmt)
cursor.insertText(f"{index}. ", cFmt) cursor.insertText(f"{index}. ", cFmt)
self._insertFragments(*content, cursor, self._defaultChar) self._insertFragments(*content, cursor, self._cText)
self._document.blockSignals(False) self._document.blockSignals(False)
@@ -285,7 +310,7 @@ class ToQTextDocument(Tokenizer):
elif fmt == self.FMT_U_E: elif fmt == self.FMT_U_E:
cFmt.setFontUnderline(False) cFmt.setFontUnderline(False)
elif fmt == self.FMT_M_B: elif fmt == self.FMT_M_B:
cFmt.setBackground(SHARED.theme.colMark) cFmt.setBackground(self._theme.highlight)
elif fmt == self.FMT_M_E: elif fmt == self.FMT_M_E:
cFmt.setBackground(QtTransparent) cFmt.setBackground(QtTransparent)
elif fmt == self.FMT_SUP_B: elif fmt == self.FMT_SUP_B:
@@ -297,7 +322,7 @@ class ToQTextDocument(Tokenizer):
elif fmt == self.FMT_SUB_E: elif fmt == self.FMT_SUB_E:
cFmt.setVerticalAlignment(QtVAlignNormal) cFmt.setVerticalAlignment(QtVAlignNormal)
elif fmt == self.FMT_FNOTE: elif fmt == self.FMT_FNOTE:
xFmt = QTextCharFormat(self._codeChar) xFmt = QTextCharFormat(self._cCode)
xFmt.setVerticalAlignment(QtVAlignSuper) xFmt.setVerticalAlignment(QtVAlignSuper)
if data in self._footnotes: if data in self._footnotes:
index = len(self._usedNotes) + 1 index = len(self._usedNotes) + 1
@@ -322,37 +347,36 @@ class ToQTextDocument(Tokenizer):
valid, bits, _ = self._project.index.scanThis("@"+text) valid, bits, _ = self._project.index.scanThis("@"+text)
if valid and bits: if valid and bits:
key = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: " key = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
cursor.insertText(key, self._keyChar) cursor.insertText(key, self._cKeyword)
if (num := len(bits)) > 1: if (num := len(bits)) > 1:
if bits[0] == nwKeyWords.TAG_KEY: if bits[0] == nwKeyWords.TAG_KEY:
one, two = self._project.index.parseValue(bits[1]) one, two = self._project.index.parseValue(bits[1])
cursor.insertText(one, self._tagChar) cursor.insertText(one, self._cTag)
if two: if two:
cursor.insertText(" | ", self._defaultChar) cursor.insertText(" | ", self._cText)
cursor.insertText(two, self._optChar) cursor.insertText(two, self._cOptional)
else: else:
for n, bit in enumerate(bits[1:], 2): for n, bit in enumerate(bits[1:], 2):
cFmt = QTextCharFormat(self._tagChar) cFmt = QTextCharFormat(self._cTag)
cFmt.setFontUnderline(True) cFmt.setFontUnderline(True)
cFmt.setAnchor(True) cFmt.setAnchor(True)
cFmt.setAnchorHref(f"#{bits[0][1:]}={bit}") cFmt.setAnchorHref(f"#{bits[0][1:]}={bit}")
cursor.insertText(bit, cFmt) cursor.insertText(bit, cFmt)
if n < num: if n < num:
cursor.insertText(", ", self._defaultChar) cursor.insertText(", ", self._cText)
return return
def _genHeadStyle(self, level: int, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle: def _genHeadStyle(self, hType: int, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle:
"""Generate a heading style set.""" """Generate a heading style set."""
mTop, mBottom = self._mHead.get(level, (0.0, 0.0)) mTop, mBottom = self._mHead.get(hType, (0.0, 0.0))
bFmt = QTextBlockFormat(rFmt) bFmt = QTextBlockFormat(rFmt)
bFmt.setTopMargin(mTop) bFmt.setTopMargin(mTop)
bFmt.setBottomMargin(mBottom) bFmt.setBottomMargin(mBottom)
cFmt = QTextCharFormat(self._defaultChar) cFmt = QTextCharFormat(self._cText if hType == self.T_TITLE else self._cHead)
cFmt.setForeground(SHARED.theme.colHead) cFmt.setFontWeight(self._bold)
cFmt.setFontWeight(QFont.Weight.Bold) cFmt.setFontPointSize(self._sHead.get(hType, 1.0))
cFmt.setFontPointSize(self._sHead.get(level, 1.0))
if nHead >= 0: if nHead >= 0:
cFmt.setAnchorNames([f"{self._handle}:T{nHead:04d}"]) cFmt.setAnchorNames([f"{self._handle}:T{nHead:04d}"])
cFmt.setAnchor(True) cFmt.setAnchor(True)
+14 -3
View File
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import cssCol from novelwriter.common import cssCol
from novelwriter.constants import nwHeaders, nwUnicode from novelwriter.constants import nwHeaders, nwUnicode
from novelwriter.core.toqdoc import ToQTextDocument from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType from novelwriter.enum import nwDocAction, nwDocMode, nwItemType
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.extensions.eventfilters import WheelEventFilter from novelwriter.extensions.eventfilters import WheelEventFilter
@@ -69,6 +69,7 @@ class GuiDocViewer(QTextBrowser):
# Internal Variables # Internal Variables
self._docHandle = None self._docHandle = None
self._docTheme = TextDocumentTheme()
# Settings # Settings
self.setMinimumWidth(CONFIG.pxInt(300)) self.setMinimumWidth(CONFIG.pxInt(300))
@@ -152,6 +153,17 @@ class GuiDocViewer(QTextBrowser):
docPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText) docPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText)
self.viewport().setPalette(docPalette) self.viewport().setPalette(docPalette)
self._docTheme.text = SHARED.theme.colText
self._docTheme.highlight = SHARED.theme.colMark
self._docTheme.head = SHARED.theme.colHead
self._docTheme.comment = SHARED.theme.colHidden
self._docTheme.note = SHARED.theme.colNote
self._docTheme.code = SHARED.theme.colCode
self._docTheme.modifier = SHARED.theme.colMod
self._docTheme.keyword = SHARED.theme.colKey
self._docTheme.tag = SHARED.theme.colTag
self._docTheme.optional = SHARED.theme.colOpt
self.docHeader.matchColours() self.docHeader.matchColours()
self.docFooter.matchColours() self.docFooter.matchColours()
@@ -203,11 +215,10 @@ class GuiDocViewer(QTextBrowser):
sPos = self.verticalScrollBar().value() sPos = self.verticalScrollBar().value()
qDoc = ToQTextDocument(SHARED.project) qDoc = ToQTextDocument(SHARED.project)
qDoc.initDocument(CONFIG.textFont) qDoc.initDocument(CONFIG.textFont, self._docTheme)
qDoc.setKeywords(True) qDoc.setKeywords(True)
qDoc.setComments(CONFIG.viewComments) qDoc.setComments(CONFIG.viewComments)
qDoc.setSynopsis(CONFIG.viewSynopsis) qDoc.setSynopsis(CONFIG.viewSynopsis)
qDoc.setLinkHeadings(True)
# Be extra careful here to prevent crashes when first opening a # Be extra careful here to prevent crashes when first opening a
# project as a crash here leaves no way of recovering. # project as a crash here leaves no way of recovering.
+42 -44
View File
@@ -31,7 +31,7 @@ from time import time
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent, QTextDocument
from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout, QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout,
@@ -44,8 +44,8 @@ from novelwriter import CONFIG, SHARED
from novelwriter.common import checkInt, fuzzyTime from novelwriter.common import checkInt, fuzzyTime
from novelwriter.core.buildsettings import BuildCollection, BuildSettings from novelwriter.core.buildsettings import BuildCollection, BuildSettings
from novelwriter.core.docbuild import NWBuildDocument from novelwriter.core.docbuild import NWBuildDocument
from novelwriter.core.tohtml import ToHtml
from novelwriter.core.tokenizer import HeadingFormatter from novelwriter.core.tokenizer import HeadingFormatter
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.extensions.circularprogress import NProgressCircle from novelwriter.extensions.circularprogress import NProgressCircle
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
@@ -250,19 +250,19 @@ class GuiManuscript(NToolDialog):
if selected in self._buildMap: if selected in self._buildMap:
self.buildList.setCurrentItem(self._buildMap[selected]) self.buildList.setCurrentItem(self._buildMap[selected])
logger.debug("Loading build cache") # logger.debug("Loading build cache")
cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json" # cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
if cache.is_file(): # if cache.is_file():
try: # try:
with open(cache, mode="r", encoding="utf-8") as fObj: # with open(cache, mode="r", encoding="utf-8") as fObj:
data = json.load(fObj) # data = json.load(fObj)
build = self._builds.getBuild(data.get("uuid", "")) # build = self._builds.getBuild(data.get("uuid", ""))
if isinstance(build, BuildSettings): # if isinstance(build, BuildSettings):
self._updatePreview(data, build) # self._updatePreview(data, build)
except Exception: # except Exception:
logger.error("Failed to load build cache") # logger.error("Failed to load build cache")
logException() # logException()
return # return
return return
@@ -345,29 +345,38 @@ class GuiManuscript(NToolDialog):
docBuild.setPreviewMode(True) docBuild.setPreviewMode(True)
docBuild.queueAll() docBuild.queueAll()
theme = TextDocumentTheme()
theme.text = QColor(0, 0, 0)
theme.highlight = QColor(255, 255, 166)
theme.head = QColor(66, 113, 174)
theme.comment = QColor(100, 100, 100)
theme.note = QColor(129, 55, 9)
theme.code = QColor(66, 113, 174)
theme.modifier = QColor(129, 55, 9)
theme.keyword = QColor(245, 135, 31)
theme.tag = QColor(66, 113, 174)
theme.optional = QColor(66, 113, 174)
self.docPreview.beginNewBuild(len(docBuild)) self.docPreview.beginNewBuild(len(docBuild))
for step, _ in docBuild.iterBuildHTML(None): for step, _ in docBuild.iterBuildPreview(theme):
self.docPreview.buildStep(step + 1) self.docPreview.buildStep(step + 1)
QApplication.processEvents() QApplication.processEvents()
buildObj = docBuild.lastBuild buildObj = docBuild.lastBuild
assert isinstance(buildObj, ToHtml) assert isinstance(buildObj, ToQTextDocument)
result = { data = {
"uuid": build.buildID, "uuid": build.buildID,
"time": int(time()), "time": int(time()),
"stats": buildObj.textStats, "stats": buildObj.textStats,
"outline": buildObj.textOutline, "outline": buildObj.textOutline,
"styles": buildObj.getStyleSheet(),
"html": buildObj.fullHTML,
} }
self._updatePreview(data, build, buildObj.document)
self._updatePreview(result, build)
logger.debug("Saving build cache") logger.debug("Saving build cache")
cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json" cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
try: try:
with open(cache, mode="w+", encoding="utf-8") as outFile: with open(cache, mode="w+", encoding="utf-8") as outFile:
outFile.write(json.dumps(result, indent=2)) outFile.write(json.dumps(data, indent=2))
except Exception: except Exception:
logger.error("Failed to save build cache") logger.error("Failed to save build cache")
logException() logException()
@@ -400,17 +409,14 @@ class GuiManuscript(NToolDialog):
# Internal Functions # Internal Functions
## ##
def _updatePreview(self, data: dict, build: BuildSettings) -> None: def _updatePreview(self, data: dict, build: BuildSettings, document: QTextDocument) -> None:
"""Update the preview widget and set relevant values.""" """Update the preview widget and set relevant values."""
textFont = QFont() font = QFont()
textFont.fromString(build.getStr("format.textFont")) font.fromString(build.getStr("format.textFont"))
self.docPreview.setTextFont(font)
self.docPreview.setContent(data) self.docPreview.setContent(data, document)
self.docPreview.setBuildName(build.name) self.docPreview.setBuildName(build.name)
self.docPreview.setTextFont(textFont) self.docPreview.setJustify(build.getBool("format.justifyText"))
self.docPreview.setJustify(
build.getBool("format.justifyText")
)
self.docStats.updateStats(data.get("stats", {})) self.docStats.updateStats(data.get("stats", {}))
self.buildOutline.updateOutline(data.get("outline", {})) self.buildOutline.updateOutline(data.get("outline", {}))
return return
@@ -848,30 +854,22 @@ class _PreviewWidget(QTextBrowser):
QApplication.processEvents() QApplication.processEvents()
return return
def setContent(self, data: dict) -> None: def setContent(self, data: dict, doc: QTextDocument) -> None:
"""Set the content of the preview widget.""" """Set the content of the preview widget."""
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
self.buildProgress.setCentreText(self.tr("Processing ...")) self.buildProgress.setCentreText(self.tr("Processing ..."))
QApplication.processEvents() QApplication.processEvents()
styles = "\n".join(data.get("styles", [])) doc.setDocumentMargin(CONFIG.getTextMargin())
self.document().setDefaultStyleSheet(styles) self.setDocument(doc)
html = "".join(data.get("html", []))
html = html.replace("\t", "!!tab!!")
self.setHtml(html)
QApplication.processEvents()
while self.find("!!tab!!"):
cursor = self.textCursor()
cursor.insertText("\t")
self._docTime = checkInt(data.get("time"), 0) self._docTime = checkInt(data.get("time"), 0)
self._updateBuildAge() self._updateBuildAge()
# Since we change the content while it may still be rendering, we mark # 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. # the document as dirty again to make sure it's re-rendered properly.
self.document().markContentsDirty(0, self.document().characterCount()) # self.document().markContentsDirty(0, self.document().characterCount())
self.buildProgress.setCentreText(self.tr("Done")) self.buildProgress.setCentreText(self.tr("Done"))
QApplication.restoreOverrideCursor() QApplication.restoreOverrideCursor()
+1
View File
@@ -56,6 +56,7 @@ QtPageBreakAfter = QTextFormat.PageBreakFlag.PageBreak_AlwaysAfter
# Qt Painter Types # Qt Painter Types
QtTransparent = QColor(0, 0, 0, 0) QtTransparent = QColor(0, 0, 0, 0)
QtBlack = QColor(0, 0, 0)
QtNoBrush = Qt.BrushStyle.NoBrush QtNoBrush = Qt.BrushStyle.NoBrush
QtNoPen = Qt.PenStyle.NoPen QtNoPen = Qt.PenStyle.NoPen
QtRoundCap = Qt.PenCapStyle.RoundCap QtRoundCap = Qt.PenCapStyle.RoundCap