diff --git a/novelwriter/core/tree.py b/novelwriter/core/tree.py index ec8073df..0a3733a8 100644 --- a/novelwriter/core/tree.py +++ b/novelwriter/core/tree.py @@ -274,11 +274,13 @@ class NWTree: return rootClasses def iterRoots(self, itemClass): - """Iterate over all items of a given class. + """Iterate over all root items of a given class in order. """ - for tHandle, nwItem in self._treeRoots.items(): - if nwItem.itemClass == itemClass: - yield tHandle, nwItem + for tHandle in self._treeOrder: + nwItem = self.__getitem__(tHandle) + if nwItem is not None and nwItem.isRootType(): + if itemClass is None or nwItem.itemClass == itemClass: + yield tHandle, nwItem return def isRoot(self, tHandle): diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 78609b45..181b8b55 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -121,18 +121,33 @@ class GuiProjectView(QWidget): ## def initSettings(self): + """Initialise GUI elements that depend on specific settings. + """ self.projTree.initSettings() return def clearProject(self): + """Clear project-related GUI content. + """ + self.projBar.clearContent() self.projTree.clearTree() return - def saveProjectTree(self): + def openProjectTasks(self): + """Run open project tasks. + """ + self.projBar.buildQuickLinkMenu() + return + + def saveProjectTasks(self): + """Run save project tasks. + """ self.projTree.saveTreeOrder() return def populateTree(self): + """Build the tree structure from project data. + """ self.projTree.buildTree() return @@ -159,6 +174,13 @@ class GuiProjectView(QWidget): self.wordCountsChanged.emit() return + @pyqtSlot(str) + def updateRootItem(self, tHandle): + """If any root item changes, rebuild the quick link root menu. + """ + self.projBar.buildQuickLinkMenu() + return + # END Class GuiProjectView @@ -197,6 +219,18 @@ class GuiProjectToolBar(QWidget): self.viewLabel.setContentsMargins(0, 0, 0, 0) self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + # Quick Links + self.mQuick = QMenu() + + self.tbQuick = QToolButton(self) + self.tbQuick.setToolTip("%s [Ctrl+L]" % self.tr("Quick Links")) + self.tbQuick.setShortcut("Ctrl+L") + self.tbQuick.setIcon(self.mainTheme.getIcon("bookmark")) + self.tbQuick.setIconSize(QSize(iPx, iPx)) + self.tbQuick.setStyleSheet(buttonStyle) + self.tbQuick.setMenu(self.mQuick) + self.tbQuick.setPopupMode(QToolButton.InstantPopup) + # Move Buttons self.tbMoveU = QToolButton(self) self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up")) @@ -292,6 +326,7 @@ class GuiProjectToolBar(QWidget): # Assemble self.outerBox = QHBoxLayout() self.outerBox.addWidget(self.viewLabel) + self.outerBox.addWidget(self.tbQuick) self.outerBox.addWidget(self.tbMoveU) self.outerBox.addWidget(self.tbMoveD) self.outerBox.addWidget(self.tbAdd) @@ -305,6 +340,32 @@ class GuiProjectToolBar(QWidget): return + ## + # Methods + ## + + def clearContent(self): + """Clear dynamic content on the tool bar. + """ + self.mQuick.clear() + return + + def buildQuickLinkMenu(self): + """Build the quick link menu. + """ + logger.verbose("Rebuilding quick links menu") + + self.mQuick.clear() + for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(None)): + aRoot = self.mQuick.addAction(nwItem.itemName) + aRoot.setData(tHandle) + aRoot.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])) + aRoot.triggered.connect( + lambda n, tHandle=tHandle: self.projView.setSelectedHandle(tHandle, doScroll=True) + ) + + return + ## # Internal Functions ## @@ -545,8 +606,7 @@ class GuiProjectTree(QTreeWidget): self._treeMap[pHandle].setExpanded(True) self._alertTreeChange(tHandle, flush=True) - self.clearSelection() - trItem.setSelected(True) + self.setCurrentItem(trItem) return True @@ -585,8 +645,7 @@ class GuiProjectTree(QTreeWidget): self._recordLastMove(cItem, pItem, tIndex) self._alertTreeChange(tHandle, flush=True) - self.clearSelection() - trItem.setSelected(True) + self.setCurrentItem(trItem) trItem.setExpanded(isExp) return True @@ -790,6 +849,11 @@ class GuiProjectTree(QTreeWidget): self._treeMap.pop(tHandle, None) self._alertTreeChange(tHandle, flush=True) + # These are not emitted by the alert function because the + # item has already been deleted + self.projView.rootFolderChanged.emit(tHandle) + self.projView.treeItemChanged.emit(tHandle) + else: if askFirst: msgYes = self.mainGui.askQuestion( @@ -817,6 +881,10 @@ class GuiProjectTree(QTreeWidget): self._alertTreeChange(tHandle, flush=flush) self.projView.wordCountsChanged.emit() + # This is not emitted by the alert function because the item + # has already been deleted + self.projView.treeItemChanged.emit(tHandle) + return True def setTreeItemValues(self, tHandle): @@ -945,8 +1013,7 @@ class GuiProjectTree(QTreeWidget): self._postItemMove(sHandle, wCount) self._alertTreeChange(sHandle, flush=True) - self.clearSelection() - movItem.setSelected(True) + self.setCurrentItem(movItem) self._lastMove = {} return True @@ -968,12 +1035,13 @@ class GuiProjectTree(QTreeWidget): if tItem is None: return False - self.clearSelection() - self._treeMap[tHandle].setSelected(True) + self.setFocus() + if tHandle in self._treeMap: + self.setCurrentItem(self._treeMap[tHandle]) - selItems = self.selectedIndexes() - if selItems and doScroll: - self.scrollTo(selItems[0], QAbstractItemView.PositionAtCenter) + selIndex = self.selectedIndexes() + if selIndex and doScroll: + self.scrollTo(selIndex[0], QAbstractItemView.PositionAtCenter) return True diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 67071bf5..a8676686 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -206,6 +206,7 @@ class GuiMain(QMainWindow): self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox) self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem) self.projView.rootFolderChanged.connect(self.novelView.updateRootItem) + self.projView.rootFolderChanged.connect(self.projView.updateRootItem) self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox) self.novelView.openDocumentRequest.connect(self._openDocument) @@ -370,6 +371,7 @@ class GuiMain(QMainWindow): self.saveProject() self.docEditor.setDictionaries() + self.projView.openProjectTasks() self.novelView.openProjectTasks() self.outlineView.openProjectTasks() self.rebuildIndex(beQuiet=True) @@ -522,6 +524,7 @@ class GuiMain(QMainWindow): self.docEditor.setDictionaries() self.docEditor.toggleSpellCheck(self.theProject.spellCheck) self.statusBar.setRefTime(self.theProject.projOpened) + self.projView.openProjectTasks() self.novelView.openProjectTasks() self.outlineView.openProjectTasks() self._updateStatusWordCount() @@ -556,7 +559,7 @@ class GuiMain(QMainWindow): logger.error("No project open") return False - self.projView.saveProjectTree() + self.projView.saveProjectTasks() if self.theProject.saveProject(autoSave=autoSave): self.theProject.index.saveIndex() @@ -841,7 +844,7 @@ class GuiMain(QMainWindow): qApp.setOverrideCursor(QCursor(Qt.WaitCursor)) tStart = time() - self.projView.saveProjectTree() + self.projView.saveProjectTasks() self.theProject.index.clearIndex() for tItem in self.theProject.tree: