From 600b60b4415ab2965f9dd74c76a99d02ba346718 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 1 May 2024 19:43:51 +0200 Subject: [PATCH 1/3] Remove main gui inheritance in manuscript tools --- novelwriter/tools/manuscript.py | 26 ++++++++++---------------- novelwriter/tools/manussettings.py | 29 ++++++++++++----------------- sample/nwProject.nwx | 4 ++-- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index 782a7109..f84dfa1a 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -28,16 +28,15 @@ import logging from datetime import datetime from time import time -from typing import TYPE_CHECKING -from PyQt5.QtCore import QTimer, QUrl, Qt, pyqtSignal, pyqtSlot +from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent -from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter +from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog from PyQt5.QtWidgets import ( QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout, - QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, - QSplitter, QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget + QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, QSplitter, + QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED @@ -57,9 +56,6 @@ from novelwriter.types import ( QtSizeExpanding, QtSizeIgnored, QtUserRole ) -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -73,16 +69,14 @@ class GuiManuscript(QDialog): D_KEY = QtUserRole - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiManuscript") self.setObjectName("GuiManuscript") if CONFIG.osDarwin: self.setWindowFlag(Qt.WindowType.Tool) - self.mainGui = mainGui - self._builds = BuildCollection(SHARED.project) self._buildMap: dict[str, QListWidgetItem] = {} @@ -280,7 +274,7 @@ class GuiManuscript(QDialog): dialog open. """ self._saveSettings() - for obj in self.mainGui.children(): + for obj in SHARED.mainGui.children(): # Make sure we don't have any settings windows open if isinstance(obj, GuiBuildSettings) and obj.isVisible(): obj.close() @@ -467,7 +461,7 @@ class GuiManuscript(QDialog): def _openSettingsDialog(self, build: BuildSettings) -> None: """Open the build settings dialog.""" - for obj in self.mainGui.children(): + for obj in SHARED.mainGui.children(): # Don't open a second dialog if one exists if isinstance(obj, GuiBuildSettings): if obj.buildID == build.buildID: @@ -476,7 +470,7 @@ class GuiManuscript(QDialog): obj.raise_() return - dlgSettings = GuiBuildSettings(self.mainGui, build) + dlgSettings = GuiBuildSettings(SHARED.mainGui, build) dlgSettings.setModal(False) dlgSettings.show() dlgSettings.raise_() diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index a27c011f..cd9ac72e 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -25,8 +25,6 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING - from PyQt5.QtCore import QEvent, Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument from PyQt5.QtWidgets import ( @@ -51,9 +49,6 @@ from novelwriter.types import ( QtRoleApply, QtRoleReject, QtUserRole ) -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -72,8 +67,8 @@ class GuiBuildSettings(QDialog): newSettingsReady = pyqtSignal(BuildSettings) - def __init__(self, mainGui: GuiMain, build: BuildSettings) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiBuildSettings") self.setObjectName("GuiBuildSettings") @@ -296,8 +291,8 @@ class _FilterTab(NFixedPage): F_INCLUDED = 2 F_EXCLUDED = 3 - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: - super().__init__(parent=buildMain) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) self._treeMap: dict[str, QTreeWidgetItem] = {} self._build = build @@ -586,8 +581,8 @@ class _HeadingsTab(NScrollablePage): EDIT_HSCENE = 5 EDIT_SECTION = 6 - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: - super().__init__(parent=buildMain) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) self._build = build self._editing = 0 @@ -972,8 +967,8 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter): class _ContentTab(NScrollableForm): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: - super().__init__(parent=buildMain) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) self._build = build @@ -1057,8 +1052,8 @@ class _ContentTab(NScrollableForm): class _FormatTab(NScrollableForm): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: - super().__init__(parent=buildMain) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) self._build = build self._unitScale = 1.0 @@ -1324,8 +1319,8 @@ class _FormatTab(NScrollableForm): class _OutputTab(NScrollableForm): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: - super().__init__(parent=buildMain) + def __init__(self, parent: QWidget, build: BuildSettings) -> None: + super().__init__(parent=parent) self._build = build diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx index 37feacec..40d46cee 100644 --- a/sample/nwProject.nwx +++ b/sample/nwProject.nwx @@ -1,6 +1,6 @@ - - + + Sample Project Jane Smith From a56b38694cd8628f6798eee820864bc63e2e29ac Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 1 May 2024 20:08:35 +0200 Subject: [PATCH 2/3] Create subclasses for non-blocking dialogs --- novelwriter/dialogs/about.py | 6 +-- novelwriter/extensions/modified.py | 49 ++++++++++++++++++++++- novelwriter/guimain.py | 37 +++++------------ novelwriter/tools/dictionaries.py | 10 ++--- novelwriter/tools/manuscript.py | 24 +++++------ novelwriter/tools/manussettings.py | 14 +++---- novelwriter/tools/noveldetails.py | 11 ++--- novelwriter/tools/writingstats.py | 9 ++--- tests/test_tools/test_tools_manuscript.py | 13 +++--- 9 files changed, 99 insertions(+), 74 deletions(-) diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py index 8317a30d..da6ba884 100644 --- a/novelwriter/dialogs/about.py +++ b/novelwriter/dialogs/about.py @@ -27,20 +27,20 @@ import logging from PyQt5.QtGui import QCloseEvent, QColor from PyQt5.QtWidgets import ( - QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, - QWidget + QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED from novelwriter.common import cssCol, readTextFile from novelwriter.extensions.configlayout import NColourLabel +from novelwriter.extensions.modified import NNonBlockingDialog from novelwriter.extensions.versioninfo import VersionInfoWidget from novelwriter.types import QtAlignRightTop, QtDialogClose logger = logging.getLogger(__name__) -class GuiAbout(QDialog): +class GuiAbout(NNonBlockingDialog): def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) diff --git a/novelwriter/extensions/modified.py b/novelwriter/extensions/modified.py index b83a2662..8f185b24 100644 --- a/novelwriter/extensions/modified.py +++ b/novelwriter/extensions/modified.py @@ -6,6 +6,8 @@ File History: Created: 2024-02-01 [2.3b1] NComboBox Created: 2024-02-01 [2.3b1] NSpinBox Created: 2024-02-01 [2.3b1] NDoubleSpinBox +Created: 2024-05-01 [2.5b1] NToolDialog +Created: 2024-05-01 [2.5b1] NNonBlockingDialog This file is a part of novelWriter Copyright 2018–2024, Veronica Berglyd Olsen @@ -29,9 +31,52 @@ from enum import Enum from PyQt5.QtCore import QSize, Qt from PyQt5.QtGui import QWheelEvent -from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget +from PyQt5.QtWidgets import ( + QApplication, QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton, + QWidget +) -from novelwriter import SHARED +from novelwriter import CONFIG, SHARED + + +class NToolDialog(QDialog): + + def __init__(self, parent: QWidget | None = None) -> None: + super().__init__(parent=parent) + self.setModal(False) + if CONFIG.osDarwin: + self.setWindowFlag(Qt.WindowType.Tool) + return + + def activateDialog(self) -> None: + """Helper function to activate dialog on various systems.""" + self.show() + if CONFIG.osWindows: + self.activateWindow() + self.raise_() + QApplication.processEvents() + return + +# END Class NToolDialog + + +class NNonBlockingDialog(QDialog): + + def __init__(self, parent: QWidget | None = None) -> None: + super().__init__(parent=parent) + self.setModal(True) + return + + def activateDialog(self) -> None: + """Helper function to activate dialog on various systems.""" + self.show() + if CONFIG.osWindows: + self.activateWindow() + self.raise_() + QApplication.processEvents() + return + +# END Class NNonBlockingDialog class NComboBox(QComboBox): diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 105d2652..afe7966d 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -23,18 +23,18 @@ along with this program. If not, see . """ from __future__ import annotations -import sys import logging +import sys -from time import time -from pathlib import Path from datetime import datetime +from pathlib import Path +from time import time from PyQt5.QtCore import Qt, QTimer, pyqtSlot from PyQt5.QtGui import QCloseEvent, QCursor, QIcon from PyQt5.QtWidgets import ( - QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, QShortcut, QSplitter, - QStackedWidget, QVBoxLayout, QWidget + QApplication, QFileDialog, QHBoxLayout, QMainWindow, QMessageBox, + QShortcut, QSplitter, QStackedWidget, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED, __hexversion__, __version__ @@ -44,7 +44,7 @@ from novelwriter.dialogs.about import GuiAbout from novelwriter.dialogs.preferences import GuiPreferences from novelwriter.dialogs.projectsettings import GuiProjectSettings from novelwriter.dialogs.wordlist import GuiWordList -from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwWidget, nwView +from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemType, nwView, nwWidget from novelwriter.gui.doceditor import GuiDocEditor from novelwriter.gui.docviewer import GuiDocViewer from novelwriter.gui.docviewerpanel import GuiDocViewerPanel @@ -794,10 +794,7 @@ class GuiMain(QMainWindow): """Open the novel details dialog.""" if SHARED.hasProject: dialog = GuiNovelDetails(self) - dialog.setModal(True) - dialog.show() - dialog.raise_() - QApplication.processEvents() + dialog.activateDialog() dialog.updateValues() return @@ -807,10 +804,7 @@ class GuiMain(QMainWindow): if SHARED.hasProject: if (dialog := SHARED.findTopLevelWidget(GuiManuscript)) is None: dialog = GuiManuscript(self) - dialog.setModal(False) - dialog.show() - dialog.raise_() - QApplication.processEvents() + dialog.activateDialog() dialog.loadContent() return @@ -829,10 +823,7 @@ class GuiMain(QMainWindow): if SHARED.hasProject: if (dialog := SHARED.findTopLevelWidget(GuiWritingStats)) is None: dialog = GuiWritingStats(self) - dialog.setModal(False) - dialog.show() - dialog.raise_() - QApplication.processEvents() + dialog.activateDialog() dialog.populateGUI() return @@ -840,10 +831,7 @@ class GuiMain(QMainWindow): def showAboutNWDialog(self) -> None: """Show the novelWriter about dialog.""" dialog = GuiAbout(self) - dialog.setModal(True) - dialog.show() - dialog.raise_() - QApplication.processEvents() + dialog.activateDialog() dialog.populateGUI() return @@ -858,10 +846,7 @@ class GuiMain(QMainWindow): def showDictionariesDialog(self) -> None: """Show the download dictionaries dialog.""" dialog = GuiDictionaries(self) - dialog.setModal(True) - dialog.show() - dialog.raise_() - QApplication.processEvents() + dialog.activateDialog() if not dialog.initDialog(): dialog.close() SHARED.error(self.tr("Could not initialise the dialog.")) diff --git a/novelwriter/tools/dictionaries.py b/novelwriter/tools/dictionaries.py index a2607e63..982ebcc9 100644 --- a/novelwriter/tools/dictionaries.py +++ b/novelwriter/tools/dictionaries.py @@ -31,20 +31,20 @@ from zipfile import ZipFile from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QCloseEvent, QTextCursor from PyQt5.QtWidgets import ( - QApplication, QDialog, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, - QLabel, QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget + QApplication, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel, + QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED -from novelwriter.common import formatFileFilter, openExternalPath, formatInt, getFileSize +from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath from novelwriter.error import formatException -from novelwriter.extensions.modified import NIconToolButton +from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog from novelwriter.types import QtDialogClose logger = logging.getLogger(__name__) -class GuiDictionaries(QDialog): +class GuiDictionaries(NNonBlockingDialog): def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index f84dfa1a..6bdbdeae 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -33,8 +33,8 @@ from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog from PyQt5.QtWidgets import ( - QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout, - QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, QSplitter, + QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout, + QLabel, QListWidget, QListWidgetItem, QPushButton, QSplitter, QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget ) @@ -47,7 +47,7 @@ from novelwriter.core.tohtml import ToHtml from novelwriter.core.tokenizer import HeadingFormatter from novelwriter.error import logException from novelwriter.extensions.circularprogress import NProgressCircle -from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton +from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON from novelwriter.tools.manusbuild import GuiManuscriptBuild from novelwriter.tools.manussettings import GuiBuildSettings @@ -59,7 +59,7 @@ from novelwriter.types import ( logger = logging.getLogger(__name__) -class GuiManuscript(QDialog): +class GuiManuscript(NToolDialog): """GUI Tools: Manuscript Tool The dialog displays all the users build definitions, a preview panel @@ -74,8 +74,6 @@ class GuiManuscript(QDialog): logger.debug("Create: GuiManuscript") self.setObjectName("GuiManuscript") - if CONFIG.osDarwin: - self.setWindowFlag(Qt.WindowType.Tool) self._builds = BuildCollection(SHARED.project) self._buildMap: dict[str, QListWidgetItem] = {} @@ -466,17 +464,13 @@ class GuiManuscript(QDialog): if isinstance(obj, GuiBuildSettings): if obj.buildID == build.buildID: logger.debug("Found instance of GuiBuildSettings") - obj.show() - obj.raise_() + obj.activateDialog() return - dlgSettings = GuiBuildSettings(SHARED.mainGui, build) - dlgSettings.setModal(False) - dlgSettings.show() - dlgSettings.raise_() - QApplication.processEvents() - dlgSettings.loadContent() - dlgSettings.newSettingsReady.connect(self._processNewSettings) + dialog = GuiBuildSettings(SHARED.mainGui, build) + dialog.activateDialog() + dialog.loadContent() + dialog.newSettingsReady.connect(self._processNewSettings) return diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index cd9ac72e..e138b592 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -25,11 +25,11 @@ from __future__ import annotations import logging -from PyQt5.QtCore import QEvent, Qt, pyqtSignal, pyqtSlot +from PyQt5.QtCore import QEvent, pyqtSignal, pyqtSlot from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument from PyQt5.QtWidgets import ( - QAbstractButton, QAbstractItemView, QDialog, QDialogButtonBox, QFontDialog, - QFrame, QGridLayout, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu, + QAbstractButton, QAbstractItemView, QDialogButtonBox, QFontDialog, QFrame, + QGridLayout, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu, QPlainTextEdit, QPushButton, QSplitter, QStackedWidget, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget ) @@ -40,7 +40,9 @@ from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.extensions.configlayout import ( NColourLabel, NFixedPage, NScrollableForm, NScrollablePage ) -from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox +from novelwriter.extensions.modified import ( + NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox, NToolDialog +) from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.switchbox import NSwitchBox @@ -52,7 +54,7 @@ from novelwriter.types import ( logger = logging.getLogger(__name__) -class GuiBuildSettings(QDialog): +class GuiBuildSettings(NToolDialog): """GUI Tools: Manuscript Build Settings Dialog The main tool for configuring manuscript builds. It's a GUI tool for @@ -72,8 +74,6 @@ class GuiBuildSettings(QDialog): logger.debug("Create: GuiBuildSettings") self.setObjectName("GuiBuildSettings") - if CONFIG.osDarwin: - self.setWindowFlag(Qt.WindowType.Tool) self._build = build diff --git a/novelwriter/tools/noveldetails.py b/novelwriter/tools/noveldetails.py index 08755425..91d95651 100644 --- a/novelwriter/tools/noveldetails.py +++ b/novelwriter/tools/noveldetails.py @@ -23,21 +23,22 @@ along with this program. If not, see . """ from __future__ import annotations -import math import logging +import math from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import ( - QAbstractItemView, QDialog, QDialogButtonBox, QFormLayout, QGridLayout, - QHBoxLayout, QLabel, QSpinBox, QStackedWidget, QTreeWidget, - QTreeWidgetItem, QVBoxLayout, QWidget + QAbstractItemView, QDialogButtonBox, QFormLayout, QGridLayout, QHBoxLayout, + QLabel, QSpinBox, QStackedWidget, QTreeWidget, QTreeWidgetItem, + QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED from novelwriter.common import formatTime, numberToRoman from novelwriter.constants import nwUnicode from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage +from novelwriter.extensions.modified import NNonBlockingDialog from novelwriter.extensions.novelselector import NovelSelector from novelwriter.extensions.pagedsidebar import NPagedSideBar from novelwriter.extensions.switch import NSwitch @@ -46,7 +47,7 @@ from novelwriter.types import QtAlignRight, QtDecoration, QtDialogClose logger = logging.getLogger(__name__) -class GuiNovelDetails(QDialog): +class GuiNovelDetails(NNonBlockingDialog): PAGE_OVERVIEW = 1 PAGE_CONTENTS = 2 diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py index 1a12e40f..ad0a5508 100644 --- a/novelwriter/tools/writingstats.py +++ b/novelwriter/tools/writingstats.py @@ -32,15 +32,16 @@ from typing import TYPE_CHECKING from PyQt5.QtCore import Qt, pyqtSlot from PyQt5.QtGui import QCloseEvent, QCursor, QPixmap from PyQt5.QtWidgets import ( - QAction, QApplication, QDialog, QDialogButtonBox, QFileDialog, QGridLayout, + QAction, QApplication, QDialogButtonBox, QFileDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QMenu, QSpinBox, QTreeWidget, QTreeWidgetItem ) from novelwriter import CONFIG, SHARED -from novelwriter.common import formatTime, checkInt, checkIntTuple, minmax +from novelwriter.common import checkInt, checkIntTuple, formatTime, minmax from novelwriter.constants import nwConst from novelwriter.error import formatException +from novelwriter.extensions.modified import NToolDialog from novelwriter.extensions.switch import NSwitch from novelwriter.types import ( QtAlignLeftMiddle, QtAlignRight, QtAlignRightMiddle, QtDecoration, @@ -53,7 +54,7 @@ if TYPE_CHECKING: # pragma: no cover logger = logging.getLogger(__name__) -class GuiWritingStats(QDialog): +class GuiWritingStats(NToolDialog): """GUI Tools: Writing Statistics Displays data from the NWSessionLog object. @@ -73,8 +74,6 @@ class GuiWritingStats(QDialog): logger.debug("Create: GuiWritingStats") self.setObjectName("GuiWritingStats") - if CONFIG.osDarwin: - self.setWindowFlag(Qt.WindowType.Tool) self.logData = [] self.filterData = [] diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index 5e80767f..b134b5c2 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -20,18 +20,18 @@ along with this program. If not, see . """ from __future__ import annotations -import pytest import sys from pathlib import Path -from pytestqt.qtbot import QtBot + +import pytest from mocked import causeOSError -from tools import C, buildTestProject - from PyQt5.QtCore import pyqtSlot from PyQt5.QtPrintSupport import QPrintPreviewDialog from PyQt5.QtWidgets import QAction, QListWidgetItem +from pytestqt.qtbot import QtBot +from tools import C, buildTestProject from novelwriter import CONFIG, SHARED from novelwriter.constants import nwHeadFmt @@ -127,8 +127,10 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): # Edit the new build manus.buildList.clearSelection() manus.buildList.setCurrentRow(0) - manus.tbEdit.click() + with qtbot.waitSignal(manus.tbEdit.clicked, timeout=5000): + manus.tbEdit.click() + manus._editSelectedBuild() bSettings = SHARED.findTopLevelWidget(GuiBuildSettings) assert isinstance(bSettings, GuiBuildSettings) build = None @@ -147,7 +149,6 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): # May have been garbage collected, but if it isn't, it should be hidden assert bSettings.isVisible() is False - # Finish # qtbot.stop() # END Test testManuscript_Builds From 53d410a6eecbe9d991ec9be61e6af40f35558e26 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 1 May 2024 20:18:08 +0200 Subject: [PATCH 3/3] Make sure build settings are closed before deletion --- novelwriter/tools/manuscript.py | 21 ++++++++++++++------- tests/test_tools/test_tools_manuscript.py | 9 ++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index 6bdbdeae..c3dac96b 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -311,6 +311,8 @@ class GuiManuscript(NToolDialog): """Delete the currently selected build settings entry.""" if build := self._getSelectedBuild(): if SHARED.question(self.tr("Delete build '{0}'?".format(build.name))): + if dialog := self._findSettingsDialog(build.buildID): + dialog.close() self._builds.removeBuild(build.buildID) self._updateBuildsList() return @@ -459,13 +461,9 @@ class GuiManuscript(NToolDialog): def _openSettingsDialog(self, build: BuildSettings) -> None: """Open the build settings dialog.""" - for obj in SHARED.mainGui.children(): - # Don't open a second dialog if one exists - if isinstance(obj, GuiBuildSettings): - if obj.buildID == build.buildID: - logger.debug("Found instance of GuiBuildSettings") - obj.activateDialog() - return + if dialog := self._findSettingsDialog(build.buildID): + dialog.activateDialog() + return dialog = GuiBuildSettings(SHARED.mainGui, build) dialog.activateDialog() @@ -495,6 +493,15 @@ class GuiManuscript(NToolDialog): self._updateBuildsList() return + def _findSettingsDialog(self, buildID: str) -> GuiBuildSettings | None: + """Return an open build settings dialog for a given build, if + one exists. + """ + for obj in SHARED.mainGui.children(): + if isinstance(obj, GuiBuildSettings) and obj.buildID == buildID: + return obj + return None + # END Class GuiManuscript diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index b134b5c2..ec88349a 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -98,7 +98,14 @@ def testManuscript_Builds(qtbot: QtBot, nwGUI: GuiMain, projPath: Path): manus.show() manus.loadContent() - # Delete the default build + # Delete the default build, while it is open + manus.buildList.clearSelection() + manus.buildList.setCurrentRow(0) + with qtbot.waitSignal(manus.tbEdit.clicked, timeout=5000): + manus.tbEdit.click() + + manus._editSelectedBuild() + manus.buildList.clearSelection() manus.buildList.setCurrentRow(0) manus.tbDel.click()