Clean up document header signals
This commit is contained in:
@@ -77,10 +77,10 @@ Text Search Shortcuts
|
||||
|
||||
":kbd:`F3`", "Find the next occurrence of the search word"
|
||||
":kbd:`Ctrl+F`", "Open the search bar and search for the selected word, if any is selected"
|
||||
":kbd:`Ctrl+G`", "Find next occurrence of search word in current document"
|
||||
":kbd:`Ctrl+G`", "Find the next occurrence of the search word"
|
||||
":kbd:`Ctrl+H`", "Open the search tool and populate with the selected word (Mac :kbd:`Cmd+=`)"
|
||||
":kbd:`Ctrl+Shift+1`", "Replace selected occurrence of the search word, and move to the next"
|
||||
":kbd:`Ctrl+Shift+G`", "Find previous occurrence of the search word"
|
||||
":kbd:`Ctrl+Shift+G`", "Find the previous occurrence of the search word"
|
||||
":kbd:`Shift+F3`", "Find the previous occurrence of the search word"
|
||||
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# Document > Close
|
||||
self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document"))
|
||||
self.aCloseDoc.setShortcut("Ctrl+W")
|
||||
self.aCloseDoc.triggered.connect(lambda: self.mainGui.closeDocEditor())
|
||||
self.aCloseDoc.triggered.connect(self.mainGui.closeDocEditor)
|
||||
|
||||
# Document > Separator
|
||||
self.docuMenu.addSeparator()
|
||||
@@ -330,7 +330,7 @@ class GuiMainMenu(QMenuBar):
|
||||
# View > Focus Mode
|
||||
self.aFocusMode = self.viewMenu.addAction(self.tr("Focus Mode"))
|
||||
self.aFocusMode.setShortcut("F8")
|
||||
self.aFocusMode.triggered.connect(lambda: self.mainGui.toggleFocusMode())
|
||||
self.aFocusMode.triggered.connect(self.mainGui.toggleFocusMode)
|
||||
|
||||
# View > Toggle Full Screen
|
||||
self.aFullScreen = self.viewMenu.addAction(self.tr("Full Screen Mode"))
|
||||
|
||||
@@ -115,7 +115,6 @@ class GuiSideBar(QWidget):
|
||||
self.outerBox.setSpacing(CONFIG.pxInt(4))
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
self.updateTheme()
|
||||
|
||||
logger.debug("Ready: GuiSideBar")
|
||||
|
||||
+169
-161
@@ -267,6 +267,8 @@ class GuiMain(QMainWindow):
|
||||
self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta)
|
||||
self.docEditor.statusMessage.connect(self.mainStatus.setStatusMessage)
|
||||
self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState)
|
||||
self.docEditor.closeDocumentRequest.connect(self.closeDocEditor)
|
||||
self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode)
|
||||
|
||||
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
|
||||
|
||||
@@ -1119,12 +1121,6 @@ class GuiMain(QMainWindow):
|
||||
self.outlineView.setTreeFocus()
|
||||
return
|
||||
|
||||
def closeDocEditor(self) -> None:
|
||||
"""Close the document editor. This does not hide the editor."""
|
||||
self.closeDocument()
|
||||
SHARED.project.data.setLastHandle(None, "editor")
|
||||
return
|
||||
|
||||
def closeDocViewer(self, byUser: bool = True) -> bool:
|
||||
"""Close the document view panel."""
|
||||
self.docViewer.clearViewer()
|
||||
@@ -1139,13 +1135,44 @@ class GuiMain(QMainWindow):
|
||||
|
||||
return not self.splitView.isVisible()
|
||||
|
||||
def toggleFocusMode(self) -> bool:
|
||||
def toggleFullScreenMode(self) -> None:
|
||||
"""Toggle full screen mode"""
|
||||
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
def closeEvent(self, event: QCloseEvent):
|
||||
"""Capture the closing event of the GUI and call the close
|
||||
function to handle all the close process steps.
|
||||
"""
|
||||
if self.closeMain():
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
##
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def closeDocEditor(self) -> None:
|
||||
"""Close the document editor. This does not hide the editor."""
|
||||
self.closeDocument()
|
||||
SHARED.project.data.setLastHandle(None, "editor")
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def toggleFocusMode(self) -> None:
|
||||
"""Handle toggle focus mode. The Main GUI Focus Mode hides tree,
|
||||
view, statusbar and menu.
|
||||
"""
|
||||
if self.docEditor.docHandle is None:
|
||||
logger.error("No document open, so not activating Focus Mode")
|
||||
return False
|
||||
return
|
||||
|
||||
self.isFocusMode = not self.isFocusMode
|
||||
if self.isFocusMode:
|
||||
@@ -1169,11 +1196,141 @@ class GuiMain(QMainWindow):
|
||||
elif self.docViewer.docHandle is not None:
|
||||
self.splitView.setVisible(True)
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
def toggleFullScreenMode(self) -> None:
|
||||
"""Toggle full screen mode"""
|
||||
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str, nwDocMode)
|
||||
def _followTag(self, tag: str, mode: nwDocMode) -> None:
|
||||
"""Follow a tag after user interaction with a link."""
|
||||
tHandle, sTitle = self._getTagSource(tag)
|
||||
if tHandle is not None:
|
||||
if mode == nwDocMode.EDIT:
|
||||
self.openDocument(tHandle)
|
||||
elif mode == nwDocMode.VIEW:
|
||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, nwDocMode, str, bool)
|
||||
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
||||
"""Handle an open document request."""
|
||||
if tHandle is not None:
|
||||
if mode == nwDocMode.EDIT:
|
||||
tLine = None
|
||||
hItem = SHARED.project.index.getItemHeader(tHandle, sTitle)
|
||||
if hItem is not None:
|
||||
tLine = hItem.line
|
||||
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
||||
elif mode == nwDocMode.VIEW:
|
||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(nwView)
|
||||
def _changeView(self, view: nwView) -> None:
|
||||
"""Handle the requested change of view from the GuiViewBar."""
|
||||
if view == nwView.EDITOR:
|
||||
# Only change the main stack, but not the project stack
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
|
||||
elif view == nwView.PROJECT:
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
self.projStack.setCurrentWidget(self.projView)
|
||||
|
||||
elif view == nwView.NOVEL:
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
self.projStack.setCurrentWidget(self.novelView)
|
||||
|
||||
elif view == nwView.OUTLINE:
|
||||
self.mainStack.setCurrentWidget(self.outlineView)
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _timeTick(self) -> None:
|
||||
"""Process time tick of the main timer."""
|
||||
if not SHARED.hasProject:
|
||||
return
|
||||
currTime = time()
|
||||
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
||||
userIdle = qApp.applicationState() != Qt.ApplicationActive
|
||||
self.mainStatus.setUserIdle(editIdle or userIdle)
|
||||
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
||||
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _autoSaveProject(self) -> None:
|
||||
"""Autosave of the project. This is a timer-activated slot."""
|
||||
doSave = SHARED.hasProject
|
||||
doSave &= SHARED.project.projChanged
|
||||
doSave &= SHARED.project.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 SHARED.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 SHARED.hasProject:
|
||||
self.mainStatus.setProjectStats(0, 0)
|
||||
|
||||
SHARED.project.updateWordCounts()
|
||||
if CONFIG.incNotesWCount:
|
||||
iTotal = sum(SHARED.project.data.initCounts)
|
||||
cTotal = sum(SHARED.project.data.currCounts)
|
||||
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
||||
else:
|
||||
iNovel, _ = SHARED.project.data.initCounts
|
||||
cNovel, _ = SHARED.project.data.currCounts
|
||||
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _keyPressReturn(self) -> None:
|
||||
"""Forward the return/enter keypress to the function that opens
|
||||
the currently selected item.
|
||||
"""
|
||||
self.openSelectedItem()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _keyPressEscape(self) -> None:
|
||||
"""Process escape keypress in the main window."""
|
||||
if self.docEditor.docSearch.isVisible():
|
||||
self.docEditor.closeSearch()
|
||||
elif self.isFocusMode:
|
||||
self.toggleFocusMode()
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _mainStackChanged(self, index: int) -> None:
|
||||
"""Process main window tab change."""
|
||||
if index == self.idxOutlineView:
|
||||
if SHARED.hasProject:
|
||||
self.outlineView.refreshTree()
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _projStackChanged(self, index: int) -> None:
|
||||
"""Process project view tab change."""
|
||||
sHandle = None
|
||||
if index == self.idxProjView:
|
||||
sHandle = self.projView.getSelectedHandle()
|
||||
elif index == self.idxNovelView:
|
||||
sHandle, _ = self.novelView.getSelectedHandle()
|
||||
self.itemDetails.updateViewBox(sHandle)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -1328,153 +1485,4 @@ class GuiMain(QMainWindow):
|
||||
return None, None
|
||||
return tHandle, sTitle
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
def closeEvent(self, event: QCloseEvent):
|
||||
"""Capture the closing event of the GUI and call the close
|
||||
function to handle all the close process steps.
|
||||
"""
|
||||
if self.closeMain():
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
##
|
||||
# Private Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str, nwDocMode)
|
||||
def _followTag(self, tag: str, mode: nwDocMode) -> None:
|
||||
"""Follow a tag after user interaction with a link."""
|
||||
tHandle, sTitle = self._getTagSource(tag)
|
||||
if tHandle is not None:
|
||||
if mode == nwDocMode.EDIT:
|
||||
self.openDocument(tHandle)
|
||||
elif mode == nwDocMode.VIEW:
|
||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(str, nwDocMode, str, bool)
|
||||
def _openDocument(self, tHandle: str, mode: nwDocMode, sTitle: str, setFocus: bool) -> None:
|
||||
"""Handle an open document request."""
|
||||
if tHandle is not None:
|
||||
if mode == nwDocMode.EDIT:
|
||||
tLine = None
|
||||
hItem = SHARED.project.index.getItemHeader(tHandle, sTitle)
|
||||
if hItem is not None:
|
||||
tLine = hItem.line
|
||||
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
|
||||
elif mode == nwDocMode.VIEW:
|
||||
self.viewDocument(tHandle=tHandle, sTitle=sTitle)
|
||||
return
|
||||
|
||||
@pyqtSlot(nwView)
|
||||
def _changeView(self, view: nwView) -> None:
|
||||
"""Handle the requested change of view from the GuiViewBar."""
|
||||
if view == nwView.EDITOR:
|
||||
# Only change the main stack, but not the project stack
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
|
||||
elif view == nwView.PROJECT:
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
self.projStack.setCurrentWidget(self.projView)
|
||||
|
||||
elif view == nwView.NOVEL:
|
||||
self.mainStack.setCurrentWidget(self.splitMain)
|
||||
self.projStack.setCurrentWidget(self.novelView)
|
||||
|
||||
elif view == nwView.OUTLINE:
|
||||
self.mainStack.setCurrentWidget(self.outlineView)
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _timeTick(self) -> None:
|
||||
"""Process time tick of the main timer."""
|
||||
if not SHARED.hasProject:
|
||||
return
|
||||
currTime = time()
|
||||
editIdle = currTime - self.docEditor.lastActive > CONFIG.userIdleTime
|
||||
userIdle = qApp.applicationState() != Qt.ApplicationActive
|
||||
self.mainStatus.setUserIdle(editIdle or userIdle)
|
||||
SHARED.updateIdleTime(currTime, editIdle or userIdle)
|
||||
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _autoSaveProject(self) -> None:
|
||||
"""Autosave of the project. This is a timer-activated slot."""
|
||||
doSave = SHARED.hasProject
|
||||
doSave &= SHARED.project.projChanged
|
||||
doSave &= SHARED.project.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 SHARED.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 SHARED.hasProject:
|
||||
self.mainStatus.setProjectStats(0, 0)
|
||||
|
||||
SHARED.project.updateWordCounts()
|
||||
if CONFIG.incNotesWCount:
|
||||
iTotal = sum(SHARED.project.data.initCounts)
|
||||
cTotal = sum(SHARED.project.data.currCounts)
|
||||
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
|
||||
else:
|
||||
iNovel, _ = SHARED.project.data.initCounts
|
||||
cNovel, _ = SHARED.project.data.currCounts
|
||||
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _keyPressReturn(self) -> None:
|
||||
"""Forward the return/enter keypress to the function that opens
|
||||
the currently selected item.
|
||||
"""
|
||||
self.openSelectedItem()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _keyPressEscape(self) -> None:
|
||||
"""Process escape keypress in the main window."""
|
||||
if self.docEditor.docSearch.isVisible():
|
||||
self.docEditor.closeSearch()
|
||||
elif self.isFocusMode:
|
||||
self.toggleFocusMode()
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _mainStackChanged(self, index: int) -> None:
|
||||
"""Process main window tab change."""
|
||||
if index == self.idxOutlineView:
|
||||
if SHARED.hasProject:
|
||||
self.outlineView.refreshTree()
|
||||
return
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _projStackChanged(self, index: int) -> None:
|
||||
"""Process project view tab change."""
|
||||
sHandle = None
|
||||
if index == self.idxProjView:
|
||||
sHandle = self.projView.getSelectedHandle()
|
||||
elif index == self.idxNovelView:
|
||||
sHandle, _ = self.novelView.getSelectedHandle()
|
||||
self.itemDetails.updateViewBox(sHandle)
|
||||
return
|
||||
|
||||
# END Class GuiMain
|
||||
|
||||
@@ -594,14 +594,18 @@ def testGuiMain_Features(qtbot, nwGUI, projPath, mockRnd):
|
||||
# ==========
|
||||
|
||||
# No document open, so not allowing focus mode
|
||||
assert nwGUI.toggleFocusMode() is False
|
||||
nwGUI.toggleFocusMode()
|
||||
assert nwGUI.treePane.isVisible() is True
|
||||
assert nwGUI.mainStatus.isVisible() is True
|
||||
assert nwGUI.mainMenu.isVisible() is True
|
||||
assert nwGUI.sideBar.isVisible() is True
|
||||
|
||||
# Open a file in editor and viewer
|
||||
assert nwGUI.openDocument(C.hSceneDoc)
|
||||
assert nwGUI.viewDocument(C.hSceneDoc)
|
||||
|
||||
# Enable focus mode
|
||||
assert nwGUI.toggleFocusMode() is True
|
||||
nwGUI.toggleFocusMode()
|
||||
assert nwGUI.treePane.isVisible() is False
|
||||
assert nwGUI.mainStatus.isVisible() is False
|
||||
assert nwGUI.mainMenu.isVisible() is False
|
||||
@@ -609,7 +613,7 @@ def testGuiMain_Features(qtbot, nwGUI, projPath, mockRnd):
|
||||
assert nwGUI.splitView.isVisible() is False
|
||||
|
||||
# Disable focus mode
|
||||
assert nwGUI.toggleFocusMode() is True
|
||||
nwGUI.toggleFocusMode()
|
||||
assert nwGUI.treePane.isVisible() is True
|
||||
assert nwGUI.mainStatus.isVisible() is True
|
||||
assert nwGUI.mainMenu.isVisible() is True
|
||||
|
||||
Reference in New Issue
Block a user