Restructured the way column state is preserved in the Outline tree

This commit is contained in:
Veronica K. B. Olsen
2020-03-10 23:18:58 +01:00
parent c9657a3515
commit 32c6d80efb
2 changed files with 134 additions and 103 deletions
+133 -102
View File
@@ -15,10 +15,11 @@ import nw
from os import path from os import path
from time import time from time import time
from enum import Enum
from PyQt5.QtCore import Qt, QByteArray from PyQt5.QtCore import Qt, QByteArray
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QMenu, QAction,
QAbstractItemView QAbstractItemView
) )
@@ -26,44 +27,46 @@ from nw.constants import nwKeyWords, nwLabels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class HCols(Enum):
TITLE = 0
LEVEL = 1
LABEL = 2
LINE = 3
WCOUNT = 4
CCOUNT = 5
PCOUNT = 6
SYNOP = 7
POV = 8
CHAR = 9
PLOT = 10
TIME = 11
WORLD = 12
OBJECT = 13
ENTITY = 14
CUSTOM = 15
# END Enum HCols
class GuiProjectOutline(QTreeWidget): class GuiProjectOutline(QTreeWidget):
I_TITLE = 0
I_LEVEL = 1
I_LABEL = 2
I_LINE = 3
I_WCOUNT = 4
I_CCOUNT = 5
I_PCOUNT = 6
I_SYNOP = 7
I_POV = 8
I_CHAR = 9
I_PLOT = 10
I_TIME = 11
I_WORLD = 12
I_OBJECT = 13
I_ENTITY = 14
I_CUSTOM = 15
COL_MAX = 15
COL_LABELS = { COL_LABELS = {
I_TITLE : "Title", HCols.TITLE : "Title",
I_LEVEL : "Level", HCols.LEVEL : "Level",
I_LABEL : "Document", HCols.LABEL : "Document",
I_LINE : "Line", HCols.LINE : "Line",
I_WCOUNT : "Words", HCols.WCOUNT : "Words",
I_CCOUNT : "Chars", HCols.CCOUNT : "Chars",
I_PCOUNT : "Pars", HCols.PCOUNT : "Pars",
I_SYNOP : "Synopsis", HCols.POV : "POV",
I_POV : "POV", HCols.CHAR : nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY],
I_CHAR : nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY], HCols.PLOT : nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY],
I_PLOT : nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY], HCols.TIME : nwLabels.KEY_NAME[nwKeyWords.TIME_KEY],
I_TIME : nwLabels.KEY_NAME[nwKeyWords.TIME_KEY], HCols.WORLD : nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY],
I_WORLD : nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY], HCols.OBJECT : nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY],
I_OBJECT : nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY], HCols.ENTITY : nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY],
I_ENTITY : nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY], HCols.CUSTOM : nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY],
I_CUSTOM : nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY], HCols.SYNOP : "Synopsis",
} }
def __init__(self, theParent, theProject): def __init__(self, theParent, theProject):
@@ -76,6 +79,7 @@ class GuiProjectOutline(QTreeWidget):
self.theProject = theProject self.theProject = theProject
self.theIndex = self.theParent.theIndex self.theIndex = self.theParent.theIndex
self.optState = self.theProject.optState self.optState = self.theProject.optState
self.headerMenu = GuiOutlineHeaderMenu(self)
self.firstView = True self.firstView = True
self.lastBuild = 0 self.lastBuild = 0
@@ -86,21 +90,16 @@ class GuiProjectOutline(QTreeWidget):
self.setDragEnabled(False) self.setDragEnabled(False)
self.itemDoubleClicked.connect(self._treeDoubleClick) self.itemDoubleClicked.connect(self._treeDoubleClick)
# self.mainHead = self.header() self.treeHead = self.header()
# self.mainHead.setContextMenuPolicy(Qt.CustomContextMenu) self.treeHead.setContextMenuPolicy(Qt.CustomContextMenu)
# self.mainHead. self.treeHead.customContextMenuRequested.connect(self._headerRightClick)
self.treeHead.sectionMoved.connect(self._columnMoved)
self.treeMap = {} self.treeMap = {}
self.treeCols = { self.treeOrder = self.COL_LABELS.keys()
"order" : [ self.treeNCols = len(self.treeOrder)
self.I_TITLE, self.I_LABEL, self.treeWidth = [150]*self.treeNCols
self.I_WCOUNT, self.I_POV, self.colIndex = {}
self.I_CHAR, self.I_PLOT,
self.I_WORLD, self.I_SYNOP
],
"width" : [150, 100, 80, 100, 100, 100, 100, 300],
}
self.colIndex = {}
logger.debug("ProjectOutline initialisation complete") logger.debug("ProjectOutline initialisation complete")
@@ -123,11 +122,9 @@ class GuiProjectOutline(QTreeWidget):
def closeOutline(self): def closeOutline(self):
"""Called before a project is closed. """Called before a project is closed.
""" """
self._saveHeaderState() self._saveHeaderState()
self.clear() self.clear()
self.firstView = True self.firstView = True
return return
## ##
@@ -138,6 +135,22 @@ class GuiProjectOutline(QTreeWidget):
print(tItem, tCol) print(tItem, tCol)
return return
def _headerRightClick(self, clickPos):
print(clickPos)
globPos = self.mapToGlobal(clickPos)
print(globPos)
return
def _columnMoved(self, logIdx, oldVisualIdx, newVisualIdx):
"""Make sure the order and width read from settings file, or
with default values, is kept up-to-date when columns are moved
around. Otherwise, the original order will be restored on a tree
rebuild.
"""
self.treeOrder.insert(newVisualIdx, self.treeOrder.pop(oldVisualIdx))
self.treeWidth.insert(newVisualIdx, self.treeWidth.pop(oldVisualIdx))
return
## ##
# Internal Functions # Internal Functions
## ##
@@ -147,20 +160,35 @@ class GuiProjectOutline(QTreeWidget):
and column width. and column width.
""" """
treeCols = self.optState.getValue("GuiProjectOutline", "headerState", self.treeCols) # Load whatever we saved last time, regardless of wether it
# contains the correct names or number of columns.
keysOrder = self.COL_LABELS.keys()
tempOrder = self.optState.getValue("GuiProjectOutline", "headerOrder", keysOrder)
treeOrder = []
for hName in tempOrder:
for hItem in HCols:
if hItem.name == hName:
treeOrder.append(hItem)
if "order" not in treeCols.keys(): return # Add columns that were not in tempOrder to treeOrder, but in
if not isinstance(treeCols["order"], list): return # the default column order.
if len(treeCols["order"]) == 0: return for cItem in keysOrder:
if cItem not in treeOrder:
treeOrder.append(cItem)
self.treeCols["order"] = [] # Check that we now have a complete list, and only if so, save
for colID in treeCols["order"]: # the order loaded from file. Otherwise, we keep the default.
if colID >= 0 and colID <= self.COL_MAX: if len(treeOrder) == self.treeNCols:
self.treeCols["order"].append(colID) self.treeOrder = treeOrder
else:
logger.error("Failed to extract outline column order from previous session")
logger.error("Column count doesn't match %d != %d" % (len(treeOrder), self.treeNCols))
if "width" in treeCols.keys(): # The columns widths we just fill whatever we've got, and append
if isinstance(treeCols["width"],list): # the rest with defaults, and truncate to desired length.
self.treeCols["width"] = treeCols["width"] tempWidth = self.optState.getValue("GuiProjectOutline", "headerWidth", [])
treeWidth = [int(w) for w in tempWidth]
self.treeWidth = (treeWidth + self.treeWidth)[0:self.treeNCols]
return return
@@ -169,12 +197,15 @@ class GuiProjectOutline(QTreeWidget):
and column width. and column width.
""" """
colW = [] treeWidth = []
treeOrder = []
for iCol in range(self.columnCount()): for iCol in range(self.columnCount()):
colW.append(self.columnWidth(iCol)) treeOrder.append(self.treeOrder[iCol].name)
iLog = self.treeHead.logicalIndex(iCol)
treeWidth.append(self.columnWidth(iLog))
self.treeCols["width"] = colW self.optState.setValue("GuiProjectOutline", "headerOrder", treeOrder)
self.optState.setValue("GuiProjectOutline", "headerState", self.treeCols) self.optState.setValue("GuiProjectOutline", "headerWidth", treeWidth)
self.optState.saveSettings() self.optState.saveSettings()
return return
@@ -184,22 +215,19 @@ class GuiProjectOutline(QTreeWidget):
""" """
theLabels = [] theLabels = []
for i, n in enumerate(self.treeCols["order"]): for i, hItem in enumerate(self.treeOrder):
theLabels.append(self.COL_LABELS[n]) theLabels.append(self.COL_LABELS[hItem])
self.colIndex[n] = i self.colIndex[hItem] = i
self.clear() self.clear()
self.setHeaderLabels(theLabels) self.setHeaderLabels(theLabels)
for n, colW in enumerate(self.treeCols["width"]): for n, colW in enumerate(self.treeWidth):
self.setColumnWidth(n,colW) self.setColumnWidth(n,colW)
treeHead = self.headerItem() headItem = self.headerItem()
if self.I_CCOUNT in self.colIndex: headItem.setTextAlignment(self.colIndex[HCols.CCOUNT],Qt.AlignRight)
treeHead.setTextAlignment(self.colIndex[self.I_CCOUNT],Qt.AlignRight) headItem.setTextAlignment(self.colIndex[HCols.WCOUNT],Qt.AlignRight)
if self.I_WCOUNT in self.colIndex: headItem.setTextAlignment(self.colIndex[HCols.PCOUNT],Qt.AlignRight)
treeHead.setTextAlignment(self.colIndex[self.I_WCOUNT],Qt.AlignRight)
if self.I_PCOUNT in self.colIndex:
treeHead.setTextAlignment(self.colIndex[self.I_PCOUNT],Qt.AlignRight)
currTitle = None currTitle = None
currChapter = None currChapter = None
@@ -267,35 +295,38 @@ class GuiProjectOutline(QTreeWidget):
novIdx = self.theIndex.novelIndex[tHandle][sTitle] novIdx = self.theIndex.novelIndex[tHandle][sTitle]
newItem = QTreeWidgetItem() newItem = QTreeWidgetItem()
self._setItemText(newItem, self.I_TITLE, novIdx["title"])
self._setItemText(newItem, self.I_LEVEL, novIdx["level"]) newItem.setText(self.colIndex[HCols.TITLE], novIdx["title"])
self._setItemText(newItem, self.I_LABEL, nwItem.itemName) newItem.setText(self.colIndex[HCols.LEVEL], novIdx["level"])
self._setItemText(newItem, self.I_LINE, sTitle[1:]) newItem.setText(self.colIndex[HCols.LABEL], nwItem.itemName)
self._setItemText(newItem, self.I_SYNOP, novIdx["synopsis"]) newItem.setText(self.colIndex[HCols.LINE], sTitle[1:])
self._setItemText(newItem, self.I_CCOUNT, str(novIdx["cCount"]), True) newItem.setText(self.colIndex[HCols.SYNOP], novIdx["synopsis"])
self._setItemText(newItem, self.I_WCOUNT, str(novIdx["wCount"]), True) newItem.setText(self.colIndex[HCols.CCOUNT], str(novIdx["cCount"]))
self._setItemText(newItem, self.I_PCOUNT, str(novIdx["pCount"]), True) newItem.setText(self.colIndex[HCols.WCOUNT], str(novIdx["wCount"]))
newItem.setText(self.colIndex[HCols.PCOUNT], str(novIdx["pCount"]))
newItem.setTextAlignment(self.colIndex[HCols.CCOUNT], Qt.AlignRight)
newItem.setTextAlignment(self.colIndex[HCols.WCOUNT], Qt.AlignRight)
newItem.setTextAlignment(self.colIndex[HCols.PCOUNT], Qt.AlignRight)
theRefs = self.theIndex.getReferences(tHandle, sTitle) theRefs = self.theIndex.getReferences(tHandle, sTitle)
self._setItemText(newItem, self.I_POV, ", ".join(theRefs[nwKeyWords.POV_KEY])) newItem.setText(self.colIndex[HCols.POV], ", ".join(theRefs[nwKeyWords.POV_KEY]))
self._setItemText(newItem, self.I_CHAR, ", ".join(theRefs[nwKeyWords.CHAR_KEY])) newItem.setText(self.colIndex[HCols.CHAR], ", ".join(theRefs[nwKeyWords.CHAR_KEY]))
self._setItemText(newItem, self.I_PLOT, ", ".join(theRefs[nwKeyWords.PLOT_KEY])) newItem.setText(self.colIndex[HCols.PLOT], ", ".join(theRefs[nwKeyWords.PLOT_KEY]))
self._setItemText(newItem, self.I_TIME, ", ".join(theRefs[nwKeyWords.TIME_KEY])) newItem.setText(self.colIndex[HCols.TIME], ", ".join(theRefs[nwKeyWords.TIME_KEY]))
self._setItemText(newItem, self.I_WORLD, ", ".join(theRefs[nwKeyWords.WORLD_KEY])) newItem.setText(self.colIndex[HCols.WORLD], ", ".join(theRefs[nwKeyWords.WORLD_KEY]))
self._setItemText(newItem, self.I_OBJECT, ", ".join(theRefs[nwKeyWords.OBJECT_KEY])) newItem.setText(self.colIndex[HCols.OBJECT], ", ".join(theRefs[nwKeyWords.OBJECT_KEY]))
self._setItemText(newItem, self.I_ENTITY, ", ".join(theRefs[nwKeyWords.ENTITY_KEY])) newItem.setText(self.colIndex[HCols.ENTITY], ", ".join(theRefs[nwKeyWords.ENTITY_KEY]))
self._setItemText(newItem, self.I_CUSTOM, ", ".join(theRefs[nwKeyWords.CUSTOM_KEY])) newItem.setText(self.colIndex[HCols.CUSTOM], ", ".join(theRefs[nwKeyWords.CUSTOM_KEY]))
return newItem return newItem
def _setItemText(self, tItem, colID, theText, rAlign=False): # END Class GuiProjectOutline
"""Set the correct text in the correct column, and if necessary,
right align it. class GuiOutlineHeaderMenu(QMenu):
"""
if colID in self.colIndex: def __init__(self, theParent):
tItem.setText(self.colIndex[colID], theText) QMenu.__init__(self, theParent)
if rAlign:
tItem.setTextAlignment(self.colIndex[colID], Qt.AlignRight)
return return
# END Class GuiProjectOutline # END Class GuiOutlineHeaderMenu