Clean up no longer needed code, and fix text justify setting

This commit is contained in:
Veronica Berglyd Olsen
2024-05-24 20:38:34 +02:00
parent e74c1057a4
commit a4e3bf848b
6 changed files with 52 additions and 125 deletions
+18 -7
View File
@@ -34,9 +34,9 @@ from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nw
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, QtBlack, QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
QtPageBreakAfter, QtPageBreakBefore, QtTransparent, QtVAlignNormal, QtBlack, QtPageBreakAfter, QtPageBreakBefore, QtTransparent,
QtVAlignSub, QtVAlignSuper QtVAlignNormal, QtVAlignSub, QtVAlignSuper
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -75,6 +75,7 @@ class ToQTextDocument(Tokenizer):
super().__init__(project) super().__init__(project)
self._document = QTextDocument() self._document = QTextDocument()
self._document.setUndoRedoEnabled(False) self._document.setUndoRedoEnabled(False)
self._document.setDocumentMargin(0)
self._theme = TextDocumentTheme() self._theme = TextDocumentTheme()
self._styles: dict[int, T_TextStyle] = {} self._styles: dict[int, T_TextStyle] = {}
@@ -100,6 +101,9 @@ class ToQTextDocument(Tokenizer):
mScale = qMetric.height() mScale = qMetric.height()
fPt = self._textFont.pointSizeF() fPt = self._textFont.pointSizeF()
# Scaled Sizes
# ============
self._mHead = { self._mHead = {
self.T_TITLE: (mScale * self._marginTitle[0], mScale * self._marginTitle[1]), self.T_TITLE: (mScale * self._marginTitle[0], mScale * self._marginTitle[1]),
self.T_HEAD1: (mScale * self._marginHead1[0], mScale * self._marginHead1[1]), self.T_HEAD1: (mScale * self._marginHead1[0], mScale * self._marginHead1[1]),
@@ -121,6 +125,17 @@ class ToQTextDocument(Tokenizer):
self._mIndent = mScale * 2.0 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 = QTextCharFormat()
self._cText.setForeground(self._theme.text) self._cText.setForeground(self._theme.text)
@@ -153,10 +168,6 @@ class ToQTextDocument(Tokenizer):
self._cOptional = QTextCharFormat() self._cOptional = QTextCharFormat()
self._cOptional.setForeground(self._theme.optional) 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
return return
+5 -13
View File
@@ -321,8 +321,11 @@ class GuiDocEditor(QPlainTextEdit):
# Reload spell check and dictionaries # Reload spell check and dictionaries
SHARED.updateSpellCheckLanguage() SHARED.updateSpellCheckLanguage()
# Set font # Set the font. See issues #1862 and #1875.
self.initFont() self.setFont(CONFIG.textFont)
self.docHeader.updateFont()
self.docFooter.updateFont()
self.docSearch.updateFont()
# Update highlighter settings # Update highlighter settings
self._qDocument.syntaxHighlighter.initHighlighter() self._qDocument.syntaxHighlighter.initHighlighter()
@@ -372,17 +375,6 @@ class GuiDocEditor(QPlainTextEdit):
return 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: def loadText(self, tHandle: str, tLine: int | None = None) -> bool:
"""Load text from a document into the editor. If we have an I/O """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 error, we must handle this and clear the editor so that we don't
+8 -54
View File
@@ -31,14 +31,13 @@ import logging
from enum import Enum from enum import Enum
from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot 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 ( from PyQt5.QtWidgets import (
QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser, QAction, QApplication, QFrame, QHBoxLayout, QLabel, QMenu, QTextBrowser,
QToolButton, QWidget QToolButton, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import cssCol
from novelwriter.constants import nwHeaders, nwUnicode from novelwriter.constants import nwHeaders, nwUnicode
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType 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.eventfilters import WheelEventFilter
from novelwriter.extensions.modified import NIconToolButton from novelwriter.extensions.modified import NIconToolButton
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
from novelwriter.types import ( from novelwriter.types import QtAlignCenterTop, QtKeepAnchor, QtMouseLeft, QtMoveAnchor
QtAlignCenterTop, QtAlignJustify, QtKeepAnchor, QtMouseLeft, QtMoveAnchor
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -138,8 +135,10 @@ class GuiDocViewer(QTextBrowser):
def initViewer(self) -> None: def initViewer(self) -> None:
"""Set editor settings from main config.""" """Set editor settings from main config."""
self._makeStyleSheet() # Set the font. See issues #1862 and #1875.
self.initFont() self.setFont(CONFIG.textFont)
self.docHeader.updateFont()
self.docFooter.updateFont()
# Set the widget colours to match syntax theme # Set the widget colours to match syntax theme
mainPalette = self.palette() mainPalette = self.palette()
@@ -153,6 +152,7 @@ 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)
# Update theme colours
self._docTheme.text = SHARED.theme.colText self._docTheme.text = SHARED.theme.colText
self._docTheme.highlight = SHARED.theme.colMark self._docTheme.highlight = SHARED.theme.colMark
self._docTheme.head = SHARED.theme.colHead self._docTheme.head = SHARED.theme.colHead
@@ -169,10 +169,6 @@ class GuiDocViewer(QTextBrowser):
# Set default text margins # Set default text margins
self.document().setDocumentMargin(0) self.document().setDocumentMargin(0)
options = QTextOption()
if CONFIG.doJustify:
options.setAlignment(QtAlignJustify)
self.document().setDefaultTextOption(options)
# Scroll bars # Scroll bars
if CONFIG.hideVScroll: if CONFIG.hideVScroll:
@@ -193,16 +189,6 @@ class GuiDocViewer(QTextBrowser):
return 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: def loadText(self, tHandle: str, updateHistory: bool = True) -> bool:
"""Load text into the viewer from an item handle.""" """Load text into the viewer from an item handle."""
if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE): if not SHARED.project.tree.checkType(tHandle, nwItemType.FILE):
@@ -215,6 +201,7 @@ class GuiDocViewer(QTextBrowser):
sPos = self.verticalScrollBar().value() sPos = self.verticalScrollBar().value()
qDoc = ToQTextDocument(SHARED.project) qDoc = ToQTextDocument(SHARED.project)
qDoc.setJustify(CONFIG.doJustify)
qDoc.initDocument(CONFIG.textFont, self._docTheme) qDoc.initDocument(CONFIG.textFont, self._docTheme)
qDoc.setKeywords(True) qDoc.setKeywords(True)
qDoc.setComments(CONFIG.viewComments) qDoc.setComments(CONFIG.viewComments)
@@ -244,11 +231,6 @@ class GuiDocViewer(QTextBrowser):
self.docHistory.append(tHandle) self.docHistory.append(tHandle)
self.setDocumentTitle(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) self.setDocument(qDoc.document)
if self._docHandle == tHandle: if self._docHandle == tHandle:
@@ -482,34 +464,6 @@ class GuiDocViewer(QTextBrowser):
self._makeSelection(selType) self._makeSelection(selType)
return 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: class GuiDocViewHistory:
+2 -13
View File
@@ -50,8 +50,8 @@ from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manusbuild import GuiManuscriptBuild
from novelwriter.tools.manussettings import GuiBuildSettings from novelwriter.tools.manussettings import GuiBuildSettings
from novelwriter.types import ( from novelwriter.types import (
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop, QtAlignCenter, QtAlignRight, QtAlignTop, QtSizeExpanding, QtSizeIgnored,
QtSizeExpanding, QtSizeIgnored, QtUserRole QtUserRole
) )
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
@@ -353,7 +353,6 @@ class GuiManuscript(NToolDialog):
self.docPreview.setTextFont(font) self.docPreview.setTextFont(font)
self.docPreview.setContent(buildObj.document) self.docPreview.setContent(buildObj.document)
self.docPreview.setBuildName(build.name) self.docPreview.setBuildName(build.name)
self.docPreview.setJustify(build.getBool("format.justifyText"))
self.docStats.updateStats(buildObj.textStats) self.docStats.updateStats(buildObj.textStats)
self.buildOutline.updateOutline(buildObj.textOutline) self.buildOutline.updateOutline(buildObj.textOutline)
@@ -777,16 +776,6 @@ class _PreviewWidget(QTextBrowser):
self._updateBuildAge() self._updateBuildAge()
return 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: def setTextFont(self, font: QFont) -> None:
"""Set the text font properties and then reset for sub-widgets. """Set the text font properties and then reset for sub-widgets.
This needs special attention since there appears to be a bug in This needs special attention since there appears to be a bug in
+1 -1
View File
@@ -202,7 +202,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
# Document footer show/hide comments # Document footer show/hide comments
assert nwGUI.viewDocument("846352075de7d") is True assert nwGUI.viewDocument("846352075de7d") is True
assert len(docViewer.toPlainText()) == 674 assert len(docViewer.toPlainText()) == 683
docViewer.docFooter._doToggleComments(False) docViewer.docFooter._doToggleComments(False)
assert len(docViewer.toPlainText()) == 634 assert len(docViewer.toPlainText()) == 634
+18 -37
View File
@@ -28,15 +28,14 @@ from PyQt5.QtCore import pyqtSlot
from PyQt5.QtPrintSupport import QPrintPreviewDialog from PyQt5.QtPrintSupport import QPrintPreviewDialog
from PyQt5.QtWidgets import QAction, QListWidgetItem from PyQt5.QtWidgets import QAction, QListWidgetItem
from novelwriter import CONFIG, SHARED from novelwriter import SHARED
from novelwriter.constants import nwHeadFmt from novelwriter.constants import nwHeadFmt
from novelwriter.core.buildsettings import BuildSettings from novelwriter.core.buildsettings import BuildSettings
from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manusbuild import GuiManuscriptBuild
from novelwriter.tools.manuscript import GuiManuscript from novelwriter.tools.manuscript import GuiManuscript
from novelwriter.tools.manussettings import GuiBuildSettings 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 from tests.tools import C, buildTestProject
@@ -64,23 +63,23 @@ def testManuscript_Init(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
manus.close() manus.close()
# A new dialog should load the old build # # A new dialog should load the old build
manus = GuiManuscript(nwGUI) # manus = GuiManuscript(nwGUI)
manus.show() # manus.show()
manus.loadContent() # manus.loadContent()
assert manus.docPreview.toPlainText().strip() == allText # assert manus.docPreview.toPlainText().strip() == allText
manus.close() # manus.close()
# But blocking the reload should leave it empty # # But blocking the reload should leave it empty
with monkeypatch.context() as mp: # with monkeypatch.context() as mp:
mp.setattr("builtins.open", lambda *a, **k: causeOSError) # mp.setattr("builtins.open", lambda *a, **k: causeOSError)
manus = GuiManuscript(nwGUI) # manus = GuiManuscript(nwGUI)
manus.show() # manus.show()
manus.loadContent() # manus.loadContent()
assert manus.docPreview.toPlainText().strip() == "" # assert manus.docPreview.toPlainText().strip() == ""
nwGUI.closeProject() # This should auto-close the manuscript tool # nwGUI.closeProject() # This should auto-close the manuscript tool
assert manus.isHidden() # assert manus.isHidden()
# qtbot.stop() # qtbot.stop()
@@ -186,7 +185,6 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
manus.show() manus.show()
manus.loadContent() manus.loadContent()
cacheFile = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
manus.buildList.setCurrentRow(0) manus.buildList.setCurrentRow(0)
build = manus._getSelectedBuild() build = manus._getSelectedBuild()
assert isinstance(build, BuildSettings) assert isinstance(build, BuildSettings)
@@ -199,17 +197,9 @@ def testManuscript_Features(monkeypatch, qtbot, nwGUI, projPath, mockRnd):
manus.btnPreview.click() manus.btnPreview.click()
qtbot.wait(200) # Should be enough to run the build qtbot.wait(200) # Should be enough to run the build
assert manus.docPreview.toPlainText().strip() == "" assert manus.docPreview.toPlainText().strip() == ""
assert cacheFile.exists() is False
manus._updateBuildsList() manus._updateBuildsList()
# Preview the first, but fail to save cache # Preview the first
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
first = manus.buildList.item(0) first = manus.buildList.item(0)
assert isinstance(first, QListWidgetItem) assert isinstance(first, QListWidgetItem)
build = manus._builds.getBuild(first.data(GuiManuscript.D_KEY)) 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) build.setValue("headings.fmtAltScene", nwHeadFmt.TITLE)
manus._builds.setBuild(build) manus._builds.setBuild(build)
# Preview again, and allow cache file to be created
manus.buildList.setCurrentRow(0) manus.buildList.setCurrentRow(0)
with qtbot.waitSignal(manus.docPreview.document().contentsChanged): with qtbot.waitSignal(manus.docPreview.document().contentsChanged):
manus.btnPreview.click() manus.btnPreview.click()
assert manus.docPreview.toPlainText().strip() != "" assert manus.docPreview.toPlainText().strip() != ""
assert cacheFile.exists() is True
# Check Outline # Check Outline
assert manus.buildOutline._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.maxTotalWords.text() == "25"
assert manus.docStats.maxTotalChars.text() == "117" 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 # Tests are too fast to trigger this one, so we trigger it manually to ensure it isn't failing
manus.docPreview._postUpdate() manus.docPreview._postUpdate()