Refactor Main GUI inheritance (#1849)
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -28,6 +28,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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")
|
||||
|
||||
+13
-23
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
+37
-39
@@ -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
|
||||
|
||||
|
||||
+16
-8
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.5a3" hexVersion="0x020500a3" fileVersion="1.5" fileRevision="4" timeStamp="2024-05-01 19:43:08">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1917" autoCount="274" editTime="87503">
|
||||
<novelWriterXML appVersion="2.5a3" hexVersion="0x020500a3" fileVersion="1.5" fileRevision="4" timeStamp="2024-05-02 21:45:22">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1918" autoCount="274" editTime="87508">
|
||||
<name>Sample Project</name>
|
||||
<author>Jane Smith</author>
|
||||
</project>
|
||||
@@ -58,7 +58,7 @@
|
||||
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
|
||||
</item>
|
||||
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
<meta expanded="no" heading="H3" charCount="2953" wordCount="520" paraCount="15" cursorPos="2155" />
|
||||
<meta expanded="no" heading="H3" charCount="2953" wordCount="520" paraCount="15" cursorPos="19" />
|
||||
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
|
||||
@@ -21,24 +21,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user