Allow changing content of last column of the novel tree
This commit is contained in:
@@ -56,7 +56,8 @@ VALID_MAP = {
|
|||||||
"winWidth", "winHeight", "widthCol0", "widthCol1", "widthCol2",
|
"winWidth", "winHeight", "widthCol0", "widthCol1", "widthCol2",
|
||||||
"widthCol3", "widthCol4", "wordsPerPage", "countFrom", "clearDouble"
|
"widthCol3", "widthCol4", "wordsPerPage", "countFrom", "clearDouble"
|
||||||
},
|
},
|
||||||
"GuiWordList": {"winWidth", "winHeight"}
|
"GuiWordList": {"winWidth", "winHeight"},
|
||||||
|
"GuiNovelView": {"lastCol"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,11 +39,20 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
from novelwriter.enum import nwDocMode, nwItemClass
|
from novelwriter.enum import nwDocMode, nwItemClass
|
||||||
from novelwriter.common import checkInt
|
from novelwriter.common import checkInt
|
||||||
from novelwriter.constants import nwKeyWords, nwLabels
|
from novelwriter.constants import nwKeyWords, nwLabels, trConst
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class NovelColumnType(Enum):
|
||||||
|
|
||||||
|
HIDDEN = 0
|
||||||
|
POV = 1
|
||||||
|
FOCUS = 2
|
||||||
|
|
||||||
|
# END Enum NovelColumnType
|
||||||
|
|
||||||
|
|
||||||
class GuiNovelView(QWidget):
|
class GuiNovelView(QWidget):
|
||||||
|
|
||||||
# Signals for user interaction with the novel tree
|
# Signals for user interaction with the novel tree
|
||||||
@@ -94,7 +103,7 @@ class GuiNovelView(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def openProjectTasks(self):
|
def openProjectTasks(self):
|
||||||
"""Run tasks related to opening a project.
|
"""Run tasks when opening a project.
|
||||||
"""
|
"""
|
||||||
lastNovel = self.theProject.lastNovel
|
lastNovel = self.theProject.lastNovel
|
||||||
if lastNovel is None:
|
if lastNovel is None:
|
||||||
@@ -104,10 +113,17 @@ class GuiNovelView(QWidget):
|
|||||||
|
|
||||||
self.clearProject()
|
self.clearProject()
|
||||||
self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
|
self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
|
||||||
|
self.novelTree.loadOptions()
|
||||||
self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
|
self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def closeProjectTasks(self):
|
||||||
|
"""Run tasks when closing a project.
|
||||||
|
"""
|
||||||
|
self.novelTree.saveOptions()
|
||||||
|
return
|
||||||
|
|
||||||
def setFocus(self):
|
def setFocus(self):
|
||||||
"""Forward the set focus call to the tree widget.
|
"""Forward the set focus call to the tree widget.
|
||||||
"""
|
"""
|
||||||
@@ -168,6 +184,14 @@ class GuiNovelToolBar(QWidget):
|
|||||||
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
||||||
self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
# Refresh Button
|
||||||
|
self.tbRefresh = QToolButton(self)
|
||||||
|
self.tbRefresh.setToolTip(self.tr("Refresh"))
|
||||||
|
self.tbRefresh.setIcon(self.mainTheme.getIcon("refresh"))
|
||||||
|
self.tbRefresh.setIconSize(QSize(iPx, iPx))
|
||||||
|
self.tbRefresh.setStyleSheet(buttonStyle)
|
||||||
|
self.tbRefresh.clicked.connect(self._refreshNovelTree)
|
||||||
|
|
||||||
# Novel Root Menu
|
# Novel Root Menu
|
||||||
self.mRoot = QMenu()
|
self.mRoot = QMenu()
|
||||||
|
|
||||||
@@ -182,6 +206,17 @@ class GuiNovelToolBar(QWidget):
|
|||||||
# More Options Menu
|
# More Options Menu
|
||||||
self.mMore = QMenu()
|
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(NovelColumnType.HIDDEN)
|
||||||
|
)
|
||||||
|
self.mCol3.addAction(self.tr("Point of View Character")).triggered.connect(
|
||||||
|
lambda: self.novelView.novelTree.setLastColType(NovelColumnType.POV)
|
||||||
|
)
|
||||||
|
self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
|
||||||
|
lambda: self.novelView.novelTree.setLastColType(NovelColumnType.FOCUS)
|
||||||
|
)
|
||||||
|
|
||||||
self.tbMore = QToolButton(self)
|
self.tbMore = QToolButton(self)
|
||||||
self.tbMore.setToolTip(self.tr("More Options"))
|
self.tbMore.setToolTip(self.tr("More Options"))
|
||||||
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
|
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
|
||||||
@@ -193,6 +228,7 @@ class GuiNovelToolBar(QWidget):
|
|||||||
# Assemble
|
# Assemble
|
||||||
self.outerBox = QHBoxLayout()
|
self.outerBox = QHBoxLayout()
|
||||||
self.outerBox.addWidget(self.viewLabel)
|
self.outerBox.addWidget(self.viewLabel)
|
||||||
|
self.outerBox.addWidget(self.tbRefresh)
|
||||||
self.outerBox.addWidget(self.tbRoot)
|
self.outerBox.addWidget(self.tbRoot)
|
||||||
self.outerBox.addWidget(self.tbMore)
|
self.outerBox.addWidget(self.tbMore)
|
||||||
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
|
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
|
||||||
@@ -230,6 +266,18 @@ class GuiNovelToolBar(QWidget):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Private Slots
|
||||||
|
##
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _refreshNovelTree(self):
|
||||||
|
"""Rebuild the current tree.
|
||||||
|
"""
|
||||||
|
rootHandle = self.theProject.lastNovel
|
||||||
|
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
||||||
|
return
|
||||||
|
|
||||||
# END Class GuiNovelToolBar
|
# END Class GuiNovelToolBar
|
||||||
|
|
||||||
|
|
||||||
@@ -237,7 +285,7 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
|
|
||||||
C_TITLE = 0
|
C_TITLE = 0
|
||||||
C_WORDS = 1
|
C_WORDS = 1
|
||||||
C_POV = 2
|
C_LAST = 2
|
||||||
|
|
||||||
def __init__(self, novelView):
|
def __init__(self, novelView):
|
||||||
QTreeWidget.__init__(self, novelView)
|
QTreeWidget.__init__(self, novelView)
|
||||||
@@ -253,6 +301,11 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
# Internal Variables
|
# Internal Variables
|
||||||
self._treeMap = {}
|
self._treeMap = {}
|
||||||
self._lastBuild = 0
|
self._lastBuild = 0
|
||||||
|
self._lastCol = NovelColumnType.POV
|
||||||
|
|
||||||
|
# Cached i18n Strings
|
||||||
|
self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
|
||||||
|
self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
|
||||||
|
|
||||||
# Build GUI
|
# Build GUI
|
||||||
# =========
|
# =========
|
||||||
@@ -276,7 +329,7 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
treeHeader.setMinimumSectionSize(iPx + cMg)
|
treeHeader.setMinimumSectionSize(iPx + cMg)
|
||||||
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
|
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
|
||||||
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
|
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
|
||||||
treeHeader.setSectionResizeMode(self.C_POV, QHeaderView.ResizeToContents)
|
treeHeader.setSectionResizeMode(self.C_LAST, QHeaderView.ResizeToContents)
|
||||||
|
|
||||||
# Connect signals
|
# Connect signals
|
||||||
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||||
@@ -317,6 +370,32 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
self._lastBuild = 0
|
self._lastBuild = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def loadOptions(self):
|
||||||
|
"""Load user options.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
lastCol = NovelColumnType[self.theProject.options.getString(
|
||||||
|
"GuiNovelView", "lastCol", NovelColumnType.POV.name
|
||||||
|
)]
|
||||||
|
except Exception:
|
||||||
|
logger.error("Failed to load last column type from options")
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._lastCol = lastCol
|
||||||
|
self.setColumnHidden(self.C_LAST, lastCol == NovelColumnType.HIDDEN)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def saveOptions(self):
|
||||||
|
"""Save user options.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol.name)
|
||||||
|
except Exception:
|
||||||
|
logger.error("Failed to save last column type to options")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def refreshTree(self, rootHandle=None, overRide=False):
|
def refreshTree(self, rootHandle=None, overRide=False):
|
||||||
"""Called whenever the Novel tab is activated.
|
"""Called whenever the Novel tab is activated.
|
||||||
"""
|
"""
|
||||||
@@ -365,6 +444,16 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
|
|
||||||
return tHandle, tLine
|
return tHandle, tLine
|
||||||
|
|
||||||
|
def setLastColType(self, colType):
|
||||||
|
"""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 == NovelColumnType.HIDDEN)
|
||||||
|
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
|
||||||
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Events
|
# Events
|
||||||
##
|
##
|
||||||
@@ -431,6 +520,8 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
currChapter = None
|
currChapter = None
|
||||||
currScene = None
|
currScene = None
|
||||||
|
|
||||||
|
tStart = time()
|
||||||
|
|
||||||
logger.verbose("Building novel tree for root item '%s'", rootHandle)
|
logger.verbose("Building novel tree for root item '%s'", rootHandle)
|
||||||
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
|
||||||
for tKey, tHandle, sTitle, novIdx in novStruct:
|
for tKey, tHandle, sTitle, novIdx in novStruct:
|
||||||
@@ -477,6 +568,8 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
|
|
||||||
tItem.setExpanded(True)
|
tItem.setExpanded(True)
|
||||||
|
|
||||||
|
logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000)
|
||||||
|
|
||||||
self._lastBuild = time()
|
self._lastBuild = time()
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -496,8 +589,20 @@ class GuiNovelTree(QTreeWidget):
|
|||||||
newItem.setText(self.C_WORDS, f"{wC:n}")
|
newItem.setText(self.C_WORDS, f"{wC:n}")
|
||||||
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
|
||||||
|
|
||||||
theRefs = self.theProject.index.getReferences(tHandle, sTitle)
|
if self._lastCol == NovelColumnType.HIDDEN:
|
||||||
newItem.setText(self.C_POV, ", ".join(theRefs[nwKeyWords.POV_KEY]))
|
newItem.setText(self.C_LAST, "")
|
||||||
|
else:
|
||||||
|
theRefs = self.theProject.index.getReferences(tHandle, sTitle)
|
||||||
|
if self._lastCol == NovelColumnType.POV:
|
||||||
|
newText = ", ".join(theRefs[nwKeyWords.POV_KEY])
|
||||||
|
newItem.setText(self.C_LAST, newText)
|
||||||
|
if newText:
|
||||||
|
newItem.setToolTip(self.C_LAST, f"{self._povLabel}: {newText}")
|
||||||
|
elif self._lastCol == NovelColumnType.FOCUS:
|
||||||
|
newText = ", ".join(theRefs[nwKeyWords.FOCUS_KEY])
|
||||||
|
newItem.setText(self.C_LAST, newText)
|
||||||
|
if newText:
|
||||||
|
newItem.setToolTip(self.C_LAST, f"{self._focLabel}: {newText}")
|
||||||
|
|
||||||
return newItem
|
return newItem
|
||||||
|
|
||||||
|
|||||||
@@ -423,6 +423,7 @@ class GuiMain(QMainWindow):
|
|||||||
self.closeDocument()
|
self.closeDocument()
|
||||||
self.docViewer.clearNavHistory()
|
self.docViewer.clearNavHistory()
|
||||||
self.outlineView.closeOutline()
|
self.outlineView.closeOutline()
|
||||||
|
self.novelView.closeProjectTasks()
|
||||||
|
|
||||||
self.theProject.closeProject(self.idleTime)
|
self.theProject.closeProject(self.idleTime)
|
||||||
self.idleRefTime = time()
|
self.idleRefTime = time()
|
||||||
|
|||||||
Reference in New Issue
Block a user