From bbbad2b17001abcdd9915678520a7dff043c0411 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 14 Oct 2022 17:29:07 +0200
Subject: [PATCH 1/3] Add bookmark icon
---
.../assets/icons/typicons_dark/icons.conf | 1 +
.../icons/typicons_dark/typ_bookmark.svg | 31 +++++++++++++++++++
.../assets/icons/typicons_light/icons.conf | 1 +
.../icons/typicons_light/typ_bookmark.svg | 31 +++++++++++++++++++
novelwriter/gui/theme.py | 6 ++--
5 files changed, 67 insertions(+), 3 deletions(-)
create mode 100644 novelwriter/assets/icons/typicons_dark/typ_bookmark.svg
create mode 100644 novelwriter/assets/icons/typicons_light/typ_bookmark.svg
diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf
index c347bf3c..521e9ee8 100644
--- a/novelwriter/assets/icons/typicons_dark/icons.conf
+++ b/novelwriter/assets/icons/typicons_dark/icons.conf
@@ -18,6 +18,7 @@ licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
[Map]
add = typ_plus.svg
backward = typ_chevron-left.svg
+bookmark = typ_bookmark.svg
bullet-off = typ_media-record-outline.svg
bullet-on = typ_media-record.svg
check = typ_tick.svg
diff --git a/novelwriter/assets/icons/typicons_dark/typ_bookmark.svg b/novelwriter/assets/icons/typicons_dark/typ_bookmark.svg
new file mode 100644
index 00000000..bea4bafa
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/typ_bookmark.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf
index 796b170f..1b6b1348 100644
--- a/novelwriter/assets/icons/typicons_light/icons.conf
+++ b/novelwriter/assets/icons/typicons_light/icons.conf
@@ -18,6 +18,7 @@ licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
[Map]
add = typ_plus.svg
backward = typ_chevron-left.svg
+bookmark = typ_bookmark.svg
bullet-off = typ_media-record-outline.svg
bullet-on = typ_media-record.svg
check = typ_tick.svg
diff --git a/novelwriter/assets/icons/typicons_light/typ_bookmark.svg b/novelwriter/assets/icons/typicons_light/typ_bookmark.svg
new file mode 100644
index 00000000..e7fa1eee
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/typ_bookmark.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index 7227ed11..131628c0 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -466,9 +466,9 @@ class GuiIcons:
"view_editor", "view_novel", "view_outline",
# General Button Icons
- "add", "backward", "check", "close", "cross", "down", "edit", "forward", "maximise",
- "menu", "minimise", "reference", "refresh", "remove", "search_replace", "search",
- "settings", "up",
+ "add", "backward", "bookmark", "check", "close", "cross", "down", "edit", "forward",
+ "maximise", "menu", "minimise", "reference", "refresh", "remove", "search_replace",
+ "search", "settings", "up",
# Switches
"sticky-on", "sticky-off",
From 77ec0a9eedcd6a1b2c9cd3e951e96c54f98f8028 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 14 Oct 2022 17:30:28 +0200
Subject: [PATCH 2/3] Add a quick links dropdown menu to the project tree
(#1137)
---
novelwriter/core/tree.py | 10 ++--
novelwriter/gui/projtree.py | 92 ++++++++++++++++++++++++++++++++-----
novelwriter/guimain.py | 7 ++-
3 files changed, 91 insertions(+), 18 deletions(-)
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:
From 5fcfbf1c7539ae9aa02d6ccc575567cb7f4bf2f7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Fri, 14 Oct 2022 17:35:10 +0200
Subject: [PATCH 3/3] Add shortcut to docs, and fix broken link
---
docs/source/int_customise.rst | 2 +-
docs/source/usage_shortcuts.rst | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/source/int_customise.rst b/docs/source/int_customise.rst
index c5c26e3b..f77cc9cc 100644
--- a/docs/source/int_customise.rst
+++ b/docs/source/int_customise.rst
@@ -71,5 +71,5 @@ On Windows, file extensions may not be visible by default, so make sure you only
extension, and don't end up with two.
The QSS files are Qt Style Sheet files. See Qt's
-`The Style Sheet Syntax `_` documentation for more
+`The Style Sheet Syntax `_ documentation for more
details.
diff --git a/docs/source/usage_shortcuts.rst b/docs/source/usage_shortcuts.rst
index e9e7bb36..7a321bcc 100644
--- a/docs/source/usage_shortcuts.rst
+++ b/docs/source/usage_shortcuts.rst
@@ -47,6 +47,7 @@ The main shorcuts are as follows:
":kbd:`Ctrl`:kbd:`H`", "Open the search and replace bar and search for the selected word, if any is selected. (On Mac, this is :kbd:`Cmd`:kbd:`=`.)"
":kbd:`Ctrl`:kbd:`I`", "Format selected text, or word under cursor, with emphasis (italic)."
":kbd:`Ctrl`:kbd:`K`", "Activate the insert commands. The commands are listed in :ref:`a_kb_ins`."
+ ":kbd:`Ctrl`:kbd:`L`", "Open the :guilabel:`Quick Links` menu in the Project Tree."
":kbd:`Ctrl`:kbd:`N`", "Create new project item."
":kbd:`Ctrl`:kbd:`O`", "Open selected document."
":kbd:`Ctrl`:kbd:`Q`", "Exit novelWriter."