Annotate main gui
This commit is contained in:
+137
-180
@@ -26,13 +26,12 @@ from __future__ import annotations
|
|||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from enum import Enum
|
|
||||||
from time import time
|
from time import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
|
from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
|
||||||
from PyQt5.QtGui import QCursor, QIcon, QKeySequence
|
from PyQt5.QtGui import QCloseEvent, QCursor, QIcon, QKeySequence
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
qApp, QDialog, QFileDialog, QMainWindow, QMessageBox, QShortcut, QSplitter,
|
qApp, QDialog, QFileDialog, QMainWindow, QMessageBox, QShortcut, QSplitter,
|
||||||
QStackedWidget, QVBoxLayout, QWidget
|
QStackedWidget, QVBoxLayout, QWidget
|
||||||
@@ -64,7 +63,7 @@ from novelwriter.core.project import NWProject
|
|||||||
from novelwriter.core.coretools import ProjectBuilder
|
from novelwriter.core.coretools import ProjectBuilder
|
||||||
|
|
||||||
from novelwriter.enum import (
|
from novelwriter.enum import (
|
||||||
nwDocMode, nwItemType, nwItemClass, nwAlert, nwWidget, nwView
|
nwDocAction, nwDocMode, nwItemType, nwItemClass, nwAlert, nwWidget, nwView
|
||||||
)
|
)
|
||||||
from novelwriter.common import getGuiItem, hexToInt
|
from novelwriter.common import getGuiItem, hexToInt
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
@@ -92,7 +91,7 @@ class GuiMain(QMainWindow):
|
|||||||
shouldn't need).
|
shouldn't need).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
logger.debug("Create: GUI")
|
logger.debug("Create: GUI")
|
||||||
@@ -328,9 +327,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def clearGUI(self):
|
def clearGUI(self) -> None:
|
||||||
"""Wrapper function to clear all sub-elements of the main GUI.
|
"""Clear all sub-elements of the main GUI."""
|
||||||
"""
|
|
||||||
# Project Area
|
# Project Area
|
||||||
self.projView.clearProject()
|
self.projView.clearProject()
|
||||||
self.novelView.clearProject()
|
self.novelView.clearProject()
|
||||||
@@ -346,16 +344,15 @@ class GuiMain(QMainWindow):
|
|||||||
self.mainStatus.clearStatus()
|
self.mainStatus.clearStatus()
|
||||||
self._updateWindowTitle()
|
self._updateWindowTitle()
|
||||||
|
|
||||||
return True
|
return
|
||||||
|
|
||||||
def initMain(self):
|
def initMain(self) -> None:
|
||||||
"""Initialise elements that depend on user settings.
|
"""Initialise elements that depend on user settings."""
|
||||||
"""
|
|
||||||
self.asProjTimer.setInterval(int(CONFIG.autoSaveProj*1000))
|
self.asProjTimer.setInterval(int(CONFIG.autoSaveProj*1000))
|
||||||
self.asDocTimer.setInterval(int(CONFIG.autoSaveDoc*1000))
|
self.asDocTimer.setInterval(int(CONFIG.autoSaveDoc*1000))
|
||||||
return True
|
return
|
||||||
|
|
||||||
def postLaunchTasks(self, cmdOpen):
|
def postLaunchTasks(self, cmdOpen: str | None) -> None:
|
||||||
"""This function is called after the main window is created to
|
"""This function is called after the main window is created to
|
||||||
determine what to open or show after initialisation.
|
determine what to open or show after initialisation.
|
||||||
"""
|
"""
|
||||||
@@ -377,9 +374,8 @@ class GuiMain(QMainWindow):
|
|||||||
# Project Actions
|
# Project Actions
|
||||||
##
|
##
|
||||||
|
|
||||||
def newProject(self, projData=None):
|
def newProject(self, projData: dict | None = None) -> bool:
|
||||||
"""Create a new project via the new project wizard.
|
"""Create a new project via the new project wizard."""
|
||||||
"""
|
|
||||||
if self.hasProject:
|
if self.hasProject:
|
||||||
if not self.closeProject():
|
if not self.closeProject():
|
||||||
self.makeAlert(self.tr(
|
self.makeAlert(self.tr(
|
||||||
@@ -414,7 +410,7 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def closeProject(self, isYes=False):
|
def closeProject(self, isYes: bool = False) -> bool:
|
||||||
"""Close the project if one is open. isYes is passed on from the
|
"""Close the project if one is open. isYes is passed on from the
|
||||||
close application event so the user doesn't get prompted twice
|
close application event so the user doesn't get prompted twice
|
||||||
to confirm.
|
to confirm.
|
||||||
@@ -468,9 +464,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return saveOK
|
return saveOK
|
||||||
|
|
||||||
def openProject(self, projFile):
|
def openProject(self, projFile: str | Path | None) -> bool:
|
||||||
"""Open a project from a projFile path.
|
"""Open a project from a projFile path."""
|
||||||
"""
|
|
||||||
if projFile is None:
|
if projFile is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -579,25 +574,21 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def saveProject(self, autoSave=False):
|
def saveProject(self, autoSave: bool = False) -> bool:
|
||||||
"""Save the current project.
|
"""Save the current project."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.projView.saveProjectTasks()
|
self.projView.saveProjectTasks()
|
||||||
self.theProject.saveProject(autoSave=autoSave)
|
self.theProject.saveProject(autoSave=autoSave)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
##
|
##
|
||||||
# Document Actions
|
# Document Actions
|
||||||
##
|
##
|
||||||
|
|
||||||
def closeDocument(self, beforeOpen=False):
|
def closeDocument(self, beforeOpen: bool = False) -> bool:
|
||||||
"""Close the document and clear the editor and title field.
|
"""Close the document and clear the editor and title field."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -615,14 +606,14 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def openDocument(self, tHandle, tLine=None, changeFocus=True, doScroll=False):
|
def openDocument(self, tHandle: str | None, tLine: int | None = None,
|
||||||
"""Open a specific document, optionally at a given line.
|
changeFocus: bool = True, doScroll: bool = False) -> bool:
|
||||||
"""
|
"""Open a specific document, optionally at a given line."""
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
|
if not tHandle or not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
|
||||||
logger.debug("Requested item '%s' is not a document", tHandle)
|
logger.debug("Requested item '%s' is not a document", tHandle)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -646,7 +637,7 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def openNextDocument(self, tHandle, wrapAround=False):
|
def openNextDocument(self, tHandle: str, wrapAround: bool = False) -> bool:
|
||||||
"""Opens the next document in the project tree, following the
|
"""Opens the next document in the project tree, following the
|
||||||
document with the given handle. Stops when reaching the end.
|
document with the given handle. Stops when reaching the end.
|
||||||
"""
|
"""
|
||||||
@@ -677,20 +668,16 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def saveDocument(self):
|
def saveDocument(self) -> bool:
|
||||||
"""Save the current documents.
|
"""Save the current documents."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.docEditor.saveText()
|
self.docEditor.saveText()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def viewDocument(self, tHandle=None, sTitle=None):
|
def viewDocument(self, tHandle: str | None = None, sTitle: str | None = None) -> bool:
|
||||||
"""Load a document for viewing in the view panel.
|
"""Load a document for viewing in the view panel."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -732,7 +719,7 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def importDocument(self):
|
def importDocument(self) -> bool:
|
||||||
"""Import the text contained in an out-of-project text file, and
|
"""Import the text contained in an out-of-project text file, and
|
||||||
insert the text into the currently open document.
|
insert the text into the currently open document.
|
||||||
"""
|
"""
|
||||||
@@ -788,16 +775,16 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def passDocumentAction(self, theAction):
|
def passDocumentAction(self, action: nwDocAction) -> None:
|
||||||
"""Pass on document action to the document viewer if it has
|
"""Pass on document action to the document viewer if it has
|
||||||
focus, or pass it to the document editor if it or any of
|
focus, or pass it to the document editor if it or any of
|
||||||
its child widgets have focus. If neither has focus, ignore the
|
its child widgets have focus. If neither has focus, ignore the
|
||||||
action.
|
action.
|
||||||
"""
|
"""
|
||||||
if self.docViewer.hasFocus():
|
if self.docViewer.hasFocus():
|
||||||
self.docViewer.docAction(theAction)
|
self.docViewer.docAction(action)
|
||||||
elif self.docEditor.hasFocus():
|
elif self.docEditor.hasFocus():
|
||||||
self.docEditor.docAction(theAction)
|
self.docEditor.docAction(action)
|
||||||
else:
|
else:
|
||||||
logger.debug("Action cancelled as neither editor nor viewer has focus")
|
logger.debug("Action cancelled as neither editor nor viewer has focus")
|
||||||
return
|
return
|
||||||
@@ -806,7 +793,7 @@ class GuiMain(QMainWindow):
|
|||||||
# Tree Item Actions
|
# Tree Item Actions
|
||||||
##
|
##
|
||||||
|
|
||||||
def openSelectedItem(self):
|
def openSelectedItem(self) -> bool:
|
||||||
"""Open the selected item from the tree that is currently
|
"""Open the selected item from the tree that is currently
|
||||||
active. It is not checked that the item is actually a document.
|
active. It is not checked that the item is actually a document.
|
||||||
That should be handled by the openDocument function.
|
That should be handled by the openDocument function.
|
||||||
@@ -838,9 +825,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def editItemLabel(self, tHandle=None):
|
def editItemLabel(self, tHandle: str | None = None) -> bool:
|
||||||
"""Open the edit item dialog.
|
"""Open the edit item dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -851,15 +837,13 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def rebuildTrees(self):
|
def rebuildTrees(self) -> None:
|
||||||
"""Rebuild the project tree.
|
"""Rebuild the project tree."""
|
||||||
"""
|
|
||||||
self.projView.populateTree()
|
self.projView.populateTree()
|
||||||
return
|
return
|
||||||
|
|
||||||
def rebuildIndex(self, beQuiet=False):
|
def rebuildIndex(self, beQuiet: bool = False) -> bool:
|
||||||
"""Rebuild the entire index.
|
"""Rebuild the entire index."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -892,7 +876,7 @@ class GuiMain(QMainWindow):
|
|||||||
# Main Dialogs
|
# Main Dialogs
|
||||||
##
|
##
|
||||||
|
|
||||||
def showProjectLoadDialog(self):
|
def showProjectLoadDialog(self) -> None:
|
||||||
"""Open the projects dialog for selecting either existing
|
"""Open the projects dialog for selecting either existing
|
||||||
projects from a cache of recently opened projects, or provide a
|
projects from a cache of recently opened projects, or provide a
|
||||||
browse button for projects not yet cached. Selecting to create a
|
browse button for projects not yet cached. Selecting to create a
|
||||||
@@ -907,11 +891,10 @@ class GuiMain(QMainWindow):
|
|||||||
elif dlgProj.openState == GuiProjectLoad.NEW_STATE:
|
elif dlgProj.openState == GuiProjectLoad.NEW_STATE:
|
||||||
self.newProject()
|
self.newProject()
|
||||||
|
|
||||||
return True
|
return
|
||||||
|
|
||||||
def showNewProjectDialog(self):
|
def showNewProjectDialog(self) -> dict | None:
|
||||||
"""Open the wizard and assemble a project options dict.
|
"""Open the wizard and assemble a project options dict."""
|
||||||
"""
|
|
||||||
newProj = GuiProjectWizard(self)
|
newProj = GuiProjectWizard(self)
|
||||||
newProj.exec_()
|
newProj.exec_()
|
||||||
|
|
||||||
@@ -920,9 +903,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def showPreferencesDialog(self):
|
def showPreferencesDialog(self) -> None:
|
||||||
"""Open the preferences dialog.
|
"""Open the preferences dialog."""
|
||||||
"""
|
|
||||||
dlgConf = GuiPreferences(self)
|
dlgConf = GuiPreferences(self)
|
||||||
dlgConf.exec_()
|
dlgConf.exec_()
|
||||||
|
|
||||||
@@ -967,9 +949,8 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def showProjectSettingsDialog(self, focusTab=GuiProjectSettings.TAB_MAIN):
|
def showProjectSettingsDialog(self, focusTab: int = GuiProjectSettings.TAB_MAIN) -> bool:
|
||||||
"""Open the project settings dialog.
|
"""Open the project settings dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -986,9 +967,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showProjectDetailsDialog(self):
|
def showProjectDetailsDialog(self) -> bool:
|
||||||
"""Open the project details dialog.
|
"""Open the project details dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -1006,9 +986,8 @@ class GuiMain(QMainWindow):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def showBuildManuscriptDialog(self):
|
def showBuildManuscriptDialog(self) -> bool:
|
||||||
"""Open the build manuscript dialog.
|
"""Open the build manuscript dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -1027,9 +1006,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showLoremIpsumDialog(self):
|
def showLoremIpsumDialog(self) -> bool:
|
||||||
"""Open the insert lorem ipsum text dialog.
|
"""Open the insert lorem ipsum text dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -1046,9 +1024,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showProjectWordListDialog(self):
|
def showProjectWordListDialog(self) -> bool:
|
||||||
"""Open the project word list dialog.
|
"""Open the project word list dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -1062,9 +1039,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showWritingStatsDialog(self):
|
def showWritingStatsDialog(self) -> bool:
|
||||||
"""Open the session stats dialog.
|
"""Open the session stats dialog."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
logger.error("No project open")
|
logger.error("No project open")
|
||||||
return False
|
return False
|
||||||
@@ -1082,9 +1058,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showAboutNWDialog(self, showNotes=False):
|
def showAboutNWDialog(self, showNotes: bool = False) -> bool:
|
||||||
"""Show the about dialog for novelWriter.
|
"""Show the about dialog for novelWriter."""
|
||||||
"""
|
|
||||||
dlgAbout = getGuiItem("GuiAbout")
|
dlgAbout = getGuiItem("GuiAbout")
|
||||||
if dlgAbout is None:
|
if dlgAbout is None:
|
||||||
dlgAbout = GuiAbout(self)
|
dlgAbout = GuiAbout(self)
|
||||||
@@ -1101,16 +1076,14 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def showAboutQtDialog(self):
|
def showAboutQtDialog(self) -> None:
|
||||||
"""Show the about dialog for Qt.
|
"""Show the about dialog for Qt."""
|
||||||
"""
|
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.aboutQt(self, "About Qt")
|
msgBox.aboutQt(self, "About Qt")
|
||||||
return True
|
return
|
||||||
|
|
||||||
def showUpdatesDialog(self):
|
def showUpdatesDialog(self) -> None:
|
||||||
"""Show the check for updates dialog.
|
"""Show the check for updates dialog."""
|
||||||
"""
|
|
||||||
dlgUpdate = getGuiItem("GuiUpdates")
|
dlgUpdate = getGuiItem("GuiUpdates")
|
||||||
if dlgUpdate is None:
|
if dlgUpdate is None:
|
||||||
dlgUpdate = GuiUpdates(self)
|
dlgUpdate = GuiUpdates(self)
|
||||||
@@ -1124,7 +1097,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def makeAlert(self, message, level=nwAlert.INFO, exception=None):
|
def makeAlert(self, message: list[str] | str, level: nwAlert = nwAlert.INFO,
|
||||||
|
exception: Exception | None = None) -> None:
|
||||||
"""Alert both the user and the logger at the same time. The
|
"""Alert both the user and the logger at the same time. The
|
||||||
message can be either a string or a list of strings.
|
message can be either a string or a list of strings.
|
||||||
"""
|
"""
|
||||||
@@ -1165,14 +1139,13 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def askQuestion(self, title, question):
|
def askQuestion(self, title: str, question: str) -> bool:
|
||||||
"""Ask the user a Yes/No question.
|
"""Ask the user a Yes/No question, and return the answer."""
|
||||||
"""
|
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgRes = msgBox.question(self, title, question, QMessageBox.Yes | QMessageBox.No)
|
msgRes = msgBox.question(self, title, question, QMessageBox.Yes | QMessageBox.No)
|
||||||
return msgRes == QMessageBox.Yes
|
return msgRes == QMessageBox.Yes
|
||||||
|
|
||||||
def reportConfErr(self):
|
def reportConfErr(self) -> bool:
|
||||||
"""Checks if the Config module has any errors to report, and let
|
"""Checks if the Config module has any errors to report, and let
|
||||||
the user know if this is the case. The Config module caches
|
the user know if this is the case. The Config module caches
|
||||||
errors since it is initialised before the GUI itself.
|
errors since it is initialised before the GUI itself.
|
||||||
@@ -1222,9 +1195,8 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def switchFocus(self, paneNo):
|
def switchFocus(self, paneNo: nwWidget) -> None:
|
||||||
"""Switch focus between main GUI views.
|
"""Switch focus between main GUI views."""
|
||||||
"""
|
|
||||||
if paneNo == nwWidget.TREE:
|
if paneNo == nwWidget.TREE:
|
||||||
tabIdx = self.projStack.currentIndex()
|
tabIdx = self.projStack.currentIndex()
|
||||||
if tabIdx == self.idxProjView:
|
if tabIdx == self.idxProjView:
|
||||||
@@ -1242,16 +1214,14 @@ class GuiMain(QMainWindow):
|
|||||||
self.outlineView.setTreeFocus()
|
self.outlineView.setTreeFocus()
|
||||||
return
|
return
|
||||||
|
|
||||||
def closeDocEditor(self):
|
def closeDocEditor(self) -> None:
|
||||||
"""Close the document edit panel. This does not hide the editor.
|
"""Close the document editor. This does not hide the editor."""
|
||||||
"""
|
|
||||||
self.closeDocument()
|
self.closeDocument()
|
||||||
self.theProject.data.setLastHandle(None, "editor")
|
self.theProject.data.setLastHandle(None, "editor")
|
||||||
return
|
return
|
||||||
|
|
||||||
def closeDocViewer(self, byUser=True):
|
def closeDocViewer(self, byUser: bool = True) -> bool:
|
||||||
"""Close the document view panel.
|
"""Close the document view panel."""
|
||||||
"""
|
|
||||||
self.docViewer.clearViewer()
|
self.docViewer.clearViewer()
|
||||||
if byUser:
|
if byUser:
|
||||||
# Only reset the last handle if the user called this
|
# Only reset the last handle if the user called this
|
||||||
@@ -1264,8 +1234,9 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return not self.splitView.isVisible()
|
return not self.splitView.isVisible()
|
||||||
|
|
||||||
def toggleFocusMode(self):
|
def toggleFocusMode(self) -> bool:
|
||||||
"""Main GUI Focus Mode hides tree, view, statusbar and menu.
|
"""Handle toggle focus mode. The Main GUI Focus Mode hides tree,
|
||||||
|
view, statusbar and menu.
|
||||||
"""
|
"""
|
||||||
if self.docEditor.docHandle() is None:
|
if self.docEditor.docHandle() is None:
|
||||||
logger.error("No document open, so not activating Focus Mode")
|
logger.error("No document open, so not activating Focus Mode")
|
||||||
@@ -1304,7 +1275,7 @@ class GuiMain(QMainWindow):
|
|||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _connectMenuActions(self):
|
def _connectMenuActions(self) -> None:
|
||||||
"""Connect to the main window all menu actions that need to be
|
"""Connect to the main window all menu actions that need to be
|
||||||
available also when the main menu is hidden.
|
available also when the main menu is hidden.
|
||||||
"""
|
"""
|
||||||
@@ -1394,40 +1365,17 @@ class GuiMain(QMainWindow):
|
|||||||
if isinstance(CONFIG.pdfDocs, Path):
|
if isinstance(CONFIG.pdfDocs, Path):
|
||||||
self.addAction(self.mainMenu.aPdfDocs)
|
self.addAction(self.mainMenu.aPdfDocs)
|
||||||
|
|
||||||
return True
|
return
|
||||||
|
|
||||||
def _updateWindowTitle(self, projName=None):
|
def _updateWindowTitle(self, projName: str | None = None) -> None:
|
||||||
"""Set the window title and add the project's name.
|
"""Set the window title and add the project's name."""
|
||||||
"""
|
|
||||||
winTitle = CONFIG.appName
|
winTitle = CONFIG.appName
|
||||||
if projName is not None:
|
if projName is not None:
|
||||||
winTitle += " - %s" % projName
|
winTitle += " - %s" % projName
|
||||||
self.setWindowTitle(winTitle)
|
self.setWindowTitle(winTitle)
|
||||||
return True
|
|
||||||
|
|
||||||
def _autoSaveProject(self):
|
|
||||||
"""Triggered by the autosave project timer to save the project.
|
|
||||||
"""
|
|
||||||
doSave = self.hasProject
|
|
||||||
doSave &= self.theProject.projChanged
|
|
||||||
doSave &= self.theProject.storage.isOpen()
|
|
||||||
|
|
||||||
if doSave:
|
|
||||||
logger.debug("Autosaving project")
|
|
||||||
self.saveProject(autoSave=True)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _autoSaveDocument(self):
|
def _assembleProjectWizardData(self, newProj: GuiProjectWizard) -> dict:
|
||||||
"""Triggered by the autosave document timer to save the
|
|
||||||
document.
|
|
||||||
"""
|
|
||||||
if self.hasProject and self.docEditor.docChanged():
|
|
||||||
logger.debug("Autosaving document")
|
|
||||||
self.saveDocument()
|
|
||||||
return
|
|
||||||
|
|
||||||
def _assembleProjectWizardData(self, newProj):
|
|
||||||
"""Extract the user choices from the New Project Wizard and
|
"""Extract the user choices from the New Project Wizard and
|
||||||
store them in a dictionary.
|
store them in a dictionary.
|
||||||
"""
|
"""
|
||||||
@@ -1459,72 +1407,68 @@ class GuiMain(QMainWindow):
|
|||||||
|
|
||||||
return projData
|
return projData
|
||||||
|
|
||||||
def _getTagSource(self, tTag):
|
def _getTagSource(self, tag: str) -> tuple[str | None, str | None]:
|
||||||
"""A wrapper function for the index lookup of a tag that will
|
"""Handle the index lookup of a tag and display an alert if the
|
||||||
display an alert if the tag cannot be found.
|
tag cannot be found.
|
||||||
"""
|
"""
|
||||||
tHandle, sTitle = self.theProject.index.getTagSource(tTag)
|
tHandle, sTitle = self.theProject.index.getTagSource(tag)
|
||||||
if tHandle is None:
|
if tHandle is None:
|
||||||
self.makeAlert(self.tr(
|
self.makeAlert(self.tr(
|
||||||
"Could not find the reference for tag '{0}'. It either doesn't "
|
"Could not find the reference for tag '{0}'. It either doesn't "
|
||||||
"exist, or the index is out of date. The index can be updated "
|
"exist, or the index is out of date. The index can be updated "
|
||||||
"from the Tools menu, or by pressing {1}."
|
"from the Tools menu, or by pressing {1}."
|
||||||
).format(
|
).format(
|
||||||
tTag, "F9"
|
tag, "F9"
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
return tHandle, sTitle
|
return tHandle, sTitle
|
||||||
|
|
||||||
##
|
##
|
||||||
# Events
|
# Events
|
||||||
##
|
##
|
||||||
|
|
||||||
def closeEvent(self, theEvent):
|
def closeEvent(self, event: QCloseEvent):
|
||||||
"""Capture the closing event of the GUI and call the close
|
"""Capture the closing event of the GUI and call the close
|
||||||
function to handle all the close process steps.
|
function to handle all the close process steps.
|
||||||
"""
|
"""
|
||||||
if self.closeMain():
|
if self.closeMain():
|
||||||
theEvent.accept()
|
event.accept()
|
||||||
else:
|
else:
|
||||||
theEvent.ignore()
|
event.ignore()
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Private Slots
|
# Private Slots
|
||||||
##
|
##
|
||||||
|
|
||||||
@pyqtSlot(str, Enum)
|
@pyqtSlot(str, nwDocMode)
|
||||||
def _followTag(self, tTag, tMode):
|
def _followTag(self, tag: str, mode: nwDocMode) -> None:
|
||||||
"""Follow a tag after user interaction with a link.
|
"""Follow a tag after user interaction with a link."""
|
||||||
"""
|
tHandle, sTitle = self._getTagSource(tag)
|
||||||
tHandle, sTitle = self._getTagSource(tTag)
|
|
||||||
if tHandle is not None:
|
if tHandle is not None:
|
||||||
if tMode == nwDocMode.EDIT:
|
if mode == nwDocMode.EDIT:
|
||||||
self.openDocument(tHandle)
|
self.openDocument(tHandle)
|
||||||
elif tMode == nwDocMode.VIEW:
|
elif mode == nwDocMode.VIEW:
|
||||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(str, Enum, str, bool)
|
@pyqtSlot(str, nwDocMode, str, bool)
|
||||||
def _openDocument(self, tHandle, tMode, sTitle, setFocus):
|
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
||||||
"""Handle an open document request from one of the tree views.
|
"""Handle an open document request."""
|
||||||
"""
|
|
||||||
if tHandle is not None:
|
if tHandle is not None:
|
||||||
if tMode == nwDocMode.EDIT:
|
if mode == nwDocMode.EDIT:
|
||||||
tLine = None
|
tLine = None
|
||||||
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
|
hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
|
||||||
if hItem is not None:
|
if hItem is not None:
|
||||||
tLine = hItem.line
|
tLine = hItem.line
|
||||||
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
||||||
elif tMode == nwDocMode.VIEW:
|
elif mode == nwDocMode.VIEW:
|
||||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(nwView)
|
@pyqtSlot(nwView)
|
||||||
def _changeView(self, view):
|
def _changeView(self, view: nwView) -> None:
|
||||||
"""Handle the requested change of view from the GuiViewBar.
|
"""Handle the requested change of view from the GuiViewBar."""
|
||||||
"""
|
|
||||||
if view == nwView.EDITOR:
|
if view == nwView.EDITOR:
|
||||||
# Only change the main stack, but not the project stack
|
# Only change the main stack, but not the project stack
|
||||||
self.mainStack.setCurrentWidget(self.splitMain)
|
self.mainStack.setCurrentWidget(self.splitMain)
|
||||||
@@ -1543,9 +1487,8 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _timeTick(self):
|
def _timeTick(self) -> None:
|
||||||
"""Triggered on every tick of the main timer.
|
"""Process time tick of the main timer."""
|
||||||
"""
|
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1565,9 +1508,27 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _updateStatusWordCount(self):
|
def _autoSaveProject(self) -> None:
|
||||||
"""Update the word count on the status bar.
|
"""Autosave of the project. This is a timer-activated slot."""
|
||||||
"""
|
doSave = self.hasProject
|
||||||
|
doSave &= self.theProject.projChanged
|
||||||
|
doSave &= self.theProject.storage.isOpen()
|
||||||
|
if doSave:
|
||||||
|
logger.debug("Autosaving project")
|
||||||
|
self.saveProject(autoSave=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _autoSaveDocument(self) -> None:
|
||||||
|
"""Autosave of the document. This is a timer-activated slot."""
|
||||||
|
if self.hasProject and self.docEditor.docChanged():
|
||||||
|
logger.debug("Autosaving document")
|
||||||
|
self.saveDocument()
|
||||||
|
return
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _updateStatusWordCount(self) -> None:
|
||||||
|
"""Update the word count on the status bar."""
|
||||||
if not self.hasProject:
|
if not self.hasProject:
|
||||||
self.mainStatus.setProjectStats(0, 0)
|
self.mainStatus.setProjectStats(0, 0)
|
||||||
|
|
||||||
@@ -1584,7 +1545,7 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _keyPressReturn(self):
|
def _keyPressReturn(self) -> None:
|
||||||
"""Forward the return/enter keypress to the function that opens
|
"""Forward the return/enter keypress to the function that opens
|
||||||
the currently selected item.
|
the currently selected item.
|
||||||
"""
|
"""
|
||||||
@@ -1592,10 +1553,8 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _keyPressEscape(self):
|
def _keyPressEscape(self) -> None:
|
||||||
"""When the escape key is pressed somewhere in the main window,
|
"""Process escape keypress in the main window."""
|
||||||
do the following, in order:
|
|
||||||
"""
|
|
||||||
if self.docEditor.docSearch.isVisible():
|
if self.docEditor.docSearch.isVisible():
|
||||||
self.docEditor.closeSearch()
|
self.docEditor.closeSearch()
|
||||||
elif self.isFocusMode:
|
elif self.isFocusMode:
|
||||||
@@ -1603,22 +1562,20 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def _mainStackChanged(self, stIndex):
|
def _mainStackChanged(self, index: int) -> None:
|
||||||
"""Activated when the main window tab is changed.
|
"""Process main window tab change."""
|
||||||
"""
|
if index == self.idxOutlineView:
|
||||||
if stIndex == self.idxOutlineView:
|
|
||||||
if self.hasProject:
|
if self.hasProject:
|
||||||
self.outlineView.refreshTree()
|
self.outlineView.refreshTree()
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def _projStackChanged(self, stIndex):
|
def _projStackChanged(self, index: int) -> None:
|
||||||
"""Activated when the project view tab is changed.
|
"""Process project view tab change."""
|
||||||
"""
|
|
||||||
sHandle = None
|
sHandle = None
|
||||||
if stIndex == self.idxProjView:
|
if index == self.idxProjView:
|
||||||
sHandle = self.projView.getSelectedHandle()
|
sHandle = self.projView.getSelectedHandle()
|
||||||
elif stIndex == self.idxNovelView:
|
elif index == self.idxNovelView:
|
||||||
sHandle, _ = self.novelView.getSelectedHandle()
|
sHandle, _ = self.novelView.getSelectedHandle()
|
||||||
self.itemDetails.updateViewBox(sHandle)
|
self.itemDetails.updateViewBox(sHandle)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ def testDlgAbout_QtDialog(monkeypatch, nwGUI):
|
|||||||
|
|
||||||
# Open About
|
# Open About
|
||||||
# All it can do is check against a crash
|
# All it can do is check against a crash
|
||||||
assert nwGUI.showAboutQtDialog() is True
|
nwGUI.showAboutQtDialog()
|
||||||
nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger)
|
nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger)
|
||||||
|
|
||||||
# END Test testDlgAbout_QtDialog
|
# END Test testDlgAbout_QtDialog
|
||||||
|
|||||||
Reference in New Issue
Block a user