diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index e0a8ef62..4a069f42 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -27,6 +27,7 @@ along with this program. If not, see . import logging import novelwriter +from enum import Enum from time import time from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot @@ -37,7 +38,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter.core import NWDoc -from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert +from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert from novelwriter.common import minmax from novelwriter.dialogs.itemeditor import GuiItemEditor @@ -51,11 +52,16 @@ class GuiProjectTree(QTreeWidget): C_EXPORT = 2 C_STATUS = 3 + # Signals triggered when the meta data values of items change treeItemChanged = pyqtSignal(str) novelItemChanged = pyqtSignal(str) rootFolderChanged = pyqtSignal(str) wordCountsChanged = pyqtSignal() + # Signals for user interaction with the project tree + selectedItemChanged = pyqtSignal(str) + openDocumentRequest = pyqtSignal(str, Enum) + def __init__(self, theParent): QTreeWidget.__init__(self, theParent) @@ -127,6 +133,10 @@ class GuiProjectTree(QTreeWidget): # The last column should just auto-scale self.resizeColumnToContents(self.C_STATUS) + # Connect signals + self.itemDoubleClicked.connect(self._treeDoubleClick) + self.itemSelectionChanged.connect(self._treeSelectionChange) + # Set custom settings self.initTree() @@ -223,9 +233,9 @@ class GuiProjectTree(QTreeWidget): if tHandle is None: # pragma: no cover return True - # Add the new item to the tree + # Add the new item to the tree and open the editor dialog self.revealNewTreeItem(tHandle, nHandle) - self.theParent.editItem(tHandle) + self.editTreeItem(tHandle) # Handle new file creation nwItem = self.theProject.tree[tHandle] @@ -249,10 +259,7 @@ class GuiProjectTree(QTreeWidget): pIndex.scanText(tHandle, newText) # Get Word Counts - cC, wC, pC = pIndex.getCounts(tHandle) - nwItem.setCharCount(cC) - nwItem.setWordCount(wC) - nwItem.setParaCount(pC) + _, wC, _ = pIndex.getCounts(tHandle) self.propagateCount(tHandle, wC) self.wordCountsChanged.emit() @@ -280,8 +287,8 @@ class GuiProjectTree(QTreeWidget): return True def moveTreeItem(self, nStep): - """Move an item up or down in the tree, but only if the treeView - has focus. This also applies when the menu is used. + """Move an item up or down in the tree, but only if the project + tree has focus. This also applies when the menu is used. """ if not self.theParent.hasProject: logger.error("No project open") @@ -321,13 +328,9 @@ class GuiProjectTree(QTreeWidget): return True - def editTreeItem(self, tHandle=None): + def editTreeItem(self, tHandle): """Open the edit item dialog. """ - if tHandle is None: - logger.warning("No item selected") - return False - tItem = self.theProject.tree[tHandle] if tItem is None: return False @@ -357,8 +360,8 @@ class GuiProjectTree(QTreeWidget): return True def getTreeFromHandle(self, tHandle): - """Recursively return all the children items starting from a - given item handle. + """Recursively return all the child items starting from a given + item handle. """ theList = [] theItem = self._getTreeItem(tHandle) @@ -366,14 +369,6 @@ class GuiProjectTree(QTreeWidget): theList = self._scanChildren(theList, theItem, 0) return theList - def toggleExpanded(self, tHandle): - """Expand an item based on its handle. - """ - trItem = self._getTreeItem(tHandle) - if trItem is not None: - trItem.setExpanded(not trItem.isExpanded()) - return - def getColumnSizes(self): """Return the column widths for the tree columns. """ @@ -719,9 +714,52 @@ class GuiProjectTree(QTreeWidget): return self._timeChanged > checkTime ## - # Slots + # Public Solts ## + @pyqtSlot(str, int, int, int) + def doUpdateCounts(self, tHandle, cCount, wCount, pCount): + """Slot for updating the word count of a specific item. + """ + self.propagateCount(tHandle, wCount, countChildren=True) + self.wordCountsChanged.emit() + return + + ## + # Private Slots + ## + + @pyqtSlot() + def _treeSelectionChange(self): + """The user changed which item is selected. + """ + tHandle = self.getSelectedHandle() + if tHandle is not None: + self.selectedItemChanged.emit(tHandle) + return + + @pyqtSlot("QTreeWidgetItem*", int) + def _treeDoubleClick(self, tItem, colNo): + """Capture a double-click event and either request the document + for editing if it is a file, or expand/close the node it is not. + """ + tHandle = self.getSelectedHandle() + if tHandle is None: + return + + tItem = self.theProject.tree[tHandle] + if tItem is None: + return + + if tItem.itemType == nwItemType.FILE: + self.openDocumentRequest.emit(tHandle, nwDocMode.EDIT) + else: + trItem = self._getTreeItem(tHandle) + if trItem is not None: + trItem.setExpanded(not trItem.isExpanded()) + + return + @pyqtSlot("QPoint") def _rightClickMenu(self, clickPos): """The user right clicked an element in the project tree, so we @@ -739,14 +777,6 @@ class GuiProjectTree(QTreeWidget): return - @pyqtSlot(str, int, int, int) - def doUpdateCounts(self, tHandle, cCount, wCount, pCount): - """Slot for updating the word count of a specific item. - """ - self.propagateCount(tHandle, wCount, countChildren=True) - self.wordCountsChanged.emit() - return - ## # Events ## @@ -774,7 +804,7 @@ class GuiProjectTree(QTreeWidget): return if tItem.itemType == nwItemType.FILE: - self.theParent.viewDocument(tHandle) + self.openDocumentRequest.emit(tHandle, nwDocMode.VIEW) return diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 6a056dca..354edbf4 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -115,28 +115,6 @@ class GuiMain(QMainWindow): self.mainMenu = GuiMainMenu(self) self.viewsBar = GuiViewsBar(self) - # Connect Signals Between Main Elements - self.viewsBar.viewChangeRequested.connect(self._changeView) - - self.treeView.itemSelectionChanged.connect(self._treeSingleClick) - self.treeView.itemDoubleClicked.connect(self._treeDoubleClick) - self.treeView.novelItemChanged.connect(self._treeNovelItemChanged) - self.treeView.wordCountsChanged.connect(self._updateStatusWordCount) - self.treeView.treeItemChanged.connect(self.docEditor.updateDocInfo) - self.treeView.treeItemChanged.connect(self.docViewer.updateDocInfo) - self.treeView.treeItemChanged.connect(self.treeMeta.updateViewBox) - self.treeView.rootFolderChanged.connect(self.projView.updateRootItem) - - self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage) - self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus) - self.docEditor.docCountsChanged.connect(self.treeMeta.doUpdateCounts) - self.docEditor.docCountsChanged.connect(self.treeView.doUpdateCounts) - self.docEditor.loadDocumentTagRequest.connect(self._followTag) - - self.docViewer.loadDocumentTagRequest.connect(self._followTag) - - self.projView.loadDocumentTagRequest.connect(self._followTag) - # Project Tree Stack self.projStack = QStackedWidget() self.projStack.addWidget(self.treeView) @@ -214,6 +192,30 @@ class GuiMain(QMainWindow): self.setStatusBar(self.statusBar) self.addToolBar(Qt.LeftToolBarArea, self.viewsBar) + # Connect Signals + # =============== + + self.viewsBar.viewChangeRequested.connect(self._changeView) + + self.treeView.selectedItemChanged.connect(self.treeMeta.updateViewBox) + self.treeView.openDocumentRequest.connect(self._openDocument) + self.treeView.novelItemChanged.connect(self._treeNovelItemChanged) + self.treeView.wordCountsChanged.connect(self._updateStatusWordCount) + self.treeView.treeItemChanged.connect(self.docEditor.updateDocInfo) + self.treeView.treeItemChanged.connect(self.docViewer.updateDocInfo) + self.treeView.treeItemChanged.connect(self.treeMeta.updateViewBox) + self.treeView.rootFolderChanged.connect(self.projView.updateRootItem) + + self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage) + self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus) + self.docEditor.docCountsChanged.connect(self.treeMeta.doUpdateCounts) + self.docEditor.docCountsChanged.connect(self.treeView.doUpdateCounts) + self.docEditor.loadDocumentTagRequest.connect(self._followTag) + + self.docViewer.loadDocumentTagRequest.connect(self._followTag) + + self.projView.loadDocumentTagRequest.connect(self._followTag) + # Finalise Initialisation # ======================= @@ -1468,6 +1470,17 @@ class GuiMain(QMainWindow): self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}") return + @pyqtSlot(str, Enum) + def _openDocument(self, tHandle, tMode): + """Handle an open document request. + """ + if tHandle is not None: + if tMode == nwDocMode.EDIT: + self.openDocument(tHandle, changeFocus=False) + elif tMode == nwDocMode.VIEW: + self.viewDocument(tHandle=tHandle) + return + @pyqtSlot(nwView) def _changeView(self, view): """Handle the requested change of view from the GuiViewBar. @@ -1531,32 +1544,6 @@ class GuiMain(QMainWindow): return - @pyqtSlot() - def _treeSingleClick(self): - """Single click on a project tree item just updates the details - panel below the tree. - """ - tHandle = self.treeView.getSelectedHandle() - if tHandle is not None: - self.treeMeta.updateViewBox(tHandle) - return - - @pyqtSlot("QTreeWidgetItem*", int) - def _treeDoubleClick(self, tItem, colNo): - """The user double-clicked an item in the tree. If it is a file, - we open it. Otherwise, we toggle the expanded status. - """ - tHandle = self.treeView.getSelectedHandle() - if tHandle is not None: - tItem = self.theProject.tree[tHandle] - if tItem is None: - return - if tItem.itemType == nwItemType.FILE: - self.openDocument(tHandle, changeFocus=False, doScroll=False) - else: - self.treeView.toggleExpanded(tHandle) - return - @pyqtSlot() def _treeNovelItemChanged(self): """Triggered when there is a change to a novel item in the