Restructured the way column state is preserved in the Outline tree
This commit is contained in:
@@ -22,4 +22,4 @@ __all__ = [
|
||||
"nwItemClass",
|
||||
"nwItemLayout",
|
||||
"nwItemType",
|
||||
]
|
||||
]
|
||||
|
||||
+133
-102
@@ -15,10 +15,11 @@ import nw
|
||||
|
||||
from os import path
|
||||
from time import time
|
||||
from enum import Enum
|
||||
|
||||
from PyQt5.QtCore import Qt, QByteArray
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem,
|
||||
QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QMenu, QAction,
|
||||
QAbstractItemView
|
||||
)
|
||||
|
||||
@@ -26,44 +27,46 @@ from nw.constants import nwKeyWords, nwLabels
|
||||
|
||||
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):
|
||||
|
||||
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 = {
|
||||
I_TITLE : "Title",
|
||||
I_LEVEL : "Level",
|
||||
I_LABEL : "Document",
|
||||
I_LINE : "Line",
|
||||
I_WCOUNT : "Words",
|
||||
I_CCOUNT : "Chars",
|
||||
I_PCOUNT : "Pars",
|
||||
I_SYNOP : "Synopsis",
|
||||
I_POV : "POV",
|
||||
I_CHAR : nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY],
|
||||
I_PLOT : nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY],
|
||||
I_TIME : nwLabels.KEY_NAME[nwKeyWords.TIME_KEY],
|
||||
I_WORLD : nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY],
|
||||
I_OBJECT : nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY],
|
||||
I_ENTITY : nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY],
|
||||
I_CUSTOM : nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
||||
HCols.TITLE : "Title",
|
||||
HCols.LEVEL : "Level",
|
||||
HCols.LABEL : "Document",
|
||||
HCols.LINE : "Line",
|
||||
HCols.WCOUNT : "Words",
|
||||
HCols.CCOUNT : "Chars",
|
||||
HCols.PCOUNT : "Pars",
|
||||
HCols.POV : "POV",
|
||||
HCols.CHAR : nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY],
|
||||
HCols.PLOT : nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY],
|
||||
HCols.TIME : nwLabels.KEY_NAME[nwKeyWords.TIME_KEY],
|
||||
HCols.WORLD : nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY],
|
||||
HCols.OBJECT : nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY],
|
||||
HCols.ENTITY : nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY],
|
||||
HCols.CUSTOM : nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
||||
HCols.SYNOP : "Synopsis",
|
||||
}
|
||||
|
||||
def __init__(self, theParent, theProject):
|
||||
@@ -76,6 +79,7 @@ class GuiProjectOutline(QTreeWidget):
|
||||
self.theProject = theProject
|
||||
self.theIndex = self.theParent.theIndex
|
||||
self.optState = self.theProject.optState
|
||||
self.headerMenu = GuiOutlineHeaderMenu(self)
|
||||
|
||||
self.firstView = True
|
||||
self.lastBuild = 0
|
||||
@@ -86,21 +90,16 @@ class GuiProjectOutline(QTreeWidget):
|
||||
self.setDragEnabled(False)
|
||||
self.itemDoubleClicked.connect(self._treeDoubleClick)
|
||||
|
||||
# self.mainHead = self.header()
|
||||
# self.mainHead.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
# self.mainHead.
|
||||
self.treeHead = self.header()
|
||||
self.treeHead.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.treeHead.customContextMenuRequested.connect(self._headerRightClick)
|
||||
self.treeHead.sectionMoved.connect(self._columnMoved)
|
||||
|
||||
self.treeMap = {}
|
||||
self.treeCols = {
|
||||
"order" : [
|
||||
self.I_TITLE, self.I_LABEL,
|
||||
self.I_WCOUNT, self.I_POV,
|
||||
self.I_CHAR, self.I_PLOT,
|
||||
self.I_WORLD, self.I_SYNOP
|
||||
],
|
||||
"width" : [150, 100, 80, 100, 100, 100, 100, 300],
|
||||
}
|
||||
self.colIndex = {}
|
||||
self.treeOrder = self.COL_LABELS.keys()
|
||||
self.treeNCols = len(self.treeOrder)
|
||||
self.treeWidth = [150]*self.treeNCols
|
||||
self.colIndex = {}
|
||||
|
||||
logger.debug("ProjectOutline initialisation complete")
|
||||
|
||||
@@ -123,11 +122,9 @@ class GuiProjectOutline(QTreeWidget):
|
||||
def closeOutline(self):
|
||||
"""Called before a project is closed.
|
||||
"""
|
||||
|
||||
self._saveHeaderState()
|
||||
self.clear()
|
||||
self.firstView = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -138,6 +135,22 @@ class GuiProjectOutline(QTreeWidget):
|
||||
print(tItem, tCol)
|
||||
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
|
||||
##
|
||||
@@ -147,20 +160,35 @@ class GuiProjectOutline(QTreeWidget):
|
||||
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
|
||||
if not isinstance(treeCols["order"], list): return
|
||||
if len(treeCols["order"]) == 0: return
|
||||
# Add columns that were not in tempOrder to treeOrder, but in
|
||||
# the default column order.
|
||||
for cItem in keysOrder:
|
||||
if cItem not in treeOrder:
|
||||
treeOrder.append(cItem)
|
||||
|
||||
self.treeCols["order"] = []
|
||||
for colID in treeCols["order"]:
|
||||
if colID >= 0 and colID <= self.COL_MAX:
|
||||
self.treeCols["order"].append(colID)
|
||||
# Check that we now have a complete list, and only if so, save
|
||||
# the order loaded from file. Otherwise, we keep the default.
|
||||
if len(treeOrder) == self.treeNCols:
|
||||
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():
|
||||
if isinstance(treeCols["width"],list):
|
||||
self.treeCols["width"] = treeCols["width"]
|
||||
# The columns widths we just fill whatever we've got, and append
|
||||
# the rest with defaults, and truncate to desired length.
|
||||
tempWidth = self.optState.getValue("GuiProjectOutline", "headerWidth", [])
|
||||
treeWidth = [int(w) for w in tempWidth]
|
||||
self.treeWidth = (treeWidth + self.treeWidth)[0:self.treeNCols]
|
||||
|
||||
return
|
||||
|
||||
@@ -169,12 +197,15 @@ class GuiProjectOutline(QTreeWidget):
|
||||
and column width.
|
||||
"""
|
||||
|
||||
colW = []
|
||||
treeWidth = []
|
||||
treeOrder = []
|
||||
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", "headerState", self.treeCols)
|
||||
self.optState.setValue("GuiProjectOutline", "headerOrder", treeOrder)
|
||||
self.optState.setValue("GuiProjectOutline", "headerWidth", treeWidth)
|
||||
self.optState.saveSettings()
|
||||
|
||||
return
|
||||
@@ -184,22 +215,19 @@ class GuiProjectOutline(QTreeWidget):
|
||||
"""
|
||||
|
||||
theLabels = []
|
||||
for i, n in enumerate(self.treeCols["order"]):
|
||||
theLabels.append(self.COL_LABELS[n])
|
||||
self.colIndex[n] = i
|
||||
for i, hItem in enumerate(self.treeOrder):
|
||||
theLabels.append(self.COL_LABELS[hItem])
|
||||
self.colIndex[hItem] = i
|
||||
|
||||
self.clear()
|
||||
self.setHeaderLabels(theLabels)
|
||||
for n, colW in enumerate(self.treeCols["width"]):
|
||||
for n, colW in enumerate(self.treeWidth):
|
||||
self.setColumnWidth(n,colW)
|
||||
|
||||
treeHead = self.headerItem()
|
||||
if self.I_CCOUNT in self.colIndex:
|
||||
treeHead.setTextAlignment(self.colIndex[self.I_CCOUNT],Qt.AlignRight)
|
||||
if self.I_WCOUNT in self.colIndex:
|
||||
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)
|
||||
headItem = self.headerItem()
|
||||
headItem.setTextAlignment(self.colIndex[HCols.CCOUNT],Qt.AlignRight)
|
||||
headItem.setTextAlignment(self.colIndex[HCols.WCOUNT],Qt.AlignRight)
|
||||
headItem.setTextAlignment(self.colIndex[HCols.PCOUNT],Qt.AlignRight)
|
||||
|
||||
currTitle = None
|
||||
currChapter = None
|
||||
@@ -267,35 +295,38 @@ class GuiProjectOutline(QTreeWidget):
|
||||
novIdx = self.theIndex.novelIndex[tHandle][sTitle]
|
||||
|
||||
newItem = QTreeWidgetItem()
|
||||
self._setItemText(newItem, self.I_TITLE, novIdx["title"])
|
||||
self._setItemText(newItem, self.I_LEVEL, novIdx["level"])
|
||||
self._setItemText(newItem, self.I_LABEL, nwItem.itemName)
|
||||
self._setItemText(newItem, self.I_LINE, sTitle[1:])
|
||||
self._setItemText(newItem, self.I_SYNOP, novIdx["synopsis"])
|
||||
self._setItemText(newItem, self.I_CCOUNT, str(novIdx["cCount"]), True)
|
||||
self._setItemText(newItem, self.I_WCOUNT, str(novIdx["wCount"]), True)
|
||||
self._setItemText(newItem, self.I_PCOUNT, str(novIdx["pCount"]), True)
|
||||
|
||||
newItem.setText(self.colIndex[HCols.TITLE], novIdx["title"])
|
||||
newItem.setText(self.colIndex[HCols.LEVEL], novIdx["level"])
|
||||
newItem.setText(self.colIndex[HCols.LABEL], nwItem.itemName)
|
||||
newItem.setText(self.colIndex[HCols.LINE], sTitle[1:])
|
||||
newItem.setText(self.colIndex[HCols.SYNOP], novIdx["synopsis"])
|
||||
newItem.setText(self.colIndex[HCols.CCOUNT], str(novIdx["cCount"]))
|
||||
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)
|
||||
self._setItemText(newItem, self.I_POV, ", ".join(theRefs[nwKeyWords.POV_KEY]))
|
||||
self._setItemText(newItem, self.I_CHAR, ", ".join(theRefs[nwKeyWords.CHAR_KEY]))
|
||||
self._setItemText(newItem, self.I_PLOT, ", ".join(theRefs[nwKeyWords.PLOT_KEY]))
|
||||
self._setItemText(newItem, self.I_TIME, ", ".join(theRefs[nwKeyWords.TIME_KEY]))
|
||||
self._setItemText(newItem, self.I_WORLD, ", ".join(theRefs[nwKeyWords.WORLD_KEY]))
|
||||
self._setItemText(newItem, self.I_OBJECT, ", ".join(theRefs[nwKeyWords.OBJECT_KEY]))
|
||||
self._setItemText(newItem, self.I_ENTITY, ", ".join(theRefs[nwKeyWords.ENTITY_KEY]))
|
||||
self._setItemText(newItem, self.I_CUSTOM, ", ".join(theRefs[nwKeyWords.CUSTOM_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.POV], ", ".join(theRefs[nwKeyWords.POV_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.CHAR], ", ".join(theRefs[nwKeyWords.CHAR_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.PLOT], ", ".join(theRefs[nwKeyWords.PLOT_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.TIME], ", ".join(theRefs[nwKeyWords.TIME_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.WORLD], ", ".join(theRefs[nwKeyWords.WORLD_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.OBJECT], ", ".join(theRefs[nwKeyWords.OBJECT_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.ENTITY], ", ".join(theRefs[nwKeyWords.ENTITY_KEY]))
|
||||
newItem.setText(self.colIndex[HCols.CUSTOM], ", ".join(theRefs[nwKeyWords.CUSTOM_KEY]))
|
||||
|
||||
return newItem
|
||||
|
||||
def _setItemText(self, tItem, colID, theText, rAlign=False):
|
||||
"""Set the correct text in the correct column, and if necessary,
|
||||
right align it.
|
||||
"""
|
||||
if colID in self.colIndex:
|
||||
tItem.setText(self.colIndex[colID], theText)
|
||||
if rAlign:
|
||||
tItem.setTextAlignment(self.colIndex[colID], Qt.AlignRight)
|
||||
# END Class GuiProjectOutline
|
||||
|
||||
class GuiOutlineHeaderMenu(QMenu):
|
||||
|
||||
def __init__(self, theParent):
|
||||
QMenu.__init__(self, theParent)
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiProjectOutline
|
||||
# END Class GuiOutlineHeaderMenu
|
||||
|
||||
Reference in New Issue
Block a user