diff --git a/novelwriter/common.py b/novelwriter/common.py
index 0f61bd896..91b2fae97 100644
--- a/novelwriter/common.py
+++ b/novelwriter/common.py
@@ -38,7 +38,6 @@
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QCoreApplication, QUrl
-from PyQt5.QtWidgets import QWidget, qApp
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.error import logException
@@ -508,18 +507,6 @@ def openExternalPath(path: Path) -> bool:
return False
-# =============================================================================================== #
-# Other Functions
-# =============================================================================================== #
-
-def getGuiItem(objName: str) -> QWidget | None:
- """Returns a QtWidget based on its objectName."""
- for qWidget in qApp.topLevelWidgets():
- if qWidget.objectName() == objName:
- return qWidget
- return None
-
-
# =============================================================================================== #
# Classes
# =============================================================================================== #
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index f66f4549a..1f74bb430 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -80,7 +80,7 @@ def __init__(self) -> None:
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: NWProject")
return
diff --git a/novelwriter/core/spellcheck.py b/novelwriter/core/spellcheck.py
index e2a022e92..852fbd485 100644
--- a/novelwriter/core/spellcheck.py
+++ b/novelwriter/core/spellcheck.py
@@ -56,7 +56,7 @@ def __init__(self, project: NWProject) -> None:
logger.debug("Ready: NWSpellEnchant")
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: NWSpellEnchant")
return
diff --git a/novelwriter/extensions/wheeleventfilter.py b/novelwriter/extensions/eventfilters.py
similarity index 80%
rename from novelwriter/extensions/wheeleventfilter.py
rename to novelwriter/extensions/eventfilters.py
index 220fa324b..9c53354e3 100644
--- a/novelwriter/extensions/wheeleventfilter.py
+++ b/novelwriter/extensions/eventfilters.py
@@ -1,9 +1,10 @@
"""
-novelWriter – Custom Object: Wheel Event Filter
-===============================================
+novelWriter – Custom Objects: Event Filters
+===========================================
File History:
-Created: 2023-08-31 [2.1rc1]
+Created: 2023-08-31 [2.1rc1] WheelEventFilter
+Created: 2023-11-28 [2.2] StatusTipFilter
This file is a part of novelWriter
Copyright 2018–2023, Veronica Berglyd Olsen
@@ -23,7 +24,7 @@
"""
from __future__ import annotations
-from PyQt5.QtGui import QWheelEvent
+from PyQt5.QtGui import QStatusTipEvent, QWheelEvent
from PyQt5.QtCore import QEvent, QObject
from PyQt5.QtWidgets import QWidget
@@ -63,3 +64,12 @@ def eventFilter(self, object: QObject, event: QEvent) -> bool:
return False
# END Class WheelEventFilter
+
+
+class StatusTipFilter(QObject):
+
+ def eventFilter(self, obj: QObject, event: QEvent) -> bool:
+ """Filter out status tip events on menus."""
+ return True if isinstance(event, QStatusTipEvent) else super().eventFilter(obj, event)
+
+# END Class StatusTipFilter
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 4d4ac3930..8ea95769a 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -62,7 +62,7 @@
from novelwriter.core.document import NWDocument
from novelwriter.gui.dochighlight import GuiDocHighlighter
from novelwriter.gui.editordocument import GuiTextDocument
-from novelwriter.extensions.wheeleventfilter import WheelEventFilter
+from novelwriter.extensions.eventfilters import WheelEventFilter
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index d548f0d41..44ccb1d5c 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -46,7 +46,7 @@
from novelwriter.error import logException
from novelwriter.constants import nwUnicode
from novelwriter.core.tohtml import ToHtml
-from novelwriter.extensions.wheeleventfilter import WheelEventFilter
+from novelwriter.extensions.eventfilters import WheelEventFilter
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
diff --git a/novelwriter/gui/editordocument.py b/novelwriter/gui/editordocument.py
index aa00ec7c1..3f6661e0b 100644
--- a/novelwriter/gui/editordocument.py
+++ b/novelwriter/gui/editordocument.py
@@ -50,7 +50,7 @@ def __init__(self, parent: QObject) -> None:
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiTextDocument")
return
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index a601fb99c..e442f9e81 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -3,8 +3,7 @@
===========================
File History:
-Created: 2019-04-27 [0.0.1] GuiMainMenu
-Created: 2023-11-28 [2.2] StatusTipFilter
+Created: 2019-04-27 [0.0.1]
This file is a part of novelWriter
Copyright 2018–2023, Veronica Berglyd Olsen
@@ -29,14 +28,15 @@
from typing import TYPE_CHECKING
from pathlib import Path
-from PyQt5.QtGui import QDesktopServices, QStatusTipEvent
-from PyQt5.QtCore import QEvent, QObject, QUrl, pyqtSignal, pyqtSlot
+from PyQt5.QtGui import QDesktopServices
+from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QMenuBar, QAction
from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwDocAction, nwDocInsert, nwWidget
from novelwriter.common import openExternalPath
from novelwriter.constants import nwConst, trConst, nwKeyWords, nwLabels, nwUnicode
+from novelwriter.extensions.eventfilters import StatusTipFilter
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
@@ -971,12 +971,3 @@ def _buildHelpMenu(self) -> None:
return
# END Class GuiMainMenu
-
-
-class StatusTipFilter(QObject):
-
- def eventFilter(self, obj: QObject, event: QEvent) -> bool:
- """Filter out status tip events."""
- return True if isinstance(event, QStatusTipEvent) else super().eventFilter(obj, event)
-
-# END Class StatusTipFilter
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 607e694a7..c2355707f 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -1650,7 +1650,7 @@ def __init__(self, projTree: GuiProjectTree, nwItem: NWItem) -> None:
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: _TreeContextMenu")
return
diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py
index 9cfbf1181..b15908a24 100644
--- a/novelwriter/gui/sidebar.py
+++ b/novelwriter/gui/sidebar.py
@@ -27,12 +27,13 @@
from typing import TYPE_CHECKING
-from PyQt5.QtCore import QEvent, QPoint, Qt, QSize, pyqtSignal
from PyQt5.QtGui import QPalette
+from PyQt5.QtCore import QEvent, QPoint, Qt, QSize, pyqtSignal
from PyQt5.QtWidgets import QMenu, QToolButton, QVBoxLayout, QWidget
from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwView
+from novelwriter.extensions.eventfilters import StatusTipFilter
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
@@ -54,6 +55,7 @@ def __init__(self, mainGui: GuiMain) -> None:
iPx = CONFIG.pxInt(24)
iconSize = QSize(iPx, iPx)
self.setContentsMargins(0, 0, 0, 0)
+ self.installEventFilter(StatusTipFilter(mainGui))
# Buttons
self.tbProject = QToolButton(self)
@@ -162,7 +164,7 @@ def updateTheme(self) -> None:
class _PopRightMenu(QMenu):
- def event(self, event: QEvent):
+ def event(self, event: QEvent) -> bool:
"""Overload the show event and move the menu popup location."""
if event.type() == QEvent.Show:
parent = self.parent()
diff --git a/novelwriter/shared.py b/novelwriter/shared.py
index 9bad600a3..5383765aa 100644
--- a/novelwriter/shared.py
+++ b/novelwriter/shared.py
@@ -45,7 +45,7 @@
class SharedData(QObject):
__slots__ = (
- "_gui", "_theme", "_project", "_spelling", "_lockedBy", "_alert",
+ "_gui", "_theme", "_project", "_spelling", "_lockedBy", "_lastAlert",
"_idleTime", "_idleRefTime",
)
@@ -68,7 +68,7 @@ def __init__(self) -> None:
# Settings
self._lockedBy = None
- self._alert = None
+ self._lastAlert = ""
self._idleTime = 0.0
self._idleRefTime = time()
@@ -122,9 +122,9 @@ def projectIdleTime(self) -> float:
return self._idleTime
@property
- def alert(self) -> _GuiAlert | None:
- """Return a pointer to the last alert box."""
- return self._alert
+ def lastAlert(self) -> str:
+ """Return the last alert message."""
+ return self._lastAlert
##
# Methods
@@ -238,44 +238,53 @@ def indexSignalProxy(self, data: dict) -> None:
def info(self, text: str, info: str = "", details: str = "", log: bool = True) -> None:
"""Open an information alert box."""
- self._alert = _GuiAlert(self.mainGui, self.theme)
- self._alert.setMessage(text, info, details)
- self._alert.setAlertType(_GuiAlert.INFO, False)
+ alert = _GuiAlert(self.mainGui, self.theme)
+ alert.setMessage(text, info, details)
+ alert.setAlertType(_GuiAlert.INFO, False)
+ self._lastAlert = alert.logMessage
if log:
- logger.info(self._alert.logMessage, stacklevel=2)
- self._alert.exec_()
+ logger.info(self._lastAlert, stacklevel=2)
+ alert.exec_()
+ alert.deleteLater()
return
def warn(self, text: str, info: str = "", details: str = "", log: bool = True) -> None:
"""Open a warning alert box."""
- self._alert = _GuiAlert(self.mainGui, self.theme)
- self._alert.setMessage(text, info, details)
- self._alert.setAlertType(_GuiAlert.WARN, False)
+ alert = _GuiAlert(self.mainGui, self.theme)
+ alert.setMessage(text, info, details)
+ alert.setAlertType(_GuiAlert.WARN, False)
+ self._lastAlert = alert.logMessage
if log:
- logger.warning(self._alert.logMessage, stacklevel=2)
- self._alert.exec_()
+ logger.warning(self._lastAlert, stacklevel=2)
+ alert.exec_()
+ alert.deleteLater()
return
def error(self, text: str, info: str = "", details: str = "", log: bool = True,
exc: Exception | None = None) -> None:
"""Open an error alert box."""
- self._alert = _GuiAlert(self.mainGui, self.theme)
- self._alert.setMessage(text, info, details)
- self._alert.setAlertType(_GuiAlert.ERROR, False)
+ alert = _GuiAlert(self.mainGui, self.theme)
+ alert.setMessage(text, info, details)
+ alert.setAlertType(_GuiAlert.ERROR, False)
if exc:
- self._alert.setException(exc)
+ alert.setException(exc)
+ self._lastAlert = alert.logMessage
if log:
- logger.error(self._alert.logMessage, stacklevel=2)
- self._alert.exec_()
+ logger.error(self._lastAlert, stacklevel=2)
+ alert.exec_()
+ alert.deleteLater()
return
def question(self, text: str, info: str = "", details: str = "", warn: bool = False) -> bool:
"""Open a question box."""
- self._alert = _GuiAlert(self.mainGui, self.theme)
- self._alert.setMessage(text, info, details)
- self._alert.setAlertType(_GuiAlert.WARN if warn else _GuiAlert.ASK, True)
- self._alert.exec_()
- return self._alert.result() == QMessageBox.Yes
+ alert = _GuiAlert(self.mainGui, self.theme)
+ alert.setMessage(text, info, details)
+ alert.setAlertType(_GuiAlert.WARN if warn else _GuiAlert.ASK, True)
+ self._lastAlert = alert.logMessage
+ alert.exec_()
+ isYes = alert.result() == QMessageBox.StandardButton.Yes
+ alert.deleteLater()
+ return isYes
##
# Internal Functions
@@ -312,6 +321,11 @@ def __init__(self, parent: QWidget, theme: GuiTheme) -> None:
super().__init__(parent=parent)
self._theme = theme
self._message = ""
+ logger.debug("Ready: _GuiAlert")
+ return
+
+ def __del__(self) -> None: # pragma: no cover
+ logger.debug("Delete: _GuiAlert")
return
@property
diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py
index 5f7b68566..d68a74e7e 100644
--- a/novelwriter/tools/manuscript.py
+++ b/novelwriter/tools/manuscript.py
@@ -66,7 +66,7 @@ class GuiManuscript(QDialog):
D_KEY = Qt.ItemDataRole.UserRole
- def __init__(self, mainGui: GuiMain):
+ def __init__(self, mainGui: GuiMain) -> None:
super().__init__(parent=mainGui)
logger.debug("Create: GuiManuscript")
@@ -173,7 +173,7 @@ def __init__(self, mainGui: GuiMain):
self.btnBuild.clicked.connect(self._buildManuscript)
self.btnClose = QPushButton(self.tr("Close"))
- self.btnClose.clicked.connect(self._doClose)
+ self.btnClose.clicked.connect(self.close)
self.processBox = QGridLayout()
self.processBox.addWidget(self.btnPreview, 0, 0)
@@ -217,11 +217,11 @@ def __init__(self, mainGui: GuiMain):
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiManuscript")
return
- def loadContent(self):
+ def loadContent(self) -> None:
"""Load dialog content from project data."""
if len(self._builds) == 0:
build = BuildSettings()
@@ -255,7 +255,7 @@ def loadContent(self):
# Events
##
- def closeEvent(self, event: QCloseEvent):
+ def closeEvent(self, event: QCloseEvent) -> None:
"""Capture the user closing the window so we can save GUI
settings. We also check that we don't have a build settings
dialog open.
@@ -274,7 +274,7 @@ def closeEvent(self, event: QCloseEvent):
##
@pyqtSlot()
- def _createNewBuild(self):
+ def _createNewBuild(self) -> None:
"""Open the build settings dialog for a new build."""
build = BuildSettings()
build.setName(self.tr("My Manuscript"))
@@ -282,7 +282,7 @@ def _createNewBuild(self):
return
@pyqtSlot()
- def _editSelectedBuild(self):
+ def _editSelectedBuild(self) -> None:
"""Edit the currently selected build settings entry."""
build = self._getSelectedBuild()
if build is not None:
@@ -299,7 +299,7 @@ def _updateBuildDetails(self, current: QListWidgetItem, previous: QListWidgetIte
return
@pyqtSlot()
- def _deleteSelectedBuild(self):
+ def _deleteSelectedBuild(self) -> None:
"""Delete the currently selected build settings entry."""
build = self._getSelectedBuild()
if build is not None:
@@ -309,7 +309,7 @@ def _deleteSelectedBuild(self):
return
@pyqtSlot(BuildSettings)
- def _processNewSettings(self, build: BuildSettings):
+ def _processNewSettings(self, build: BuildSettings) -> None:
"""Process new build settings from the settings dialog."""
self._builds.setBuild(build)
self._updateBuildItem(build)
@@ -319,7 +319,7 @@ def _processNewSettings(self, build: BuildSettings):
return
@pyqtSlot()
- def _generatePreview(self):
+ def _generatePreview(self) -> None:
"""Run the document builder on the current build settings for
the preview widget.
"""
@@ -359,7 +359,7 @@ def _generatePreview(self):
return
@pyqtSlot()
- def _buildManuscript(self):
+ def _buildManuscript(self) -> None:
"""Open the build dialog and build the manuscript."""
build = self._getSelectedBuild()
if isinstance(build, BuildSettings):
@@ -373,24 +373,18 @@ def _buildManuscript(self):
return
@pyqtSlot()
- def _printDocument(self):
+ def _printDocument(self) -> None:
"""Open the print preview dialog."""
thePreview = QPrintPreviewDialog(self)
thePreview.paintRequested.connect(self.docPreview.printPreview)
thePreview.exec_()
return
- @pyqtSlot()
- def _doClose(self):
- """Forward the close button to the default close method."""
- self.close()
- return
-
##
# Internal Functions
##
- def _updatePreview(self, data: dict, build: BuildSettings):
+ def _updatePreview(self, data: dict, build: BuildSettings) -> None:
"""Update the preview widget and set relevant values."""
self.docPreview.setContent(data)
self.docPreview.setBuildName(build.name)
@@ -415,7 +409,7 @@ def _getSelectedBuild(self) -> BuildSettings | None:
return build
return None
- def _saveSettings(self):
+ def _saveSettings(self) -> None:
"""Save the user GUI settings."""
buildOrder = []
for i in range(self.buildList.count()):
@@ -454,7 +448,7 @@ def _saveSettings(self):
return
- def _openSettingsDialog(self, build: BuildSettings):
+ def _openSettingsDialog(self, build: BuildSettings) -> None:
"""Open the build settings dialog."""
for obj in self.mainGui.children():
# Don't open a second dialog if one exists
@@ -475,7 +469,7 @@ def _openSettingsDialog(self, build: BuildSettings):
return
- def _updateBuildsList(self):
+ def _updateBuildsList(self) -> None:
"""Update the list of available builds."""
self.buildList.clear()
for key, name in self._builds.builds():
@@ -487,7 +481,7 @@ def _updateBuildsList(self):
self._buildMap[key] = bItem
return
- def _updateBuildItem(self, build: BuildSettings):
+ def _updateBuildItem(self, build: BuildSettings) -> None:
"""Update the entry of a specific build item."""
bItem = self._buildMap.get(build.buildID, None)
if isinstance(bItem, QListWidgetItem):
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index b47da1cf3..5c3b18324 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -80,7 +80,7 @@ def __init__(self, mainGui):
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiProjectWizard")
return
diff --git a/tests/test_base/test_base_common.py b/tests/test_base/test_base_common.py
index 2ca1a35fa..785944d62 100644
--- a/tests/test_base/test_base_common.py
+++ b/tests/test_base/test_base_common.py
@@ -21,8 +21,6 @@
from __future__ import annotations
import time
-from PyQt5.QtCore import QUrl
-from PyQt5.QtGui import QDesktopServices
import pytest
from pathlib import Path
@@ -31,14 +29,16 @@
from tools import writeFile
from mocked import causeOSError
-from novelwriter.guimain import GuiMain
+from PyQt5.QtGui import QDesktopServices
+from PyQt5.QtCore import QUrl
+
from novelwriter.common import (
checkBool, checkFloat, checkHandle, checkInt, checkIntTuple, checkPath,
checkString, checkStringNone, checkUuid, formatInt, formatTime,
- formatTimeStamp, fuzzyTime, getFileSize, getGuiItem, hexToInt, isHandle,
- isItemClass, isItemLayout, isItemType, isTitleTag, jsonEncode,
- makeFileNameSafe, minmax, numberToRoman, NWConfigParser, openExternalPath,
- readTextFile, simplified, transferCase, xmlIndent, yesNo
+ formatTimeStamp, fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass,
+ isItemLayout, isItemType, isTitleTag, jsonEncode, makeFileNameSafe, minmax,
+ numberToRoman, NWConfigParser, openExternalPath, readTextFile, simplified,
+ transferCase, xmlIndent, yesNo
)
@@ -655,15 +655,6 @@ def mockOpenUrl(url: QUrl) -> None:
# END Test testBaseCommon_openExternalPath
-@pytest.mark.base
-def testBaseCommon_getGuiItem(nwGUI):
- """Check the GUI item function."""
- assert getGuiItem("gibberish") is None
- assert isinstance(getGuiItem("GuiMain"), GuiMain)
-
-# END Test testBaseCommon_getGuiItem
-
-
@pytest.mark.base
def testBaseCommon_NWConfigParser(fncPath):
"""Test the NWConfigParser subclass."""
diff --git a/tests/test_base/test_base_shared.py b/tests/test_base/test_base_shared.py
index 4e3de75a0..0f105284b 100644
--- a/tests/test_base/test_base_shared.py
+++ b/tests/test_base/test_base_shared.py
@@ -22,13 +22,13 @@
import pytest
+from tools import buildTestProject
from mocked import MockGuiMain, MockTheme
from PyQt5.QtWidgets import QMessageBox
+from novelwriter.shared import SharedData
from novelwriter.core.project import NWProject
-from novelwriter.shared import SharedData, _GuiAlert
-from tests.tools import buildTestProject
@pytest.mark.base
@@ -62,8 +62,6 @@ def testBaseSharedData_Init():
assert shared.projectIdleTime == 0.0
assert shared.projectLock is None
- assert shared.alert is None
-
# END Test testBaseSharedData_Init
@@ -124,7 +122,7 @@ def testBaseSharedData_Projects(fncPath, caplog):
@pytest.mark.base
-def testBaseSharedData_Alerts(monkeypatch, caplog):
+def testBaseSharedData_Alerts(qtbot, monkeypatch, caplog):
"""Test SharedData class alert helper functions."""
monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None)
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes)
@@ -135,56 +133,38 @@ def testBaseSharedData_Alerts(monkeypatch, caplog):
mockTheme = MockTheme()
shared.initSharedData(mockGui, mockTheme) # type: ignore
- assert shared.alert is None
+ assert shared.lastAlert == ""
# Info box
caplog.clear()
shared.info("Hello World", info="foo", details="bar")
- assert isinstance(shared.alert, _GuiAlert)
- assert shared.alert.text() == "Hello World"
- assert shared.alert.informativeText() == "foo"
- assert shared.alert.detailedText() == "bar"
+ assert shared.lastAlert == "Hello World foo bar"
assert caplog.text.strip().startswith("INFO")
assert caplog.text.strip().endswith("Hello World foo bar")
- shared._alert = None
# Warning box
caplog.clear()
shared.warn("Oops!", info="foo", details="bar")
- assert isinstance(shared.alert, _GuiAlert)
- assert shared.alert.text() == "Oops!"
- assert shared.alert.informativeText() == "foo"
- assert shared.alert.detailedText() == "bar"
+ assert shared.lastAlert == "Oops! foo bar"
assert caplog.text.strip().startswith("WARNING")
assert caplog.text.strip().endswith("Oops! foo bar")
- shared._alert = None
# Error box
caplog.clear()
shared.error("Oh noes!", info="foo", details="bar")
- assert isinstance(shared.alert, _GuiAlert)
- assert shared.alert.text() == "Oh noes!"
- assert shared.alert.informativeText() == "foo"
- assert shared.alert.detailedText() == "bar"
+ assert shared.lastAlert == "Oh noes! foo bar"
assert caplog.text.strip().startswith("ERROR")
assert caplog.text.strip().endswith("Oh noes! foo bar")
- shared._alert = None
# Error box with exception
caplog.clear()
shared.error("Oh noes!", info="foo", details="bar", exc=Exception("Boom!"))
- assert isinstance(shared.alert, _GuiAlert)
- assert shared.alert.text() == "Oh noes!"
- assert shared.alert.informativeText() == "foo
Exception: Boom!"
- assert shared.alert.detailedText() == "bar"
+ assert shared.lastAlert == "Oh noes! foo bar"
assert caplog.text.strip().startswith("ERROR")
assert caplog.text.strip().endswith("Oh noes! foo bar")
- shared._alert = None
# Question box
assert shared.question("Why?") is True
- assert isinstance(shared.alert, _GuiAlert)
- assert shared.alert.text() == "Why?"
- shared._alert = None
+ assert shared.lastAlert == "Why?"
# END Test testBaseSharedData_Alerts
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 475c9ce18..6cf3b04ac 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -206,40 +206,35 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.NOT_NWX_FILE))
assert theProject.openProject(fncPath) is False
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "Project file does not appear" in lastMsg
+ assert "Project file does not appear" in SHARED.lastAlert
# Unknown project file version
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.UNKNOWN_VERSION))
assert theProject.openProject(fncPath) is False
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "Unknown or unsupported novelWriter project file" in lastMsg
+ assert "Unknown or unsupported novelWriter project file" in SHARED.lastAlert
# Other parse error
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.CANNOT_PARSE))
assert theProject.openProject(fncPath) is False
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "Failed to parse project xml" in lastMsg
+ assert "Failed to parse project xml" in SHARED.lastAlert
# Won't convert legacy file
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert theProject.openProject(fncPath) is False
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "The file format of your project is about to be" in lastMsg
+ assert "The file format of your project is about to be" in SHARED.lastAlert
# Won't open project from newer version
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert theProject.openProject(fncPath) is False
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "This project was saved by a newer version" in lastMsg
+ assert "This project was saved by a newer version" in SHARED.lastAlert
# Fail checking items should still pass
with monkeypatch.context() as mp:
@@ -254,8 +249,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
mp.setattr("novelwriter.core.index.NWIndex.loadIndex", lambda *a: True)
theProject.index._indexBroken = True
assert theProject.openProject(fncPath) is True
- lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert "The file format of your project is about to be" in lastMsg
+ assert "The file format of your project is about to be" in SHARED.lastAlert
assert theProject.index._indexBroken is False
theProject.closeProject()
diff --git a/tests/test_ext/test_ext_wheeleventfilter.py b/tests/test_ext/test_ext_eventfilters.py
similarity index 92%
rename from tests/test_ext/test_ext_wheeleventfilter.py
rename to tests/test_ext/test_ext_eventfilters.py
index 2d348358e..844d44036 100644
--- a/tests/test_ext/test_ext_wheeleventfilter.py
+++ b/tests/test_ext/test_ext_eventfilters.py
@@ -26,7 +26,7 @@
from PyQt5.QtCore import QEvent, QObject, QPoint, Qt
from PyQt5.QtWidgets import QWidget
-from novelwriter.extensions.wheeleventfilter import WheelEventFilter
+from novelwriter.extensions.eventfilters import WheelEventFilter
class MockWidget(QWidget):
@@ -42,7 +42,7 @@ def wheelEvent(self, event: QWheelEvent) -> None:
@pytest.mark.gui
-def testExtWheelEventFilter_Main():
+def testExtEventFilters_WheelEventFilter():
"""Test the WheelEventFilter class."""
obj = QObject()
widget = MockWidget()
@@ -65,4 +65,4 @@ def testExtWheelEventFilter_Main():
eFilter.eventFilter(obj, event)
assert widget.count == 1
-# END Test testExtWheelEventFilter_Main
+# END Test testExtEventFilters_WheelEventFilter
diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py
index 721cc1306..91c1ac13f 100644
--- a/tests/test_gui/test_gui_mainmenu.py
+++ b/tests/test_gui/test_gui_mainmenu.py
@@ -656,8 +656,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
nwGUI.mainMenu.aFileDetails.activate(QAction.Trigger)
path = str(projPath / "content" / "000000000000f.nwd")
- logMsg = SHARED.alert.logMessage if SHARED.alert else ""
- assert logMsg.endswith(f"File Location: {path}")
+ assert SHARED.lastAlert.endswith(f"File Location: {path}")
# qtbot.stop()
diff --git a/tests/test_tools/test_tools_dictionaries.py b/tests/test_tools/test_tools_dictionaries.py
index eee0f0f7b..02cc5dc01 100644
--- a/tests/test_tools/test_tools_dictionaries.py
+++ b/tests/test_tools/test_tools_dictionaries.py
@@ -44,8 +44,7 @@ def testToolDictionaries_Main(qtbot, monkeypatch, nwGUI, fncPath):
with monkeypatch.context() as mp:
mp.setattr(enchant, "get_user_config_dir", lambda *a: causeException)
nwGUI.showDictionariesDialog()
- assert SHARED.alert is not None
- assert SHARED.alert.logMessage == "Could not initialise the dialog."
+ assert SHARED.lastAlert == "Could not initialise the dialog."
# Open the tool
nwGUI.showDictionariesDialog()
@@ -57,17 +56,16 @@ def testToolDictionaries_Main(qtbot, monkeypatch, nwGUI, fncPath):
assert nwDicts.inPath.text() == str(fncPath)
# Allow Open Dir
- SHARED._alert = None
+ SHARED._lastAlert = ""
with monkeypatch.context() as mp:
mp.setattr(QDesktopServices, "openUrl", lambda *a: None)
nwDicts._doOpenInstallLocation()
- assert SHARED.alert is None
+ assert SHARED.lastAlert == ""
# Fail Open Dir
nwDicts.inPath.setText("/foo/bar")
nwDicts._doOpenInstallLocation()
- assert SHARED.alert is not None
- assert SHARED.alert.logMessage == "Path not found."
+ assert SHARED.lastAlert == "Path not found."
nwDicts.inPath.setText(str(fncPath))
# Create Mock Dicts