diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 9b04c8d3..8992505d 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -280,14 +280,12 @@ class GuiDocViewer(QTextBrowser): return False return True - def navigateTo(self, tAnchor: str) -> bool: + def navigateTo(self, tAnchor: str) -> None: """Go to a specific #link in the document.""" - if not isinstance(tAnchor, str): - return False - if tAnchor.startswith("#"): + if isinstance(tAnchor, str) and tAnchor.startswith("#"): logger.debug("Moving to anchor '%s'", tAnchor) self.setSource(QUrl(tAnchor)) - return True + return def clearNavHistory(self) -> None: """Clear the navigation history.""" @@ -381,9 +379,6 @@ class GuiDocViewer(QTextBrowser): mnuContext = QMenu(self) - # Cut, Copy and Paste - # =================== - if userSelection: mnuCopy = QAction(self.tr("Copy"), mnuContext) mnuCopy.triggered.connect(lambda: self.docAction(nwDocAction.COPY)) @@ -391,9 +386,6 @@ class GuiDocViewer(QTextBrowser): mnuContext.addSeparator() - # Selections - # ========== - mnuSelAll = QAction(self.tr("Select All"), mnuContext) mnuSelAll.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL)) mnuContext.addAction(mnuSelAll) @@ -628,7 +620,7 @@ class GuiDocViewHistory: """Debug function to dump history to the logger. Since it is a for loop, it is skipped entirely if log level isn't DEBUG. """ - if logger.getEffectiveLevel() == logging.DEBUG: + if logger.getEffectiveLevel() == logging.DEBUG: # pragma: no cover for i, (h, p) in enumerate(zip(self._navHistory, self._posHistory)): logger.debug( "History %02d: %s %13s [x:%d]" % ( @@ -776,7 +768,7 @@ class GuiDocViewHeader(QWidget): self.docTitle.setPalette(palette) return - def setTitleFromHandle(self, tHandle: str | None) -> bool: + def setTitleFromHandle(self, tHandle: str | None) -> None: """Sets the document title from the handle, or alternatively, set the whole document path. """ @@ -787,7 +779,7 @@ class GuiDocViewHeader(QWidget): self.forwardButton.setVisible(False) self.closeButton.setVisible(False) self.refreshButton.setVisible(False) - return True + return pTree = SHARED.project.tree if CONFIG.showFullPath: @@ -800,17 +792,15 @@ class GuiDocViewHeader(QWidget): sSep = " %s " % nwUnicode.U_RSAQUO self.docTitle.setText(sSep.join(tTitle)) else: - nwItem = pTree[tHandle] - if nwItem is None: - return False - self.docTitle.setText(nwItem.itemName) + if nwItem := pTree[tHandle]: + self.docTitle.setText(nwItem.itemName) self.backButton.setVisible(True) self.forwardButton.setVisible(True) self.closeButton.setVisible(True) self.refreshButton.setVisible(True) - return True + return def updateNavButtons(self, firstIdx: int, lastIdx: int, currIdx: int) -> None: """Enable and disable nav buttons based on index in history.""" diff --git a/tests/test_core/test_core_projectxml.py b/tests/test_core/test_core_projectxml.py index 3448e653..a6c6e5e1 100644 --- a/tests/test_core/test_core_projectxml.py +++ b/tests/test_core/test_core_projectxml.py @@ -84,7 +84,7 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, tstPaths, fncPath): assert xmlReader.read(data, content) is False assert xmlReader.state == XMLReadState.NOT_NWX_FILE - # Add a valid novelwriter file without a file version + # Add a valid novelWriter file without a file version writeFile(xmlFile, "") assert xmlReader.read(data, content) is False assert xmlReader.state == XMLReadState.UNKNOWN_VERSION diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py index bda73915..b05e35b1 100644 --- a/tests/test_gui/test_gui_docviewer.py +++ b/tests/test_gui/test_gui_docviewer.py @@ -23,9 +23,9 @@ import pytest from mocked import causeException -from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QTextCursor -from PyQt5.QtWidgets import qApp, QAction +from PyQt5.QtCore import Qt, QUrl +from PyQt5.QtWidgets import QMenu, qApp, QAction from novelwriter import CONFIG, SHARED from novelwriter.enum import nwDocAction @@ -40,13 +40,12 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert nwGUI.openProject(prjLipsum) docViewer: GuiDocViewer = nwGUI.docViewer - # Rebuild the index - nwGUI.mainMenu.aRebuildIndex.activate(QAction.Trigger) - assert SHARED.project.index._tagsIndex._tags != {} - assert SHARED.project.index._itemIndex._items != {} - # Select a document in the project tree nwGUI.projView.setSelectedHandle("88243afbe5ed8") + nwGUI.openDocument("88243afbe5ed8") + + # Can only open a document + assert docViewer.loadText("b3643d0f92e32") is False # Middle-click the selected item item = nwGUI.projView.projTree._getTreeItem("88243afbe5ed8") @@ -54,6 +53,14 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): qtbot.mouseClick(nwGUI.projView.projTree.viewport(), Qt.MidButton, pos=rect.center()) assert docViewer.docHandle == "88243afbe5ed8" + # Clear selection + nwGUI.projView.projTree.clearSelection() + assert nwGUI.projView.projTree.getSelectedHandle() is None + + # Re-select via header click + docViewer.docHeader.mousePressEvent(None) # type: ignore + assert nwGUI.projView.projTree.getSelectedHandle() == "88243afbe5ed8" + # Reload the text origText = docViewer.toPlainText() docViewer.setPlainText("Oops, all gone!") @@ -88,6 +95,21 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): "mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. " "Etiam finibus nisi vel mi molestie consectetur." ) + cursor.clearSelection() + docViewer.setTextCursor(cursor) + + docViewer._makePosSelection( + QTextCursor.SelectionType.BlockUnderCursor, docViewer.cursorRect().center() + ) + cursor = docViewer.textCursor() + assert cursor.selectedText() == ( + "Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, " + "eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et " + "mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. " + "Etiam finibus nisi vel mi molestie consectetur." + ) + cursor.clearSelection() + docViewer.setTextCursor(cursor) # Select All assert docViewer.docAction(nwDocAction.SEL_ALL) is True @@ -108,6 +130,22 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert nwGUI.projView.setSelectedHandle("88243afbe5ed8") nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger) + # Open context menu + menuOpened = False + + def mockExec(*a): + nonlocal menuOpened + menuOpened = True + + cursor = docViewer.textCursor() + cursor.setPosition(27) + docViewer.setTextCursor(cursor) + docViewer._makeSelection(QTextCursor.WordUnderCursor) + with monkeypatch.context() as mp: + mp.setattr(QMenu, "exec_", mockExec) + docViewer._openContextMenu(docViewer.cursorRect().center()) + assert menuOpened + # Select "Bod" link cursor = docViewer.textCursor() cursor.setPosition(27) @@ -122,12 +160,22 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert docViewer.docHandle == "88243afbe5ed8" qtbot.mouseClick(docViewer.viewport(), Qt.ForwardButton, pos=rect.center(), delay=100) assert docViewer.docHandle == "4c4f28287af27" + qtbot.mouseClick(docViewer.viewport(), Qt.LeftButton, pos=rect.center(), delay=100) + assert docViewer.docHandle == "4c4f28287af27" # Scroll bar default on empty document docViewer.clear() assert docViewer.scrollPosition == 0 docViewer.reloadText() + # Flip some settings + CONFIG.doJustify = True + CONFIG.hideVScroll = True + CONFIG.hideHScroll = True + docViewer.initViewer() + assert docViewer.verticalScrollBar().isVisible() is False + assert docViewer.horizontalScrollBar().isVisible() is False + # Change document title nwItem = SHARED.project.tree["4c4f28287af27"] nwItem.setName("Test Title") # type: ignore @@ -159,6 +207,10 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum): assert docViewer.loadText("846352075de7d") is False assert docViewer.toPlainText() == "An error occurred while generating the preview." + # Call the update theme function + # This only checks that t doesn't fail, functionality tested elsewhere + docViewer.updateTheme() + # qtbot.stop() # END Test testGuiViewer_Main