Update novel tree menu processing and fix issue with reaload of document
This commit is contained in:
@@ -28,11 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from time import time
|
||||
from enum import Enum
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
|
||||
from PyQt5.QtGui import QPalette, QPixmap, QColor
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
||||
QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
||||
@@ -81,13 +81,7 @@ class GuiNovelView(QWidget):
|
||||
|
||||
self.setLayout(self.outerBox)
|
||||
|
||||
# Connect Signals
|
||||
self.novelBar.rootFolderSelectionChanged.connect(
|
||||
lambda tHandle: self.novelTree.refreshTree(rootHandle=tHandle, overRide=True)
|
||||
)
|
||||
|
||||
# Function Mappings
|
||||
self.refreshTree = self.novelTree.refreshTree
|
||||
self.updateWordCounts = self.novelTree.updateWordCounts
|
||||
self.getSelectedHandle = self.novelTree.getSelectedHandle
|
||||
|
||||
@@ -101,30 +95,44 @@ class GuiNovelView(QWidget):
|
||||
self.novelTree.initSettings()
|
||||
return
|
||||
|
||||
def refreshTree(self):
|
||||
"""Refresh the current tree.
|
||||
"""
|
||||
self.novelTree.refreshTree(rootHandle=self.theProject.lastNovel)
|
||||
return
|
||||
|
||||
def clearProject(self):
|
||||
self.novelTree.clearTree()
|
||||
"""Clear project-related GUI content.
|
||||
"""
|
||||
self.novelTree.clearContent()
|
||||
self.novelBar.clearContent()
|
||||
return
|
||||
|
||||
def openProjectTasks(self):
|
||||
"""Run tasks when opening a project.
|
||||
"""Run opening project tasks.
|
||||
"""
|
||||
lastNovel = self.theProject.lastNovel
|
||||
if lastNovel is None:
|
||||
if lastNovel not in self.theProject.tree:
|
||||
lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
|
||||
|
||||
logger.debug("Setting novel tree to root item '%s'", lastNovel)
|
||||
|
||||
lastCol = self.theProject.options.getEnum(
|
||||
"GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.HIDDEN
|
||||
)
|
||||
|
||||
self.clearProject()
|
||||
self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
|
||||
self.novelTree.loadOptions()
|
||||
self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
|
||||
self.novelBar.buildNovelRootMenu()
|
||||
self.novelBar.setLastColType(lastCol, doRefresh=False)
|
||||
self.novelBar.setCurrentRoot(lastNovel)
|
||||
|
||||
return
|
||||
|
||||
def closeProjectTasks(self):
|
||||
"""Run tasks when closing a project.
|
||||
"""Run closing project tasks.
|
||||
"""
|
||||
self.novelTree.saveOptions()
|
||||
lastColType = self.novelTree.lastColType
|
||||
self.theProject.options.setValue("GuiNovelView", "lastCol", lastColType)
|
||||
return
|
||||
|
||||
def setFocus(self):
|
||||
@@ -133,7 +141,7 @@ class GuiNovelView(QWidget):
|
||||
self.novelTree.setFocus()
|
||||
return
|
||||
|
||||
def treeFocus(self):
|
||||
def treeHasFocus(self):
|
||||
"""Check if the novel tree has focus.
|
||||
"""
|
||||
return self.novelTree.hasFocus()
|
||||
@@ -144,9 +152,9 @@ class GuiNovelView(QWidget):
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateRootItem(self, tHandle):
|
||||
"""Should be called whenever a root folders changes.
|
||||
"""If any root item changes, rebuild the novel root menu.
|
||||
"""
|
||||
self.novelBar.rebuildNovelRootMenu()
|
||||
self.novelBar.buildNovelRootMenu()
|
||||
return
|
||||
|
||||
# END Class GuiNovelView
|
||||
@@ -154,8 +162,6 @@ class GuiNovelView(QWidget):
|
||||
|
||||
class GuiNovelToolBar(QWidget):
|
||||
|
||||
rootFolderSelectionChanged = pyqtSignal(str)
|
||||
|
||||
def __init__(self, novelView):
|
||||
QTreeWidget.__init__(self, novelView)
|
||||
|
||||
@@ -167,7 +173,7 @@ class GuiNovelToolBar(QWidget):
|
||||
self.mainTheme = novelView.mainGui.mainTheme
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
mPx = self.mainConf.pxInt(4)
|
||||
mPx = self.mainConf.pxInt(3)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
@@ -197,6 +203,8 @@ class GuiNovelToolBar(QWidget):
|
||||
|
||||
# Novel Root Menu
|
||||
self.mRoot = QMenu()
|
||||
self.gRoot = QActionGroup(self.mRoot)
|
||||
self.aRoot = {}
|
||||
|
||||
self.tbRoot = QToolButton(self)
|
||||
self.tbRoot.setToolTip(self.tr("Novel Root"))
|
||||
@@ -209,19 +217,13 @@ class GuiNovelToolBar(QWidget):
|
||||
# More Options Menu
|
||||
self.mMore = QMenu()
|
||||
|
||||
self.mCol3 = self.mMore.addMenu(self.tr("Third Column"))
|
||||
self.mCol3.addAction(self.tr("Hide Column")).triggered.connect(
|
||||
lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.HIDDEN)
|
||||
)
|
||||
self.mCol3.addAction(self.tr("Point of View Character")).triggered.connect(
|
||||
lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.POV)
|
||||
)
|
||||
self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
|
||||
lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.FOCUS)
|
||||
)
|
||||
self.mCol3.addAction(self.tr("Novel Plot")).triggered.connect(
|
||||
lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.PLOT)
|
||||
)
|
||||
self.mLastCol = self.mMore.addMenu(self.tr("Last Column"))
|
||||
self.gLastCol = QActionGroup(self.mMore)
|
||||
self.aLastCol = {}
|
||||
self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden"))
|
||||
self._addLastColAction(NovelTreeColumn.POV, self.tr("Point of View Character"))
|
||||
self._addLastColAction(NovelTreeColumn.FOCUS, self.tr("Focus Character"))
|
||||
self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot"))
|
||||
|
||||
self.tbMore = QToolButton(self)
|
||||
self.tbMore.setToolTip(self.tr("More Options"))
|
||||
@@ -250,25 +252,41 @@ class GuiNovelToolBar(QWidget):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def rebuildNovelRootMenu(self, selHandle=None):
|
||||
def clearContent(self):
|
||||
"""Run clearing project tasks.
|
||||
"""
|
||||
self.mRoot.clear()
|
||||
self.aRoot = {}
|
||||
return
|
||||
|
||||
def buildNovelRootMenu(self):
|
||||
"""Build the novel root menu.
|
||||
"""
|
||||
self.mRoot.clear()
|
||||
agRoot = QActionGroup(self.mRoot)
|
||||
self.aRoot = {}
|
||||
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(nwItemClass.NOVEL)):
|
||||
aRoot = self.mRoot.addAction(nwItem.itemName)
|
||||
aRoot.setData(tHandle)
|
||||
aRoot.setCheckable(True)
|
||||
aRoot.triggered.connect(
|
||||
lambda n, tHandle=tHandle: self.rootFolderSelectionChanged.emit(tHandle)
|
||||
)
|
||||
agRoot.addAction(aRoot)
|
||||
aRoot.triggered.connect(lambda n, tHandle=tHandle: self.setCurrentRoot(tHandle))
|
||||
self.gRoot.addAction(aRoot)
|
||||
self.aRoot[tHandle] = aRoot
|
||||
|
||||
if n == 0:
|
||||
aRoot.setChecked(True)
|
||||
if selHandle == tHandle:
|
||||
aRoot.setChecked(True)
|
||||
return
|
||||
|
||||
def setCurrentRoot(self, rootHandle):
|
||||
"""Set the current active root handle.
|
||||
"""
|
||||
if rootHandle in self.aRoot:
|
||||
self.aRoot[rootHandle].setChecked(True)
|
||||
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||
return
|
||||
|
||||
def setLastColType(self, colType, doRefresh=True):
|
||||
"""Set the last column type.
|
||||
"""
|
||||
self.aLastCol[colType].setChecked(True)
|
||||
self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -283,6 +301,20 @@ class GuiNovelToolBar(QWidget):
|
||||
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _addLastColAction(self, colType, actionLabel):
|
||||
"""Add a column selection entry to the last column menu.
|
||||
"""
|
||||
aLast = self.mLastCol.addAction(actionLabel)
|
||||
aLast.setCheckable(True)
|
||||
aLast.setActionGroup(self.gLastCol)
|
||||
aLast.triggered.connect(lambda: self.setLastColType(colType))
|
||||
self.aLastCol[colType] = aLast
|
||||
return
|
||||
|
||||
# END Class GuiNovelToolBar
|
||||
|
||||
|
||||
@@ -319,13 +351,12 @@ class GuiNovelTree(QTreeWidget):
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
nPx = self.mainTheme.textNWidth
|
||||
cMg = self.mainConf.pxInt(6)
|
||||
mPx = self.mainConf.pxInt(4)
|
||||
nMg = self.mainConf.pxInt(6)
|
||||
|
||||
# self.setIconSize(QSize(iPx, iPx))
|
||||
self.setFrameStyle(QFrame.NoFrame)
|
||||
self.setHeaderHidden(True)
|
||||
self.setIndentation(mPx)
|
||||
self.setIndentation(0)
|
||||
self.setColumnCount(3)
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
@@ -349,7 +380,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
fH2.setBold(True)
|
||||
|
||||
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
|
||||
self._hIndent = ["", "", "", "\u2022\u00a0", "\u00bb\u00a0"]
|
||||
self._hIndent = ["", "", "", "\u203a\u00a0", "\u00bb\u00a0"]
|
||||
self._pIndent = [QPixmap(), QPixmap()]
|
||||
|
||||
hPix = QPixmap(QSize(iPx, iPx))
|
||||
@@ -386,11 +417,19 @@ class GuiNovelTree(QTreeWidget):
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def lastColType(self):
|
||||
return self._lastCol
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def clearTree(self):
|
||||
def clearContent(self):
|
||||
"""Clear the GUI content and the related maps.
|
||||
"""
|
||||
self.clear()
|
||||
@@ -398,21 +437,6 @@ class GuiNovelTree(QTreeWidget):
|
||||
self._lastBuild = 0
|
||||
return
|
||||
|
||||
def loadOptions(self):
|
||||
"""Load user options.
|
||||
"""
|
||||
self._lastCol = self.theProject.options.getEnum(
|
||||
"GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.POV
|
||||
)
|
||||
self.setColumnHidden(self.C_LAST, self._lastCol == NovelTreeColumn.HIDDEN)
|
||||
return True
|
||||
|
||||
def saveOptions(self):
|
||||
"""Save user options.
|
||||
"""
|
||||
self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol)
|
||||
return
|
||||
|
||||
def refreshTree(self, rootHandle=None, overRide=False):
|
||||
"""Called whenever the Novel tab is activated.
|
||||
"""
|
||||
@@ -461,14 +485,15 @@ class GuiNovelTree(QTreeWidget):
|
||||
|
||||
return tHandle, tLine
|
||||
|
||||
def setLastColType(self, colType):
|
||||
def setLastColType(self, colType, doRefresh=True):
|
||||
"""Change the content type of the last column and rebuild.
|
||||
"""
|
||||
if self._lastCol != colType:
|
||||
logger.debug("Changing last column to %s", colType.name)
|
||||
self._lastCol = colType
|
||||
self.setColumnHidden(self.C_LAST, colType == NovelTreeColumn.HIDDEN)
|
||||
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
|
||||
if doRefresh:
|
||||
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
|
||||
return
|
||||
|
||||
##
|
||||
@@ -531,7 +556,7 @@ class GuiNovelTree(QTreeWidget):
|
||||
def _populateTree(self, rootHandle):
|
||||
"""Build the tree based on the project index.
|
||||
"""
|
||||
self.clearTree()
|
||||
self.clearContent()
|
||||
tStart = time()
|
||||
logger.verbose("Building novel tree for root item '%s'", rootHandle)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class GuiOutlineView(QWidget):
|
||||
self.outlineTree.refreshTree(overRide=overRide, novelChanged=novelChanged)
|
||||
return
|
||||
|
||||
def treeFocus(self):
|
||||
def treeHasFocus(self):
|
||||
return self.outlineTree.hasFocus()
|
||||
|
||||
def setTreeFocus(self):
|
||||
|
||||
+11
-18
@@ -31,8 +31,8 @@ import novelwriter
|
||||
from enum import Enum
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtGui import QPalette
|
||||
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QIcon, QPalette
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
||||
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
|
||||
@@ -142,7 +142,7 @@ class GuiProjectView(QWidget):
|
||||
self.projTree.setFocus()
|
||||
return
|
||||
|
||||
def treeFocus(self):
|
||||
def treeHasFocus(self):
|
||||
"""Check if the project tree has focus.
|
||||
"""
|
||||
return self.projTree.hasFocus()
|
||||
@@ -177,7 +177,7 @@ class GuiProjectToolBar(QWidget):
|
||||
self.mainTheme = projView.mainGui.mainTheme
|
||||
|
||||
iPx = self.mainTheme.baseIconSize
|
||||
mPx = self.mainConf.pxInt(4)
|
||||
mPx = self.mainConf.pxInt(3)
|
||||
|
||||
self.setContentsMargins(0, 0, 0, 0)
|
||||
self.setAutoFillBackground(True)
|
||||
@@ -252,7 +252,7 @@ class GuiProjectToolBar(QWidget):
|
||||
self._addRootFolderEntry(nwItemClass.PLOT)
|
||||
self._addRootFolderEntry(nwItemClass.CHARACTER)
|
||||
self._addRootFolderEntry(nwItemClass.WORLD)
|
||||
self._addRootFolderEntry(nwItemClass.ARCHIVE)
|
||||
self._addRootFolderEntry(nwItemClass.TIMELINE)
|
||||
self._addRootFolderEntry(nwItemClass.OBJECT)
|
||||
self._addRootFolderEntry(nwItemClass.ENTITY)
|
||||
self._addRootFolderEntry(nwItemClass.CUSTOM)
|
||||
@@ -778,13 +778,6 @@ class GuiProjectTree(QTreeWidget):
|
||||
if trItem is None or nwItem is None:
|
||||
return
|
||||
|
||||
expIcon = QIcon()
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
if nwItem.isExported:
|
||||
expIcon = self.mainTheme.getIcon("check")
|
||||
else:
|
||||
expIcon = self.mainTheme.getIcon("cross")
|
||||
|
||||
itemStatus, statusIcon = nwItem.getImportStatus()
|
||||
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
|
||||
itemIcon = self.mainTheme.getItemIcon(
|
||||
@@ -793,18 +786,18 @@ class GuiProjectTree(QTreeWidget):
|
||||
|
||||
trItem.setIcon(self.C_NAME, itemIcon)
|
||||
trItem.setText(self.C_NAME, nwItem.itemName)
|
||||
trItem.setIcon(self.C_EXPORT, expIcon)
|
||||
trItem.setIcon(self.C_STATUS, statusIcon)
|
||||
trItem.setToolTip(self.C_STATUS, itemStatus)
|
||||
|
||||
if nwItem.itemType == nwItemType.FILE:
|
||||
trItem.setIcon(
|
||||
self.C_EXPORT, self.mainTheme.getIcon("check" if nwItem.isExported else "cross")
|
||||
)
|
||||
|
||||
if self.mainConf.emphLabels and nwItem.itemLayout == nwItemLayout.DOCUMENT:
|
||||
trFont = trItem.font(self.C_NAME)
|
||||
if hLevel in ("H1", "H2"):
|
||||
trFont.setBold(True)
|
||||
trFont.setUnderline(True)
|
||||
else:
|
||||
trFont.setBold(False)
|
||||
trFont.setUnderline(False)
|
||||
trFont.setBold(hLevel == "H1" or hLevel == "H2")
|
||||
trFont.setUnderline(hLevel == "H1")
|
||||
trItem.setFont(self.C_NAME, trFont)
|
||||
|
||||
return
|
||||
|
||||
@@ -796,11 +796,11 @@ class GuiMain(QMainWindow):
|
||||
|
||||
tHandle = None
|
||||
tLine = None
|
||||
if self.projView.treeFocus():
|
||||
if self.projView.treeHasFocus():
|
||||
tHandle = self.projView.getSelectedHandle()
|
||||
elif self.novelView.treeFocus():
|
||||
elif self.novelView.treeHasFocus():
|
||||
tHandle, tLine = self.novelView.getSelectedHandle()
|
||||
elif self.outlineView.treeFocus():
|
||||
elif self.outlineView.treeHasFocus():
|
||||
tHandle, tLine = self.outlineView.getSelectedHandle()
|
||||
else:
|
||||
logger.warning("No item selected")
|
||||
|
||||
@@ -135,7 +135,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
nwGUI._changeView(nwView.NOVEL)
|
||||
nwGUI.novelView.refreshTree(rootHandle=None, overRide=True)
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(GuiNovelView, "treeFocus", lambda *a: True)
|
||||
mp.setattr(GuiNovelView, "treeHasFocus", lambda *a: True)
|
||||
assert nwGUI.docEditor.docHandle() is None
|
||||
selItem = nwGUI.novelView.novelTree.topLevelItem(2)
|
||||
nwGUI.novelView.novelTree.setCurrentItem(selItem)
|
||||
@@ -147,7 +147,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
nwGUI._changeView(nwView.OUTLINE)
|
||||
nwGUI.switchFocus(nwWidget.OUTLINE)
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(GuiOutlineView, "treeFocus", lambda *a: True)
|
||||
mp.setattr(GuiOutlineView, "treeHasFocus", lambda *a: True)
|
||||
assert nwGUI.docEditor.docHandle() is None
|
||||
actItem = nwGUI.outlineView.outlineTree.topLevelItem(0)
|
||||
chpItem = actItem.child(0)
|
||||
|
||||
@@ -71,7 +71,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
|
||||
# Check focus
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QWidget, "hasFocus", lambda *a: True)
|
||||
assert outlineView.treeFocus() is True
|
||||
assert outlineView.treeHasFocus() is True
|
||||
|
||||
outlineView.setTreeFocus() # Can't check. just ensures that it doesn't error
|
||||
|
||||
|
||||
Reference in New Issue
Block a user