diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py index 54ec2f2f..721ab91e 100644 --- a/novelwriter/dialogs/wordlist.py +++ b/novelwriter/dialogs/wordlist.py @@ -25,14 +25,13 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING from pathlib import Path from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import ( QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog, - QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout + QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED @@ -42,9 +41,6 @@ from novelwriter.extensions.configlayout import NColourLabel from novelwriter.extensions.modified import NIconToolButton from novelwriter.types import QtDialogClose, QtDialogSave -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -52,8 +48,8 @@ class GuiWordList(QDialog): newWordListReady = pyqtSignal() - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiWordList") self.setObjectName("GuiWordList") diff --git a/novelwriter/extensions/modified.py b/novelwriter/extensions/modified.py index 8f185b24..450647ac 100644 --- a/novelwriter/extensions/modified.py +++ b/novelwriter/extensions/modified.py @@ -28,6 +28,7 @@ along with this program. If not, see . from __future__ import annotations from enum import Enum +from typing import TYPE_CHECKING from PyQt5.QtCore import QSize, Qt from PyQt5.QtGui import QWheelEvent @@ -38,10 +39,13 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED +if TYPE_CHECKING: # pragma: no cover + from novelwriter.guimain import GuiMain + class NToolDialog(QDialog): - def __init__(self, parent: QWidget | None = None) -> None: + def __init__(self, parent: GuiMain) -> None: super().__init__(parent=parent) self.setModal(False) if CONFIG.osDarwin: diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 7ed3fab7..662b1c35 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -36,7 +36,6 @@ import logging from enum import Enum from time import time -from typing import TYPE_CHECKING from PyQt5.QtCore import ( QObject, QPoint, QRegularExpression, QRunnable, Qt, QTimer, pyqtSignal, @@ -69,9 +68,6 @@ from novelwriter.types import ( QtMoveAnchor, QtMoveLeft, QtMoveRight ) -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -107,15 +103,14 @@ class GuiDocEditor(QPlainTextEdit): requestProjectItemSelected = pyqtSignal(str, bool) requestProjectItemRenamed = pyqtSignal(str, str) requestNewNoteCreation = pyqtSignal(str, nwItemClass) + requestNextDocument = pyqtSignal(str, bool) - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiDocEditor") # Class Variables - self.mainGui = mainGui - self._nwDocument = None self._nwItem = None @@ -477,7 +472,6 @@ class GuiDocEditor(QPlainTextEdit): cC, wC, pC = standardCounter(docText) self._updateDocCounts(cC, wC, pC) - self.saveCursorPosition() if not self._nwDocument.writeDocument(docText): saveOk = False if self._nwDocument.hashError: @@ -1320,9 +1314,8 @@ class GuiDocEditor(QPlainTextEdit): self.docSearch.setResultCount(0, 0) self._lastFind = None if CONFIG.searchNextFile and not goBack: - self.mainGui.openNextDocument( - self._docHandle, wrapAround=CONFIG.searchLoop - ) + self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) + QApplication.processEvents() self.beginSearch() self.setFocus() return @@ -1341,9 +1334,8 @@ class GuiDocEditor(QPlainTextEdit): if resIdx > maxIdx and self._docHandle: if CONFIG.searchNextFile and not goBack: - self.mainGui.openNextDocument( - self._docHandle, wrapAround=CONFIG.searchLoop - ) + self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop) + QApplication.processEvents() self.beginSearch() self.setFocus() return diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py index 7d6b05cf..6ac50c19 100644 --- a/novelwriter/gui/mainmenu.py +++ b/novelwriter/gui/mainmenu.py @@ -25,16 +25,16 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING from pathlib import Path +from typing import TYPE_CHECKING -from PyQt5.QtGui import QDesktopServices from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot -from PyQt5.QtWidgets import QMenuBar, QAction +from PyQt5.QtGui import QDesktopServices +from PyQt5.QtWidgets import QAction, QMenuBar from novelwriter import CONFIG, SHARED from novelwriter.common import openExternalPath -from novelwriter.constants import nwConst, trConst, nwKeyWords, nwLabels, nwUnicode +from novelwriter.constants import nwConst, nwKeyWords, nwLabels, nwUnicode, trConst from novelwriter.enum import nwDocAction, nwDocInsert, nwView, nwWidget from novelwriter.extensions.eventfilters import StatusTipFilter @@ -202,7 +202,7 @@ class GuiMainMenu(QMenuBar): # Document > Save self.aSaveDoc = self.docuMenu.addAction(self.tr("Save Document")) self.aSaveDoc.setShortcut("Ctrl+S") - self.aSaveDoc.triggered.connect(self.mainGui.saveDocument) + self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument) # Document > Close self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document")) diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index 6643df47..68aa8c46 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -29,9 +29,8 @@ import logging from enum import Enum from time import time -from typing import TYPE_CHECKING -from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSlot, pyqtSignal +from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent from PyQt5.QtWidgets import ( QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, @@ -52,9 +51,6 @@ from novelwriter.types import ( QtUserRole ) -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -74,10 +70,8 @@ class GuiNovelView(QWidget): selectedItemChanged = pyqtSignal(str) openDocumentRequest = pyqtSignal(str, Enum, str, bool) - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) - - self.mainGui = mainGui + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) # Build GUI self.novelTree = GuiNovelTree(self) @@ -202,7 +196,6 @@ class GuiNovelToolBar(QWidget): logger.debug("Create: GuiNovelToolBar") self.novelView = novelView - self.mainGui = novelView.mainGui iSz = SHARED.theme.baseIconSize mPx = CONFIG.pxInt(2) @@ -378,7 +371,6 @@ class GuiNovelTree(QTreeWidget): logger.debug("Create: GuiNovelTree") self.novelView = novelView - self.mainGui = novelView.mainGui # Internal Variables self._treeMap = {} @@ -493,7 +485,7 @@ class GuiNovelTree(QTreeWidget): if rootHandle is None: rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL) - treeChanged = self.mainGui.projView.changedSince(self._lastBuild) + treeChanged = SHARED.mainGui.projView.changedSince(self._lastBuild) indexChanged = SHARED.project.index.rootChangedSince(rootHandle, self._lastBuild) if not (treeChanged or indexChanged or overRide): logger.debug("No changes have been made to the novel index") diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 8074325b..34a324da 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -30,12 +30,9 @@ import logging from enum import Enum from time import time -from typing import TYPE_CHECKING -from PyQt5.QtCore import QPoint, QTimer, Qt, pyqtSignal, pyqtSlot -from PyQt5.QtGui import ( - QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette -) +from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette from PyQt5.QtWidgets import ( QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView, QLabel, QMenu, QShortcut, QTreeWidget, QTreeWidgetItem, QVBoxLayout, @@ -44,24 +41,21 @@ from PyQt5.QtWidgets import ( from novelwriter import CONFIG, SHARED from novelwriter.common import minmax -from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels +from novelwriter.constants import nwHeaders, nwLabels, nwUnicode, trConst from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter from novelwriter.core.item import NWItem from novelwriter.dialogs.docmerge import GuiDocMerge from novelwriter.dialogs.docsplit import GuiDocSplit from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.projectsettings import GuiProjectSettings -from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout +from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType from novelwriter.extensions.modified import NIconToolButton from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON from novelwriter.types import ( QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtSizeExpanding, - QtUserRole, + QtUserRole ) -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) @@ -83,10 +77,8 @@ class GuiProjectView(QWidget): # Requests for the main GUI projectSettingsRequest = pyqtSignal(int) - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) - - self.mainGui = mainGui + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) # Build GUI self.projTree = GuiProjectTree(self) @@ -265,7 +257,6 @@ class GuiProjectToolBar(QWidget): self.projView = projView self.projTree = projView.projTree - self.mainGui = projView.mainGui iSz = SHARED.theme.baseIconSize mPx = CONFIG.pxInt(2) @@ -501,7 +492,6 @@ class GuiProjectTree(QTreeWidget): logger.debug("Create: GuiProjectTree") self.projView = projView - self.mainGui = projView.mainGui # Internal Variables self._treeMap: dict[str, QTreeWidgetItem] = {} @@ -1012,8 +1002,7 @@ class GuiProjectTree(QTreeWidget): trItemP.takeChild(tIndex) for dHandle in reversed(self.getTreeFromHandle(tHandle)): - if self.mainGui.docEditor.docHandle == dHandle: - self.mainGui.closeDocument() + SHARED.closeDocument(dHandle) SHARED.project.removeItem(dHandle) self._treeMap.pop(dHandle, None) @@ -1412,7 +1401,7 @@ class GuiProjectTree(QTreeWidget): if not newFile: itemList.remove(tHandle) - dlgMerge = GuiDocMerge(self.mainGui, tHandle, itemList) + dlgMerge = GuiDocMerge(SHARED.mainGui, tHandle, itemList) dlgMerge.exec() if dlgMerge.result() == QDialog.DialogCode.Accepted: @@ -1424,7 +1413,7 @@ class GuiProjectTree(QTreeWidget): return False # Save the open document first, in case it's part of merge - self.mainGui.saveDocument() + SHARED.saveDocument() # Create merge object, and append docs docMerger = DocMerger(SHARED.project) @@ -1453,7 +1442,8 @@ class GuiProjectTree(QTreeWidget): if newFile: self.revealNewTreeItem(mHandle, nHandle=tHandle, wordCount=True) - self.mainGui.openDocument(mHandle, doScroll=True) + self.projView.openDocumentRequest.emit(mHandle, nwDocMode.EDIT, "", False) + self.projView.setSelectedHandle(mHandle, doScroll=True) if mrgData.get("moveToTrash", False): for sHandle in reversed(mrgData.get("finalItems", [])): @@ -1482,7 +1472,7 @@ class GuiProjectTree(QTreeWidget): logger.error("Only valid document items can be split") return False - dlgSplit = GuiDocSplit(self.mainGui, tHandle) + dlgSplit = GuiDocSplit(SHARED.mainGui, tHandle) dlgSplit.exec() if dlgSplit.result() == QDialog.DialogCode.Accepted: diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index 93ee759b..17d18f53 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -259,7 +259,7 @@ class GuiProjectSearch(QWidget): if not self._blocked: QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) start = time() - SHARED.mainGui.saveDocument() + SHARED.saveDocument() self._blocked = True self._map = {} self.searchResult.clear() diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py index d5dce50d..0620ad2d 100644 --- a/novelwriter/gui/sidebar.py +++ b/novelwriter/gui/sidebar.py @@ -27,8 +27,8 @@ import logging from typing import TYPE_CHECKING -from PyQt5.QtGui import QPalette from PyQt5.QtCore import QEvent, QPoint, QSize, pyqtSignal +from PyQt5.QtGui import QPalette from PyQt5.QtWidgets import QMenu, QVBoxLayout, QWidget from novelwriter import CONFIG, SHARED @@ -58,7 +58,7 @@ class GuiSideBar(QWidget): iSz = QSize(iPx, iPx) self.setContentsMargins(0, 0, 0, 0) - self.installEventFilter(StatusTipFilter(mainGui)) + self.installEventFilter(StatusTipFilter(self.mainGui)) # Buttons self.tbProject = NIconToolButton(self, iSz) diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py index 1992d609..6b51731a 100644 --- a/novelwriter/gui/statusbar.py +++ b/novelwriter/gui/statusbar.py @@ -27,26 +27,23 @@ import logging from datetime import datetime from time import time -from typing import TYPE_CHECKING, Literal +from typing import Literal -from PyQt5.QtCore import pyqtSlot, QLocale -from PyQt5.QtWidgets import QApplication, QStatusBar, QLabel +from PyQt5.QtCore import QLocale, pyqtSlot +from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget from novelwriter import CONFIG, SHARED from novelwriter.common import formatTime from novelwriter.constants import nwConst from novelwriter.extensions.statusled import StatusLED -if TYPE_CHECKING: # pragma: no cover - from novelwriter.guimain import GuiMain - logger = logging.getLogger(__name__) class GuiMainStatus(QStatusBar): - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: QWidget) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiMainStatus") @@ -238,6 +235,7 @@ class GuiMainStatus(QStatusBar): before starting novelWriter. """ import tracemalloc + from collections import Counter widgets = QApplication.allWidgets() diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index afe7966d..e35699e8 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -263,6 +263,7 @@ class GuiMain(QMainWindow): self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem) self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote) self.docEditor.docTextChanged.connect(self.projSearch.textChanged) + self.docEditor.requestNextDocument.connect(self.openNextDocument) self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle) self.docViewer.loadDocumentTagRequest.connect(self._followTag) @@ -369,9 +370,7 @@ class GuiMain(QMainWindow): if not msgYes: return False - if self.docEditor.docChanged: - self.saveDocument() - + self.saveDocument() saveOK = self.saveProject() doBackup = False if SHARED.project.data.doBackup and CONFIG.backupOnClose: @@ -514,9 +513,7 @@ class GuiMain(QMainWindow): # Disable focus mode if it is active if SHARED.focusMode: SHARED.setFocusMode(False) - self.docEditor.saveCursorPosition() - if self.docEditor.docChanged: - self.saveDocument() + self.saveDocument() self.docEditor.clearEditor() if not beforeOpen: self.novelView.setActiveHandle(None) @@ -553,42 +550,43 @@ class GuiMain(QMainWindow): return True - def openNextDocument(self, tHandle: str, wrapAround: bool = False) -> bool: + @pyqtSlot(str, bool) + def openNextDocument(self, tHandle: str, wrapAround: bool) -> None: """Open the next document in the project tree, following the document with the given handle. Stop when reaching the end. """ - if not SHARED.hasProject: - logger.error("No project open") - return False + if SHARED.hasProject: + nHandle = None # The next handle after tHandle + fHandle = None # The first file handle we encounter + foundIt = False # We've found tHandle, pick the next we see + for tItem in SHARED.project.tree: + if not tItem.isFileType(): + continue + if fHandle is None: + fHandle = tItem.itemHandle + if tItem.itemHandle == tHandle: + foundIt = True + elif foundIt: + nHandle = tItem.itemHandle + break + if nHandle is not None: + self.openDocument(nHandle, tLine=1, doScroll=True) + elif wrapAround: + self.openDocument(fHandle, tLine=1, doScroll=True) + return - nHandle = None # The next handle after tHandle - fHandle = None # The first file handle we encounter - foundIt = False # We've found tHandle, pick the next we see - for tItem in SHARED.project.tree: - if not tItem.isFileType(): - continue - if fHandle is None: - fHandle = tItem.itemHandle - if tItem.itemHandle == tHandle: - foundIt = True - elif foundIt: - nHandle = tItem.itemHandle - break - - if nHandle is not None: - self.openDocument(nHandle, tLine=1, doScroll=True) - return True - elif wrapAround: - self.openDocument(fHandle, tLine=1, doScroll=True) - return False - - return False - - @pyqtSlot() - def saveDocument(self) -> None: + def saveDocument(self, force: bool = False) -> None: """Save the current documents.""" if SHARED.hasProject: - self.docEditor.saveText() + self.docEditor.saveCursorPosition() + if force or self.docEditor.docChanged: + self.docEditor.saveText() + return + + @pyqtSlot() + def forceSaveDocument(self) -> None: + """Save document even of it has not changed.""" + self.saveDocument(force=True) return def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool: @@ -1133,7 +1131,7 @@ class GuiMain(QMainWindow): @pyqtSlot() def _reloadViewer(self) -> None: """Reload the document in the viewer.""" - if self.docEditor.docChanged and self.docEditor.docHandle == self.docViewer.docHandle: + if self.docEditor.docHandle == self.docViewer.docHandle: # If the two panels have the same document, save any changes in the editor self.saveDocument() self.docViewer.reloadText() @@ -1213,7 +1211,7 @@ class GuiMain(QMainWindow): doSave &= SHARED.project.projChanged doSave &= SHARED.project.storage.isOpen() if doSave: - logger.debug("Autosaving project") + logger.debug("Auto-saving project") self.saveProject(autoSave=True) return @@ -1221,7 +1219,7 @@ class GuiMain(QMainWindow): def _autoSaveDocument(self) -> None: """Autosave of the document. This is a timer-activated slot.""" if SHARED.hasProject and self.docEditor.docChanged: - logger.debug("Autosaving document") + logger.debug("Auto-saving document") self.saveDocument() return diff --git a/novelwriter/shared.py b/novelwriter/shared.py index be323386..6586f676 100644 --- a/novelwriter/shared.py +++ b/novelwriter/shared.py @@ -171,6 +171,17 @@ class SharedData(QObject): logger.debug("Thread Pool Max Count: %d", QThreadPool.globalInstance().maxThreadCount()) return + def closeDocument(self, tHandle: str | None = None) -> None: + """Close the document editor, optionally a specific document.""" + if tHandle is None or tHandle == self.mainGui.docEditor.docHandle: + self.mainGui.closeDocument() + return + + def saveDocument(self) -> None: + """Forward save document call to main GUI.""" + self.mainGui.saveDocument() + return + def openProject(self, path: str | Path, clearLock: bool = False) -> bool: """Open a project.""" if self.project.isValid: @@ -198,7 +209,7 @@ class SharedData(QObject): def closeProject(self) -> None: """Close the current project.""" - self._closeDialogs() + self._closeToolDialogs() self.project.closeProject(self._idleTime) self._resetProject() self._resetIdleTimer() @@ -357,15 +368,12 @@ class SharedData(QObject): self._idleTime = 0.0 return - def _closeDialogs(self) -> None: - """Close non-modal dialogs.""" - from novelwriter.tools.manuscript import GuiManuscript - from novelwriter.tools.writingstats import GuiWritingStats - + def _closeToolDialogs(self) -> None: + """Close all open tool dialogs.""" + from novelwriter.extensions.modified import NToolDialog for widget in self.mainGui.children(): - if isinstance(widget, (GuiManuscript, GuiWritingStats)): + if isinstance(widget, NToolDialog): widget.close() - return # END Class SharedData diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py index e27e8b6a..8b6cdb0e 100644 --- a/novelwriter/tools/manusbuild.py +++ b/novelwriter/tools/manusbuild.py @@ -327,7 +327,7 @@ class GuiManuscriptBuild(QDialog): return False # Make sure editor content is saved before we start - SHARED.mainGui.saveDocument() + SHARED.saveDocument() docBuild = NWBuildDocument(SHARED.project, self._build) docBuild.queueAll() diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index 58c4ec53..47bbdc10 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -28,6 +28,7 @@ import logging from datetime import datetime from time import time +from typing import TYPE_CHECKING from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent @@ -56,6 +57,9 @@ from novelwriter.types import ( QtSizeExpanding, QtSizeIgnored, QtUserRole ) +if TYPE_CHECKING: # pragma: no cover + from novelwriter.guimain import GuiMain + logger = logging.getLogger(__name__) @@ -69,7 +73,7 @@ class GuiManuscript(NToolDialog): D_KEY = QtUserRole - def __init__(self, parent: QWidget) -> None: + def __init__(self, parent: GuiMain) -> None: super().__init__(parent=parent) logger.debug("Create: GuiManuscript") @@ -335,7 +339,7 @@ class GuiManuscript(NToolDialog): return # Make sure editor content is saved before we start - SHARED.mainGui.saveDocument() + SHARED.saveDocument() docBuild = NWBuildDocument(SHARED.project, build) docBuild.setPreviewMode(True) diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index e138b592..77b8035a 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -25,6 +25,8 @@ from __future__ import annotations import logging +from typing import TYPE_CHECKING + from PyQt5.QtCore import QEvent, pyqtSignal, pyqtSlot from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument from PyQt5.QtWidgets import ( @@ -51,6 +53,9 @@ from novelwriter.types import ( QtRoleApply, QtRoleReject, QtUserRole ) +if TYPE_CHECKING: # pragma: no cover + from novelwriter.guimain import GuiMain + logger = logging.getLogger(__name__) @@ -69,7 +74,7 @@ class GuiBuildSettings(NToolDialog): newSettingsReady = pyqtSignal(BuildSettings) - def __init__(self, parent: QWidget, build: BuildSettings) -> None: + def __init__(self, parent: GuiMain, build: BuildSettings) -> None: super().__init__(parent=parent) logger.debug("Create: GuiBuildSettings") diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py index ad0a5508..cc59f9f0 100644 --- a/novelwriter/tools/writingstats.py +++ b/novelwriter/tools/writingstats.py @@ -69,8 +69,8 @@ class GuiWritingStats(NToolDialog): FMT_JSON = 0 FMT_CSV = 1 - def __init__(self, mainGui: GuiMain) -> None: - super().__init__(parent=mainGui) + def __init__(self, parent: GuiMain) -> None: + super().__init__(parent=parent) logger.debug("Create: GuiWritingStats") self.setObjectName("GuiWritingStats") diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx index 40d46cee..5aa8cdba 100644 --- a/sample/nwProject.nwx +++ b/sample/nwProject.nwx @@ -1,6 +1,6 @@ - - + + Sample Project Jane Smith @@ -58,7 +58,7 @@ Chapter One - + Making a Scene diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py index dc6ffcfc..2a2205e8 100644 --- a/tests/test_gui/test_gui_guimain.py +++ b/tests/test_gui/test_gui_guimain.py @@ -21,24 +21,25 @@ along with this program. If not, see . from __future__ import annotations import sys -import pytest from shutil import copyfile -from tools import C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE +import pytest -from PyQt5.QtGui import QPalette from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QMenu, QInputDialog +from PyQt5.QtGui import QPalette +from PyQt5.QtWidgets import QInputDialog, QMenu from novelwriter import CONFIG, SHARED +from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.enum import nwItemType, nwView, nwWidget -from novelwriter.gui.outline import GuiOutlineView -from novelwriter.gui.projtree import GuiProjectTree from novelwriter.gui.doceditor import GuiDocEditor from novelwriter.gui.noveltree import GuiNovelView +from novelwriter.gui.outline import GuiOutlineView +from novelwriter.gui.projtree import GuiProjectTree from novelwriter.tools.welcome import GuiWelcome -from novelwriter.dialogs.editlabel import GuiEditLabel + +from tests.tools import NWD_IGNORE, XML_IGNORE, C, buildTestProject, cmpFiles KEY_DELAY = 1 @@ -50,7 +51,6 @@ def testGuiMain_ProjectBlocker(nwGUI): assert nwGUI.closeProject() is True assert nwGUI.saveProject() is False assert nwGUI.openDocument(None) is False - assert nwGUI.openNextDocument(None) is False assert nwGUI.viewDocument(None) is False assert nwGUI.importDocument() is False @@ -84,7 +84,7 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath): nwGUI.closeProject() # Check that latest release info updated - CONFIG.lastNotes != "0x0" + assert CONFIG.lastNotes != "0x0" # Check that project open dialog launches nwGUI.postLaunchTasks(None) @@ -522,6 +522,8 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd): assert docEditor.docChanged nwGUI.saveDocument() assert docEditor.docChanged is False + nwGUI.forceSaveDocument() + assert docEditor.docChanged is False nwGUI.rebuildIndex() # Open and view the edited document