diff --git a/nw/constants/constants.py b/nw/constants/constants.py index a0325482..acc63977 100644 --- a/nw/constants/constants.py +++ b/nw/constants/constants.py @@ -20,15 +20,15 @@ class nwConst(): class nwFiles(): - APP_ICON = "novelWriter.svg" - PROJ_FILE = "nwProject.nwx" - PROJ_COUNT = "projCount.txt" - PROJ_DICT = "wordlist.txt" - SESS_INFO = "sessionInfo.log" - INDEX_FILE = "tagsIndex.json" - EXPORT_OPT = "exportOptions.json" - TLINE_OPT = "timelineOptions.json" - SLOG_OPT = "sessionLogOptions.json" + APP_ICON = "novelWriter.svg" + PROJ_FILE = "nwProject.nwx" + PROJ_COUNT = "projCount.txt" + PROJ_DICT = "wordlist.txt" + SESS_INFO = "sessionInfo.log" + INDEX_FILE = "tagsIndex.json" + EXPORT_OPT = "exportOptions.json" + OUTLINE_OPT = "outlineOptions.json" + SLOG_OPT = "sessionLogOptions.json" # END Class nwFiles diff --git a/nw/gui/dialogs/export.py b/nw/gui/dialogs/export.py index 8d580f87..16f72484 100644 --- a/nw/gui/dialogs/export.py +++ b/nw/gui/dialogs/export.py @@ -683,7 +683,7 @@ class ExportLastState(OptLastState): def __init__(self, theProject, theFile): OptLastState.__init__(self, theProject, theFile) - self.theState = { + self.theState = { "wNovel" : True, "wNotes" : False, "eFormat" : 1, diff --git a/nw/gui/elements/outline.py b/nw/gui/elements/outline.py index dc0af7c9..403c20a0 100644 --- a/nw/gui/elements/outline.py +++ b/nw/gui/elements/outline.py @@ -16,12 +16,13 @@ import nw from os import path from time import time -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QByteArray from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem ) -from nw.constants import nwItemLayout, nwKeyWords, nwLabels +from nw.tools import OptLastState +from nw.constants import nwItemLayout, nwKeyWords, nwLabels, nwFiles logger = logging.getLogger(__name__) @@ -44,12 +45,7 @@ class GuiProjectOutline(QWidget): I_ENTITY = 14 I_CUSTOM = 15 - COL_ORDER = [ - I_TITLE, I_LEVEL, I_LABEL, I_LINE, - I_WCOUNT, I_CCOUNT, I_PCOUNT, I_SYNOP, - I_POV, I_CHAR, I_PLOT, I_TIME, - I_WORLD, I_OBJECT, I_ENTITY, I_CUSTOM, - ] + COL_MAX = 15 COL_LABELS = { I_TITLE : "Title", @@ -79,6 +75,7 @@ class GuiProjectOutline(QWidget): self.theParent = theParent self.theProject = theProject self.theIndex = self.theParent.theIndex + self.optState = OutlineLastState(self.theProject,nwFiles.OUTLINE_OPT) self.showWords = True self.showSynopsis = True @@ -86,9 +83,18 @@ class GuiProjectOutline(QWidget): self.outerBox = QVBoxLayout() self.mainTree = QTreeWidget() - self.treeCols = self.COL_ORDER self.lastBuild = 0 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.outerBox.addWidget(self.mainTree) self.outerBox.setContentsMargins(0,0,0,0) @@ -98,19 +104,57 @@ class GuiProjectOutline(QWidget): return + def saveHeaderState(self): + + colW = [] + for iCol in range(self.mainTree.columnCount()): + colW.append(self.mainTree.columnWidth(iCol)) + + self.treeCols["width"] = colW + self.optState.setSetting("headState", self.treeCols) + self.optState.saveSettings() + return + + def loadHeaderState(self): + self.optState.loadSettings() + treeCols = self.optState.getSetting("headState") + + if "order" not in treeCols.keys(): return + if not isinstance(treeCols["order"], list): return + if len(treeCols["order"]) == 0: return + + self.treeCols["order"] = [] + for colID in treeCols["order"]: + if colID >= 0 and colID <= self.COL_MAX: + self.treeCols["order"].append(colID) + + if "width" in treeCols.keys(): + if isinstance(treeCols["width"],list): + self.treeCols["width"] = treeCols["width"] + + return + def populateTree(self): + self.loadHeaderState() + theLabels = [] - for n in self.treeCols: + for i, n in enumerate(self.treeCols["order"]): theLabels.append(self.COL_LABELS[n]) + self.colIndex[n] = i self.mainTree.clear() self.mainTree.setHeaderLabels(theLabels) + for n, colW in enumerate(self.treeCols["width"]): + self.mainTree.setColumnWidth(n,colW) treeHead = self.mainTree.headerItem() - treeHead.setTextAlignment(self.I_CCOUNT,Qt.AlignRight) - treeHead.setTextAlignment(self.I_WCOUNT,Qt.AlignRight) - treeHead.setTextAlignment(self.I_PCOUNT,Qt.AlignRight) + 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) currTitle = None currChapter = None @@ -180,28 +224,44 @@ class GuiProjectOutline(QWidget): novIdx = self.theIndex.novelIndex[tHandle][sTitle] newItem = QTreeWidgetItem() - newItem.setText(self.I_TITLE, novIdx["title"]) - newItem.setText(self.I_LEVEL, novIdx["level"]) - newItem.setText(self.I_LABEL, nwItem.itemName) - newItem.setText(self.I_LINE, sTitle[1:]) - - newItem.setText(self.I_CCOUNT, str(novIdx["cCount"])) - newItem.setText(self.I_WCOUNT, str(novIdx["wCount"])) - newItem.setText(self.I_PCOUNT, str(novIdx["pCount"])) - newItem.setTextAlignment(self.I_CCOUNT,Qt.AlignRight) - newItem.setTextAlignment(self.I_WCOUNT,Qt.AlignRight) - newItem.setTextAlignment(self.I_PCOUNT,Qt.AlignRight) + 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) theRefs = self.theIndex.getReferences(tHandle, sTitle) - newItem.setText(self.I_POV, ", ".join(theRefs[nwKeyWords.POV_KEY])) - newItem.setText(self.I_CHAR, ", ".join(theRefs[nwKeyWords.CHAR_KEY])) - newItem.setText(self.I_PLOT, ", ".join(theRefs[nwKeyWords.PLOT_KEY])) - newItem.setText(self.I_TIME, ", ".join(theRefs[nwKeyWords.TIME_KEY])) - newItem.setText(self.I_WORLD, ", ".join(theRefs[nwKeyWords.WORLD_KEY])) - newItem.setText(self.I_OBJECT, ", ".join(theRefs[nwKeyWords.OBJECT_KEY])) - newItem.setText(self.I_ENTITY, ", ".join(theRefs[nwKeyWords.ENTITY_KEY])) - newItem.setText(self.I_CUSTOM, ", ".join(theRefs[nwKeyWords.CUSTOM_KEY])) + 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])) return newItem + def _setItemText(self, tItem, colID, theText, rAlign=False): + if colID in self.colIndex: + tItem.setText(self.colIndex[colID], theText) + if rAlign: + tItem.setTextAlignment(self.colIndex[colID],Qt.AlignRight) + return + # END Class GuiProjectOutline + +class OutlineLastState(OptLastState): + + def __init__(self, theProject, theFile): + OptLastState.__init__(self, theProject, theFile) + self.theState = { + "headState" : {}, + } + self.dictOpt = ("headState") + return + +# END Class OutlineLastState diff --git a/nw/guimain.py b/nw/guimain.py index c6535eb5..acdeb131 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -679,6 +679,8 @@ class GuiMain(QMainWindow): return False logger.info("Exiting %s" % nw.__package__) + self.projView.saveHeaderState() + self.closeProject(True) self.mainConf.setTreeColWidths(self.treeView.getColumnSizes()) diff --git a/nw/tools/optlaststate.py b/nw/tools/optlaststate.py index 0df6ff68..bce89f00 100644 --- a/nw/tools/optlaststate.py +++ b/nw/tools/optlaststate.py @@ -28,12 +28,21 @@ class OptLastState(): self.theState = {} self.stringOpt = () self.boolOpt = () + self.dictOpt = () self.intOpt = () return def loadSettings(self): + + if self.theProject.projMeta is None or self.theFile is None: + logger.error("Cannot load file '%s' to path '%s'" % ( + str(self.theFile), str(self.theProject.projMeta) + )) + return False + stateFile = path.join(self.theProject.projMeta,self.theFile) theState = {} + if path.isfile(stateFile): logger.debug("Loading options file") try: @@ -44,11 +53,20 @@ class OptLastState(): logger.error("Failed to load options file") logger.error(str(e)) return False + for anOpt in theState: self.theState[anOpt] = theState[anOpt] + return True def saveSettings(self): + + if self.theProject.projMeta is None or self.theFile is None: + logger.error("Cannot save file '%s' to path '%s'" % ( + str(self.theFile), str(self.theProject.projMeta) + )) + return False + stateFile = path.join(self.theProject.projMeta,self.theFile) logger.debug("Saving options file") try: @@ -58,6 +76,7 @@ class OptLastState(): logger.error("Failed to save options file") logger.error(str(e)) return False + return True def setSetting(self, setName, setValue): @@ -72,6 +91,11 @@ class OptLastState(): return checkString(self.theState[setName],self.theState[setName],False) elif setName in self.boolOpt: return checkBool(self.theState[setName],self.theState[setName],False) + elif setName in self.dictOpt: + if isinstance(self.theState[setName], dict): + return self.theState[setName] + else: + return {} elif setName in self.intOpt: return checkInt(self.theState[setName],self.theState[setName],False) return None