Clean up Main GUI inheritance

This commit is contained in:
Veronica Berglyd Olsen
2024-05-02 22:13:35 +02:00
parent e75b5e012c
commit 2b8338f537
10 changed files with 68 additions and 96 deletions
+3 -7
View File
@@ -25,14 +25,13 @@ from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING
from pathlib import Path from pathlib import Path
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent from PyQt5.QtGui import QCloseEvent
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog, QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog,
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout, QWidget
) )
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
@@ -42,9 +41,6 @@ from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.modified import NIconToolButton from novelwriter.extensions.modified import NIconToolButton
from novelwriter.types import QtDialogClose, QtDialogSave from novelwriter.types import QtDialogClose, QtDialogSave
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -52,8 +48,8 @@ class GuiWordList(QDialog):
newWordListReady = pyqtSignal() newWordListReady = pyqtSignal()
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
logger.debug("Create: GuiWordList") logger.debug("Create: GuiWordList")
self.setObjectName("GuiWordList") self.setObjectName("GuiWordList")
+7 -14
View File
@@ -36,7 +36,6 @@ import logging
from enum import Enum from enum import Enum
from time import time from time import time
from typing import TYPE_CHECKING
from PyQt5.QtCore import ( from PyQt5.QtCore import (
QObject, QPoint, QRegularExpression, QRunnable, Qt, QTimer, pyqtSignal, QObject, QPoint, QRegularExpression, QRunnable, Qt, QTimer, pyqtSignal,
@@ -69,9 +68,6 @@ from novelwriter.types import (
QtMoveAnchor, QtMoveLeft, QtMoveRight QtMoveAnchor, QtMoveLeft, QtMoveRight
) )
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -107,15 +103,14 @@ class GuiDocEditor(QPlainTextEdit):
requestProjectItemSelected = pyqtSignal(str, bool) requestProjectItemSelected = pyqtSignal(str, bool)
requestProjectItemRenamed = pyqtSignal(str, str) requestProjectItemRenamed = pyqtSignal(str, str)
requestNewNoteCreation = pyqtSignal(str, nwItemClass) requestNewNoteCreation = pyqtSignal(str, nwItemClass)
requestNextDocument = pyqtSignal(str, bool)
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
logger.debug("Create: GuiDocEditor") logger.debug("Create: GuiDocEditor")
# Class Variables # Class Variables
self.mainGui = mainGui
self._nwDocument = None self._nwDocument = None
self._nwItem = None self._nwItem = None
@@ -1319,9 +1314,8 @@ class GuiDocEditor(QPlainTextEdit):
self.docSearch.setResultCount(0, 0) self.docSearch.setResultCount(0, 0)
self._lastFind = None self._lastFind = None
if CONFIG.searchNextFile and not goBack: if CONFIG.searchNextFile and not goBack:
self.mainGui.openNextDocument( self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
self._docHandle, wrapAround=CONFIG.searchLoop QApplication.processEvents()
)
self.beginSearch() self.beginSearch()
self.setFocus() self.setFocus()
return return
@@ -1340,9 +1334,8 @@ class GuiDocEditor(QPlainTextEdit):
if resIdx > maxIdx and self._docHandle: if resIdx > maxIdx and self._docHandle:
if CONFIG.searchNextFile and not goBack: if CONFIG.searchNextFile and not goBack:
self.mainGui.openNextDocument( self.requestNextDocument.emit(self._docHandle, CONFIG.searchLoop)
self._docHandle, wrapAround=CONFIG.searchLoop QApplication.processEvents()
)
self.beginSearch() self.beginSearch()
self.setFocus() self.setFocus()
return return
+4 -12
View File
@@ -29,9 +29,8 @@ import logging
from enum import Enum from enum import Enum
from time import time 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.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView,
@@ -52,9 +51,6 @@ from novelwriter.types import (
QtUserRole QtUserRole
) )
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -74,10 +70,8 @@ class GuiNovelView(QWidget):
selectedItemChanged = pyqtSignal(str) selectedItemChanged = pyqtSignal(str)
openDocumentRequest = pyqtSignal(str, Enum, str, bool) openDocumentRequest = pyqtSignal(str, Enum, str, bool)
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
self.mainGui = mainGui
# Build GUI # Build GUI
self.novelTree = GuiNovelTree(self) self.novelTree = GuiNovelTree(self)
@@ -202,7 +196,6 @@ class GuiNovelToolBar(QWidget):
logger.debug("Create: GuiNovelToolBar") logger.debug("Create: GuiNovelToolBar")
self.novelView = novelView self.novelView = novelView
self.mainGui = novelView.mainGui
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(2) mPx = CONFIG.pxInt(2)
@@ -378,7 +371,6 @@ class GuiNovelTree(QTreeWidget):
logger.debug("Create: GuiNovelTree") logger.debug("Create: GuiNovelTree")
self.novelView = novelView self.novelView = novelView
self.mainGui = novelView.mainGui
# Internal Variables # Internal Variables
self._treeMap = {} self._treeMap = {}
@@ -493,7 +485,7 @@ class GuiNovelTree(QTreeWidget):
if rootHandle is None: if rootHandle is None:
rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL) 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) indexChanged = SHARED.project.index.rootChangedSince(rootHandle, self._lastBuild)
if not (treeChanged or indexChanged or overRide): if not (treeChanged or indexChanged or overRide):
logger.debug("No changes have been made to the novel index") logger.debug("No changes have been made to the novel index")
+7 -15
View File
@@ -30,7 +30,6 @@ import logging
from enum import Enum from enum import Enum
from time import time from time import time
from typing import TYPE_CHECKING
from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
@@ -57,9 +56,6 @@ from novelwriter.types import (
QtUserRole QtUserRole
) )
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -81,10 +77,8 @@ class GuiProjectView(QWidget):
# Requests for the main GUI # Requests for the main GUI
projectSettingsRequest = pyqtSignal(int) projectSettingsRequest = pyqtSignal(int)
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
self.mainGui = mainGui
# Build GUI # Build GUI
self.projTree = GuiProjectTree(self) self.projTree = GuiProjectTree(self)
@@ -263,7 +257,6 @@ class GuiProjectToolBar(QWidget):
self.projView = projView self.projView = projView
self.projTree = projView.projTree self.projTree = projView.projTree
self.mainGui = projView.mainGui
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
mPx = CONFIG.pxInt(2) mPx = CONFIG.pxInt(2)
@@ -499,7 +492,6 @@ class GuiProjectTree(QTreeWidget):
logger.debug("Create: GuiProjectTree") logger.debug("Create: GuiProjectTree")
self.projView = projView self.projView = projView
self.mainGui = projView.mainGui
# Internal Variables # Internal Variables
self._treeMap: dict[str, QTreeWidgetItem] = {} self._treeMap: dict[str, QTreeWidgetItem] = {}
@@ -1010,8 +1002,7 @@ class GuiProjectTree(QTreeWidget):
trItemP.takeChild(tIndex) trItemP.takeChild(tIndex)
for dHandle in reversed(self.getTreeFromHandle(tHandle)): for dHandle in reversed(self.getTreeFromHandle(tHandle)):
if self.mainGui.docEditor.docHandle == dHandle: SHARED.closeDocument(dHandle)
self.mainGui.closeDocument()
SHARED.project.removeItem(dHandle) SHARED.project.removeItem(dHandle)
self._treeMap.pop(dHandle, None) self._treeMap.pop(dHandle, None)
@@ -1410,7 +1401,7 @@ class GuiProjectTree(QTreeWidget):
if not newFile: if not newFile:
itemList.remove(tHandle) itemList.remove(tHandle)
dlgMerge = GuiDocMerge(self.mainGui, tHandle, itemList) dlgMerge = GuiDocMerge(SHARED.mainGui, tHandle, itemList)
dlgMerge.exec() dlgMerge.exec()
if dlgMerge.result() == QDialog.DialogCode.Accepted: if dlgMerge.result() == QDialog.DialogCode.Accepted:
@@ -1451,7 +1442,8 @@ class GuiProjectTree(QTreeWidget):
if newFile: if newFile:
self.revealNewTreeItem(mHandle, nHandle=tHandle, wordCount=True) 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): if mrgData.get("moveToTrash", False):
for sHandle in reversed(mrgData.get("finalItems", [])): for sHandle in reversed(mrgData.get("finalItems", [])):
@@ -1480,7 +1472,7 @@ class GuiProjectTree(QTreeWidget):
logger.error("Only valid document items can be split") logger.error("Only valid document items can be split")
return False return False
dlgSplit = GuiDocSplit(self.mainGui, tHandle) dlgSplit = GuiDocSplit(SHARED.mainGui, tHandle)
dlgSplit.exec() dlgSplit.exec()
if dlgSplit.result() == QDialog.DialogCode.Accepted: if dlgSplit.result() == QDialog.DialogCode.Accepted:
+2 -2
View File
@@ -27,8 +27,8 @@ import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from PyQt5.QtGui import QPalette
from PyQt5.QtCore import QEvent, QPoint, QSize, pyqtSignal from PyQt5.QtCore import QEvent, QPoint, QSize, pyqtSignal
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QMenu, QVBoxLayout, QWidget from PyQt5.QtWidgets import QMenu, QVBoxLayout, QWidget
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
@@ -58,7 +58,7 @@ class GuiSideBar(QWidget):
iSz = QSize(iPx, iPx) iSz = QSize(iPx, iPx)
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
self.installEventFilter(StatusTipFilter(mainGui)) self.installEventFilter(StatusTipFilter(self.mainGui))
# Buttons # Buttons
self.tbProject = NIconToolButton(self, iSz) self.tbProject = NIconToolButton(self, iSz)
+6 -8
View File
@@ -27,26 +27,23 @@ import logging
from datetime import datetime from datetime import datetime
from time import time from time import time
from typing import TYPE_CHECKING, Literal from typing import Literal
from PyQt5.QtCore import pyqtSlot, QLocale from PyQt5.QtCore import QLocale, pyqtSlot
from PyQt5.QtWidgets import QApplication, QStatusBar, QLabel from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import formatTime from novelwriter.common import formatTime
from novelwriter.constants import nwConst from novelwriter.constants import nwConst
from novelwriter.extensions.statusled import StatusLED from novelwriter.extensions.statusled import StatusLED
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class GuiMainStatus(QStatusBar): class GuiMainStatus(QStatusBar):
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: QWidget) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
logger.debug("Create: GuiMainStatus") logger.debug("Create: GuiMainStatus")
@@ -238,6 +235,7 @@ class GuiMainStatus(QStatusBar):
before starting novelWriter. before starting novelWriter.
""" """
import tracemalloc import tracemalloc
from collections import Counter from collections import Counter
widgets = QApplication.allWidgets() widgets = QApplication.allWidgets()
+22 -27
View File
@@ -263,6 +263,7 @@ class GuiMain(QMainWindow):
self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem) self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem)
self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote) self.docEditor.requestNewNoteCreation.connect(self.projView.createNewNote)
self.docEditor.docTextChanged.connect(self.projSearch.textChanged) self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
self.docEditor.requestNextDocument.connect(self.openNextDocument)
self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle) self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle)
self.docViewer.loadDocumentTagRequest.connect(self._followTag) self.docViewer.loadDocumentTagRequest.connect(self._followTag)
@@ -549,36 +550,30 @@ class GuiMain(QMainWindow):
return True 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 """Open the next document in the project tree, following the
document with the given handle. Stop when reaching the end. document with the given handle. Stop when reaching the end.
""" """
if not SHARED.hasProject: if SHARED.hasProject:
logger.error("No project open") nHandle = None # The next handle after tHandle
return False fHandle = None # The first file handle we encounter
foundIt = False # We've found tHandle, pick the next we see
nHandle = None # The next handle after tHandle for tItem in SHARED.project.tree:
fHandle = None # The first file handle we encounter if not tItem.isFileType():
foundIt = False # We've found tHandle, pick the next we see continue
for tItem in SHARED.project.tree: if fHandle is None:
if not tItem.isFileType(): fHandle = tItem.itemHandle
continue if tItem.itemHandle == tHandle:
if fHandle is None: foundIt = True
fHandle = tItem.itemHandle elif foundIt:
if tItem.itemHandle == tHandle: nHandle = tItem.itemHandle
foundIt = True break
elif foundIt: if nHandle is not None:
nHandle = tItem.itemHandle self.openDocument(nHandle, tLine=1, doScroll=True)
break elif wrapAround:
self.openDocument(fHandle, tLine=1, doScroll=True)
if nHandle is not None: return
self.openDocument(nHandle, tLine=1, doScroll=True)
return True
elif wrapAround:
self.openDocument(fHandle, tLine=1, doScroll=True)
return False
return False
@pyqtSlot() @pyqtSlot()
def saveDocument(self) -> None: def saveDocument(self) -> None:
+6
View File
@@ -171,6 +171,12 @@ class SharedData(QObject):
logger.debug("Thread Pool Max Count: %d", QThreadPool.globalInstance().maxThreadCount()) logger.debug("Thread Pool Max Count: %d", QThreadPool.globalInstance().maxThreadCount())
return 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: def saveDocument(self) -> None:
"""Forward save document call to main GUI.""" """Forward save document call to main GUI."""
self.mainGui.saveDocument() self.mainGui.saveDocument()
+2 -2
View File
@@ -69,8 +69,8 @@ class GuiWritingStats(NToolDialog):
FMT_JSON = 0 FMT_JSON = 0
FMT_CSV = 1 FMT_CSV = 1
def __init__(self, mainGui: GuiMain) -> None: def __init__(self, parent: GuiMain) -> None:
super().__init__(parent=mainGui) super().__init__(parent=parent)
logger.debug("Create: GuiWritingStats") logger.debug("Create: GuiWritingStats")
self.setObjectName("GuiWritingStats") self.setObjectName("GuiWritingStats")
+9 -9
View File
@@ -21,24 +21,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations from __future__ import annotations
import sys import sys
import pytest
from shutil import copyfile 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.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 import CONFIG, SHARED
from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.enum import nwItemType, nwView, nwWidget 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.doceditor import GuiDocEditor
from novelwriter.gui.noveltree import GuiNovelView 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.tools.welcome import GuiWelcome
from novelwriter.dialogs.editlabel import GuiEditLabel
from tests.tools import NWD_IGNORE, XML_IGNORE, C, buildTestProject, cmpFiles
KEY_DELAY = 1 KEY_DELAY = 1
@@ -50,7 +51,6 @@ def testGuiMain_ProjectBlocker(nwGUI):
assert nwGUI.closeProject() is True assert nwGUI.closeProject() is True
assert nwGUI.saveProject() is False assert nwGUI.saveProject() is False
assert nwGUI.openDocument(None) is False assert nwGUI.openDocument(None) is False
assert nwGUI.openNextDocument(None) is False
assert nwGUI.viewDocument(None) is False assert nwGUI.viewDocument(None) is False
assert nwGUI.importDocument() is False assert nwGUI.importDocument() is False
@@ -84,7 +84,7 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath):
nwGUI.closeProject() nwGUI.closeProject()
# Check that latest release info updated # Check that latest release info updated
CONFIG.lastNotes != "0x0" assert CONFIG.lastNotes != "0x0"
# Check that project open dialog launches # Check that project open dialog launches
nwGUI.postLaunchTasks(None) nwGUI.postLaunchTasks(None)