Clean up alert boxes and update event filters (#1631)

This commit is contained in:
Veronica Berglyd Olsen
2023-11-29 16:12:08 +01:00
committed by GitHub
19 changed files with 116 additions and 156 deletions
-13
View File
@@ -38,7 +38,6 @@ from urllib.request import pathname2url
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
# =============================================================================================== #
+1 -1
View File
@@ -80,7 +80,7 @@ class NWProject:
return
def __del__(self): # pragma: no cover
def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: NWProject")
return
+1 -1
View File
@@ -56,7 +56,7 @@ class NWSpellEnchant:
logger.debug("Ready: NWSpellEnchant")
return
def __del__(self): # pragma: no cover
def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: NWSpellEnchant")
return
@@ -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 20182023, Veronica Berglyd Olsen
@@ -23,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
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 @@ class WheelEventFilter(QObject):
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
+1 -1
View File
@@ -62,7 +62,7 @@ from novelwriter.tools.lipsum import GuiLipsum
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
+1 -1
View File
@@ -46,7 +46,7 @@ from novelwriter.enum import nwItemType, nwDocAction, nwDocMode
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
+1 -1
View File
@@ -50,7 +50,7 @@ class GuiTextDocument(QTextDocument):
return
def __del__(self): # pragma: no cover
def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiTextDocument")
return
+4 -13
View File
@@ -3,8 +3,7 @@ novelWriter GUI Main Menu
===========================
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 20182023, Veronica Berglyd Olsen
@@ -29,14 +28,15 @@ import logging
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 @@ class GuiMainMenu(QMenuBar):
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
+1 -1
View File
@@ -1650,7 +1650,7 @@ class _TreeContextMenu(QMenu):
return
def __del__(self): # pragma: no cover
def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: _TreeContextMenu")
return
+4 -2
View File
@@ -27,12 +27,13 @@ import logging
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 @@ class GuiSideBar(QWidget):
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 @@ class GuiSideBar(QWidget):
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()
+40 -26
View File
@@ -45,7 +45,7 @@ logger = logging.getLogger(__name__)
class SharedData(QObject):
__slots__ = (
"_gui", "_theme", "_project", "_spelling", "_lockedBy", "_alert",
"_gui", "_theme", "_project", "_spelling", "_lockedBy", "_lastAlert",
"_idleTime", "_idleRefTime",
)
@@ -68,7 +68,7 @@ class SharedData(QObject):
# Settings
self._lockedBy = None
self._alert = None
self._lastAlert = ""
self._idleTime = 0.0
self._idleRefTime = time()
@@ -122,9 +122,9 @@ class SharedData(QObject):
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 @@ class SharedData(QObject):
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 @@ class _GuiAlert(QMessageBox):
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
+17 -23
View File
@@ -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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
# 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 @@ class GuiManuscript(QDialog):
##
@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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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 @@ class GuiManuscript(QDialog):
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):
+1 -1
View File
@@ -80,7 +80,7 @@ class GuiProjectWizard(QWizard):
return
def __del__(self): # pragma: no cover
def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiProjectWizard")
return
+7 -16
View File
@@ -21,8 +21,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
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 xml.etree import ElementTree as ET
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 testBaseCommon_openExternalPath(monkeypatch, tstPaths):
# 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."""
+9 -29
View File
@@ -22,13 +22,13 @@ from __future__ import annotations
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<br><b>Exception</b>: 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
+6 -12
View File
@@ -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()
@@ -26,7 +26,7 @@ from PyQt5.QtGui import QKeyEvent, QWheelEvent
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 @@ class MockWidget(QWidget):
@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
+1 -2
View File
@@ -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()
+4 -6
View File
@@ -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