From a4e3bf848b2d2e89aa9787e66eabb41b512aa03d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 24 May 2024 20:38:34 +0200 Subject: [PATCH] Clean up no longer needed code, and fix text justify setting --- novelwriter/core/toqdoc.py | 25 ++++++--- novelwriter/gui/doceditor.py | 18 ++----- novelwriter/gui/docviewer.py | 62 +++-------------------- novelwriter/tools/manuscript.py | 15 +----- tests/test_gui/test_gui_docviewer.py | 2 +- tests/test_tools/test_tools_manuscript.py | 55 +++++++------------- 6 files changed, 52 insertions(+), 125 deletions(-) diff --git a/novelwriter/core/toqdoc.py b/novelwriter/core/toqdoc.py index bfe4aa52..ee530fd8 100644 --- a/novelwriter/core/toqdoc.py +++ b/novelwriter/core/toqdoc.py @@ -34,9 +34,9 @@ from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nw from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import T_Formats, Tokenizer from novelwriter.types import ( - QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, QtBlack, - QtPageBreakAfter, QtPageBreakBefore, QtTransparent, QtVAlignNormal, - QtVAlignSub, QtVAlignSuper + QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight, + QtBlack, QtPageBreakAfter, QtPageBreakBefore, QtTransparent, + QtVAlignNormal, QtVAlignSub, QtVAlignSuper ) logger = logging.getLogger(__name__) @@ -75,6 +75,7 @@ class ToQTextDocument(Tokenizer): super().__init__(project) self._document = QTextDocument() self._document.setUndoRedoEnabled(False) + self._document.setDocumentMargin(0) self._theme = TextDocumentTheme() self._styles: dict[int, T_TextStyle] = {} @@ -100,6 +101,9 @@ class ToQTextDocument(Tokenizer): mScale = qMetric.height() fPt = self._textFont.pointSizeF() + # Scaled Sizes + # ============ + self._mHead = { self.T_TITLE: (mScale * self._marginTitle[0], mScale * self._marginTitle[1]), self.T_HEAD1: (mScale * self._marginHead1[0], mScale * self._marginHead1[1]), @@ -121,6 +125,17 @@ class ToQTextDocument(Tokenizer): self._mIndent = mScale * 2.0 + # Block Format + # ============ + + self._blockFmt = QTextBlockFormat() + self._blockFmt.setTopMargin(self._mText[0]) + self._blockFmt.setBottomMargin(self._mText[1]) + self._blockFmt.setAlignment(QtAlignJustify if self._doJustify else QtAlignAbsolute) + + # Character Formats + # ================= + self._cText = QTextCharFormat() self._cText.setForeground(self._theme.text) @@ -153,10 +168,6 @@ class ToQTextDocument(Tokenizer): 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 return diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 7fdbfdf9..6b16f021 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -321,8 +321,11 @@ class GuiDocEditor(QPlainTextEdit): # Reload spell check and dictionaries SHARED.updateSpellCheckLanguage() - # Set font - self.initFont() + # Set the font. See issues #1862 and #1875. + self.setFont(CONFIG.textFont) + self.docHeader.updateFont() + self.docFooter.updateFont() + self.docSearch.updateFont() # Update highlighter settings self._qDocument.syntaxHighlighter.initHighlighter() @@ -372,17 +375,6 @@ class GuiDocEditor(QPlainTextEdit): return - def initFont(self) -> None: - """Set the font of the main widget and sub-widgets. This needs - special attention since there appears to be a bug in Qt 5.15.3. - See issues #1862 and #1875. - """ - self.setFont(CONFIG.textFont) - self.docHeader.updateFont() - self.docFooter.updateFont() - self.docSearch.updateFont() - return - def loadText(self, tHandle: str, tLine: int | None = None) -> bool: """Load text from a document into the editor. If we have an I/O error, we must handle this and clear the editor so that we don't diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 4eda952c..cba386f5 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -31,14 +31,13 @@ import logging from enum import Enum from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot -from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor, QTextOption +from PyQt5.QtGui import QCursor, QMouseEvent, QPalette, QResizeEvent, QTextCursor from PyQt5.QtWidgets import ( QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, QToolButton, QWidget ) from novelwriter import CONFIG, SHARED -from novelwriter.common import cssCol from novelwriter.constants import nwHeaders, nwUnicode from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument from novelwriter.enum import nwDocAction, nwDocMode, nwItemType @@ -46,9 +45,7 @@ from novelwriter.error import logException from novelwriter.extensions.eventfilters import WheelEventFilter from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON -from novelwriter.types import ( - QtAlignCenterTop, QtAlignJustify, QtKeepAnchor, QtMouseLeft, QtMoveAnchor -) +from novelwriter.types import QtAlignCenterTop, QtKeepAnchor, QtMouseLeft, QtMoveAnchor logger = logging.getLogger(__name__) @@ -138,8 +135,10 @@ class GuiDocViewer(QTextBrowser): def initViewer(self) -> None: """Set editor settings from main config.""" - self._makeStyleSheet() - self.initFont() + # Set the font. See issues #1862 and #1875. + self.setFont(CONFIG.textFont) + self.docHeader.updateFont() + self.docFooter.updateFont() # Set the widget colours to match syntax theme mainPalette = self.palette() @@ -153,6 +152,7 @@ class GuiDocViewer(QTextBrowser): docPalette.setColor(QPalette.ColorRole.Text, SHARED.theme.colText) self.viewport().setPalette(docPalette) + # Update theme colours self._docTheme.text = SHARED.theme.colText self._docTheme.highlight = SHARED.theme.colMark self._docTheme.head = SHARED.theme.colHead @@ -169,10 +169,6 @@ class GuiDocViewer(QTextBrowser): # Set default text margins self.document().setDocumentMargin(0) - options = QTextOption() - if CONFIG.doJustify: - options.setAlignment(QtAlignJustify) - self.document().setDefaultTextOption(options) # Scroll bars if CONFIG.hideVScroll: @@ -193,16 +189,6 @@ class GuiDocViewer(QTextBrowser): return - def initFont(self) -> None: - """Set the font of the main widget and sub-widgets. This needs - special attention since there appears to be a bug in Qt 5.15.3. - See issues #1862 and #1875. - """ - self.setFont(CONFIG.textFont) - self.docHeader.updateFont() - self.docFooter.updateFont() - return - def loadText(self, tHandle: str, updateHistory: bool = True) -> bool: """Load text into the viewer from an item handle.""" if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE): @@ -215,6 +201,7 @@ class GuiDocViewer(QTextBrowser): sPos = self.verticalScrollBar().value() qDoc = ToQTextDocument(SHARED.project) + qDoc.setJustify(CONFIG.doJustify) qDoc.initDocument(CONFIG.textFont, self._docTheme) qDoc.setKeywords(True) qDoc.setComments(CONFIG.viewComments) @@ -244,11 +231,6 @@ class GuiDocViewer(QTextBrowser): self.docHistory.append(tHandle) self.setDocumentTitle(tHandle) - - # Replace tabs before setting the HTML, and then put them back in - # self.setHtml(qDoc.result.replace("\t", "!!tab!!")) - # while self.find("!!tab!!"): - # self.textCursor().insertText("\t") self.setDocument(qDoc.document) if self._docHandle == tHandle: @@ -482,34 +464,6 @@ class GuiDocViewer(QTextBrowser): self._makeSelection(selType) return - def _makeStyleSheet(self) -> None: - """Generate an appropriate style sheet for the document viewer, - based on the current syntax highlighter theme. - """ - colHead = cssCol(SHARED.theme.colHead) - colHide = cssCol(SHARED.theme.colHidden) - colKeys = cssCol(SHARED.theme.colKey) - colMark = cssCol(SHARED.theme.colMark) - colMods = cssCol(SHARED.theme.colMod) - colNote = cssCol(SHARED.theme.colNote) - colOpts = cssCol(SHARED.theme.colOpt) - colTags = cssCol(SHARED.theme.colTag) - colText = cssCol(SHARED.theme.colText) - self.document().setDefaultStyleSheet( - f"body {{color: {colText};}}\n" - f"h1, h2, h3, h4 {{color: {colHead};}}\n" - f"mark {{background-color: {colMark};}}\n" - f".keyword {{color: {colKeys};}}\n" - f".tag {{color: {colTags};}}\n" - f".optional {{color: {colOpts};}}\n" - f".comment {{color: {colHide};}}\n" - f".note {{color: {colNote};}}\n" - f".modifier {{color: {colMods};}}\n" - ".title {text-align: center;}\n" - ) - - return - class GuiDocViewHistory: diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index d7da4cb0..263bf332 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -50,8 +50,8 @@ from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manussettings import GuiBuildSettings from novelwriter.types import ( - QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop, - QtSizeExpanding, QtSizeIgnored, QtUserRole + QtAlignCenter, QtAlignRight, QtAlignTop, QtSizeExpanding, QtSizeIgnored, + QtUserRole ) if TYPE_CHECKING: # pragma: no cover @@ -353,7 +353,6 @@ class GuiManuscript(NToolDialog): 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) @@ -777,16 +776,6 @@ class _PreviewWidget(QTextBrowser): self._updateBuildAge() return - def setJustify(self, state: bool) -> None: - """Enable/disable the justify text option.""" - pOptions = self.document().defaultTextOption() - if state: - pOptions.setAlignment(QtAlignJustify) - else: - pOptions.setAlignment(QtAlignAbsolute) - self.document().setDefaultTextOption(pOptions) - return - def setTextFont(self, font: QFont) -> None: """Set the text font properties and then reset for sub-widgets. This needs special attention since there appears to be a bug in diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py index 2fa287f6..72a71655 100644 --- a/tests/test_gui/test_gui_docviewer.py +++ b/tests/test_gui/test_gui_docviewer.py @@ -202,7 +202,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): # Document footer show/hide comments assert nwGUI.viewDocument("846352075de7d") is True - assert len(docViewer.toPlainText()) == 674 + assert len(docViewer.toPlainText()) == 683 docViewer.docFooter._doToggleComments(False) assert len(docViewer.toPlainText()) == 634 diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index 5d0c928c..383ff098 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -28,15 +28,14 @@ from PyQt5.QtCore import pyqtSlot from PyQt5.QtPrintSupport import QPrintPreviewDialog from PyQt5.QtWidgets import QAction, QListWidgetItem -from novelwriter import CONFIG, SHARED +from novelwriter import SHARED from novelwriter.constants import nwHeadFmt from novelwriter.core.buildsettings import BuildSettings from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manuscript import GuiManuscript from novelwriter.tools.manussettings import GuiBuildSettings -from novelwriter.types import QtAlignAbsolute, QtAlignJustify, QtDialogApply, QtDialogSave +from novelwriter.types import QtDialogApply, QtDialogSave -from tests.mocked import causeOSError from tests.tools import C, buildTestProject @@ -64,23 +63,23 @@ def testManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd): manus.close() - # A new dialog should load the old build - manus = GuiManuscript(nwGUI) - manus.show() - manus.loadContent() - assert manus.docPreview.toPlainText().strip() == allText - manus.close() + # # A new dialog should load the old build + # manus = GuiManuscript(nwGUI) + # manus.show() + # manus.loadContent() + # assert manus.docPreview.toPlainText().strip() == allText + # manus.close() - # But blocking the reload should leave it empty - with monkeypatch.context() as mp: - mp.setattr("builtins.open", lambda *a, **k: causeOSError) - manus = GuiManuscript(nwGUI) - manus.show() - manus.loadContent() - assert manus.docPreview.toPlainText().strip() == "" + # # But blocking the reload should leave it empty + # with monkeypatch.context() as mp: + # mp.setattr("builtins.open", lambda *a, **k: causeOSError) + # manus = GuiManuscript(nwGUI) + # manus.show() + # manus.loadContent() + # assert manus.docPreview.toPlainText().strip() == "" - nwGUI.closeProject() # This should auto-close the manuscript tool - assert manus.isHidden() + # nwGUI.closeProject() # This should auto-close the manuscript tool + # assert manus.isHidden() # qtbot.stop() @@ -186,7 +185,6 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd): manus.show() manus.loadContent() - cacheFile = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json" manus.buildList.setCurrentRow(0) build = manus._getSelectedBuild() assert isinstance(build, BuildSettings) @@ -199,17 +197,9 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd): manus.btnPreview.click() qtbot.wait(200) # Should be enough to run the build assert manus.docPreview.toPlainText().strip() == "" - assert cacheFile.exists() is False manus._updateBuildsList() - # Preview the first, but fail to save cache - manus.buildList.setCurrentRow(0) - with monkeypatch.context() as mp: - mp.setattr("builtins.open", lambda *a, **k: causeOSError) - with qtbot.waitSignal(manus.docPreview.document().contentsChanged): - manus.btnPreview.click() - assert cacheFile.exists() is False - + # Preview the first first = manus.buildList.item(0) assert isinstance(first, QListWidgetItem) build = manus._builds.getBuild(first.data(GuiManuscript.D_KEY)) @@ -218,12 +208,10 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd): build.setValue("headings.fmtAltScene", nwHeadFmt.TITLE) manus._builds.setBuild(build) - # Preview again, and allow cache file to be created manus.buildList.setCurrentRow(0) with qtbot.waitSignal(manus.docPreview.document().contentsChanged): manus.btnPreview.click() assert manus.docPreview.toPlainText().strip() != "" - assert cacheFile.exists() is True # Check Outline assert manus.buildOutline._outline == { @@ -265,13 +253,6 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd): assert manus.docStats.maxTotalWords.text() == "25" assert manus.docStats.maxTotalChars.text() == "117" - # Toggle justify - assert manus.docPreview.document().defaultTextOption().alignment() == QtAlignAbsolute - manus.docPreview.setJustify(True) - assert manus.docPreview.document().defaultTextOption().alignment() == QtAlignJustify - manus.docPreview.setJustify(False) - assert manus.docPreview.document().defaultTextOption().alignment() == QtAlignAbsolute - # Tests are too fast to trigger this one, so we trigger it manually to ensure it isn't failing manus.docPreview._postUpdate()