From 9d283d2eae11c0cacf4527f2d8b694861340df7c Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Mon, 31 Oct 2022 15:55:33 +0100 Subject: [PATCH] Move all remaining trivial project settings to the data class --- novelwriter/core/project.py | 176 ++++++++----------------- novelwriter/core/projectdata.py | 71 +++++++++- novelwriter/core/projectxml.py | 72 +++++++--- novelwriter/dialogs/projsettings.py | 4 +- novelwriter/gui/docviewer.py | 2 +- novelwriter/gui/noveltree.py | 11 +- novelwriter/gui/outline.py | 6 +- novelwriter/guimain.py | 24 ++-- novelwriter/tools/build.py | 2 +- tests/test_core/test_core_project.py | 46 +++---- tests/test_core/test_core_tokenizer.py | 4 +- tests/tools.py | 2 +- 12 files changed, 225 insertions(+), 195 deletions(-) diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py index cecb6092..e4153709 100644 --- a/novelwriter/core/project.py +++ b/novelwriter/core/project.py @@ -74,10 +74,10 @@ class NWProject: self._langData = {} # Localisation data # Project Status - self.projOpened = 0 # The time stamp of when the project file was opened - self.projChanged = False # The project has unsaved changes - self.projAltered = False # The project has been altered this session - self.lockedBy = None # Data on which computer has the project open + self._projOpened = 0 # The time stamp of when the project file was opened + self._projChanged = False # The project has unsaved changes + self._projAltered = False # The project has been altered this session + self.lockedBy = None # Data on which computer has the project open # Class Settings self.projPath = None # The full path to where the currently open project is saved @@ -86,7 +86,6 @@ class NWProject: self.projContent = None # The full path to the project's content folder self.projDict = None # The spell check dictionary self.projSpell = None # The spell check language, if different than default - self.projLang = None # The project language, used for builds self.projFiles = [] # A list of all files in the content folder on load # Project Settings @@ -95,17 +94,9 @@ class NWProject: self.spellCheck = False # Controls the spellcheck-as-you-type feature self.statusItems = None # Novel file progress status values self.importItems = None # Note file importance values - self.lastEdited = None # The handle of the last file to be edited - self.lastViewed = None # The handle of the last file to be viewed - self.lastNovel = None # The handle of the last novel root viewed - self.lastOutline = None # The handle of the last outline root viewed - self.lastWCount = 0 # The project word count from last session - self.lastNovelWC = 0 # The novel files word count from last session - self.lastNotesWC = 0 # The note files word count from last session self.currWCount = 0 # The project word count in current session self.currNovelWC = 0 # The novel files word count in cutrent session self.currNotesWC = 0 # The note files word count in cutrent session - self.doBackup = True # Run project backup on exit # Internal Mapping self.tr = partial(QCoreApplication.translate, "NWProject") @@ -135,6 +126,18 @@ class NWProject: def options(self): return self._optState + @property + def projOpened(self): + return self._projOpened + + @property + def projChanged(self): + return self._projChanged or self._data.changed + + @property + def projAltered(self): + return self._projAltered + ## # Item Methods ## @@ -243,9 +246,9 @@ class NWProject: default values. """ # Project Status - self.projOpened = 0 - self.projChanged = False - self.projAltered = False + self._projOpened = 0 + self._projChanged = False + self._projAltered = False # Project Tree self._projTree.clear() @@ -259,7 +262,6 @@ class NWProject: self.projContent = None self.projDict = None self.projSpell = None - self.projLang = None self.projFiles = [] self.autoReplace = {} self.titleFormat = { @@ -280,11 +282,6 @@ class NWProject: self.importItems.write(None, self.tr("Minor"), (200, 50, 0)) self.importItems.write(None, self.tr("Major"), (200, 150, 0)) self.importItems.write(None, self.tr("Main"), (50, 200, 0)) - self.lastEdited = None - self.lastViewed = None - self.lastWCount = 0 - self.lastNovelWC = 0 - self.lastNotesWC = 0 self.currWCount = 0 self.currNovelWC = 0 self.currNotesWC = 0 @@ -414,7 +411,7 @@ class NWProject: # Finalise if popCustom or popMinimal: - self.projOpened = time() + self._projOpened = time() self.setProjectChanged(True) self.saveProject(autoSave=True) @@ -484,10 +481,10 @@ class NWProject: # print(json.dumps(xmlData, indent=2)) - nwxRoot = xmlData.get("xmlRoot", "") - appVersion = xmlData.get("appVersion", self.tr("Unknown")) - hexVersion = xmlData.get("hexVersion", 0x0000) - xmlVersion = xmlData.get("xmlVersion", self.tr("Unknown")) + nwxRoot = xmlReader.xmlRoot + appVersion = xmlReader.appVersion or self.tr("Unknown") + hexVersion = xmlReader.hexVersion or "0x0" + xmlVersion = xmlReader.xmlVersion or self.tr("Unknown") if not xmlParsed: if xmlReader.state == XMLReadState.NOT_NWX_FILE: @@ -555,17 +552,8 @@ class NWProject: xmlSettings = xmlData.get("settings", {}) - self.doBackup = xmlSettings.get("doBackup", False) - self.projLang = xmlSettings.get("language", None) - self.spellCheck = xmlSettings.get("spellCheck", False) - self.projSpell = xmlSettings.get("spellLang", None) - self.lastEdited = xmlSettings.get("lastEdited", None) - self.lastViewed = xmlSettings.get("lastViewed", None) - self.lastNovel = xmlSettings.get("lastNovel", None) - self.lastOutline = xmlSettings.get("lastOutline", None) - self.lastWCount = xmlSettings.get("lastWordCount", 0) - self.lastNovelWC = xmlSettings.get("novelWordCount", 0) - self.lastNotesWC = xmlSettings.get("notesWordCount", 0) + self.spellCheck = self._data.spellCheck + self.projSpell = self._data.spellLang self.statusItems.unpack(xmlSettings.get("status", {})) self.importItems.unpack(xmlSettings.get("import", {})) self.autoReplace = xmlSettings.get("autoReplace", {}) @@ -590,7 +578,9 @@ class NWProject: self._deprecatedFiles() # Update recent projects - self.mainConf.updateRecentCache(self.projPath, self._data.name, self.lastWCount, time()) + self.mainConf.updateRecentCache( + self.projPath, self._data.name, self._data.getLastCount("total"), time() + ) self.mainConf.saveRecentCache() # Check the project tree consistency @@ -605,8 +595,8 @@ class NWProject: self._loadProjectLocalisation() self.updateWordCounts() - self.projOpened = time() - self.projAltered = False + self._projOpened = time() + self._projAltered = False self._writeLockFile() self.setProjectChanged(False) @@ -647,7 +637,7 @@ class NWProject: }) self.updateWordCounts() - editTime = int(self._data.editTime + saveTime - self.projOpened) + editTime = int(self._data.editTime + saveTime - self._projOpened) # Save Project Meta xProject = etree.SubElement(nwXML, "project") @@ -660,14 +650,14 @@ class NWProject: # Save Project Settings xSettings = etree.SubElement(nwXML, "settings") - self._packProjectValue(xSettings, "doBackup", self.doBackup) - self._packProjectValue(xSettings, "language", self.projLang) - self._packProjectValue(xSettings, "spellCheck", self.spellCheck) - self._packProjectValue(xSettings, "spellLang", self.projSpell) - self._packProjectValue(xSettings, "lastEdited", self.lastEdited) - self._packProjectValue(xSettings, "lastViewed", self.lastViewed) - self._packProjectValue(xSettings, "lastNovel", self.lastNovel) - self._packProjectValue(xSettings, "lastOutline", self.lastOutline) + self._packProjectValue(xSettings, "doBackup", self._data.doBackup) + self._packProjectValue(xSettings, "language", self._data.language) + self._packProjectValue(xSettings, "spellCheck", self._data.spellCheck) + self._packProjectValue(xSettings, "spellLang", self._data.spellLang) + self._packProjectValue(xSettings, "lastEdited", self._data.getLastHandle("editor")) + self._packProjectValue(xSettings, "lastViewed", self._data.getLastHandle("viewer")) + self._packProjectValue(xSettings, "lastNovel", self._data.getLastHandle("noveltree")) + self._packProjectValue(xSettings, "lastOutline", self._data.getLastHandle("outline")) self._packProjectValue(xSettings, "lastWordCount", self.currWCount) self._packProjectValue(xSettings, "novelWordCount", self.currNovelWC) self._packProjectValue(xSettings, "notesWordCount", self.currNotesWC) @@ -942,28 +932,6 @@ class NWProject: return True - def setProjBackup(self, doBackup): - """Set whether projects should be backed up or not. The user - will be notified in case required settings are missing. - """ - self.doBackup = doBackup - if doBackup: - if not os.path.isdir(self.mainConf.backupPath): - self.mainGui.makeAlert(self.tr( - "You must set a valid backup path in Preferences to use " - "the automatic project backup feature." - ), nwAlert.WARN) - return False - - if self._data.name == "": - self.mainGui.makeAlert(self.tr( - "You must set a valid project name in Project Settings to " - "use the automatic project backup feature." - ), nwAlert.WARN) - return False - - return True - def setSpellCheck(self, theMode): """Enable/disable spell checking. """ @@ -986,8 +954,8 @@ class NWProject: """Set the project-specific language. """ theLang = checkStringNone(theLang, None) - if self.projLang != theLang: - self.projLang = theLang + if self._data.language != theLang: + self._data.setLanguage(theLang) self._loadProjectLocalisation() self.setProjectChanged(True) return True @@ -1003,38 +971,6 @@ class NWProject: self.setProjectChanged(True) return True - def setLastEdited(self, tHandle): - """Set last edited project item. - """ - if self.lastEdited != tHandle: - self.lastEdited = tHandle - self.setProjectChanged(True) - return True - - def setLastViewed(self, tHandle): - """Set last viewed project item. - """ - if self.lastViewed != tHandle: - self.lastViewed = tHandle - self.setProjectChanged(True) - return True - - def setLastNovelViewed(self, tHandle): - """Set last viewed novel root in the novel tree. - """ - if self.lastNovel != tHandle: - self.lastNovel = tHandle - self.setProjectChanged(True) - return True - - def setLastOutlineViewed(self, tHandle): - """Set last viewed novel root in the outline view. - """ - if self.lastOutline != tHandle: - self.lastOutline = tHandle - self.setProjectChanged(True) - return True - def setStatusColours(self, newCols, delCols): """Update the list of novel file status flags. """ @@ -1068,12 +1004,15 @@ class NWProject: """Toggle the project changed flag, and propagate the information to the GUI statusbar. """ - self.projChanged = bValue + self._projChanged = bValue self.mainGui.mainStatus.doUpdateProjectStatus(bValue) - if bValue: + if bValue is True: # If we've changed the project at all, this should be True - self.projAltered = True - return self.projChanged + self._projAltered = True + else: + # If we're resetting the status, also reset for data class + self._data.resetProjectChanged() + return self._projChanged ## # Getters @@ -1083,7 +1022,7 @@ class NWProject: """Get the total project edit time, including the time spent in the current session. """ - return round(self._data.editTime + time() - self.projOpened) + return round(self._data.editTime + time() - self._projOpened) def getProjectItems(self): """This function ensures that the item tree loaded is sent to @@ -1193,11 +1132,11 @@ class NWProject: def _loadProjectLocalisation(self): """Load the language data for the current project language. """ - if self.projLang is None: + if self._data.language is None: self._langData = {} return False - langFile = os.path.join(self.mainConf.nwLangPath, "project_%s.json" % self.projLang) + langFile = os.path.join(self.mainConf.nwLangPath, "project_%s.json" % self._data.language) if not os.path.isfile(langFile): langFile = os.path.join(self.mainConf.nwLangPath, "project_en_GB.json") @@ -1421,8 +1360,9 @@ class NWProject: isFile = os.path.isfile(sessionFile) nowTime = time() - sessDiff = self.currWCount - self.lastWCount - sessTime = nowTime - self.projOpened + lastCount = self._data.getLastCount("total") + sessDiff = self.currWCount - lastCount + sessTime = nowTime - self._projOpened logger.info("The session lasted %d sec and added %d words", int(sessTime), sessDiff) if sessTime < 300 and sessDiff == 0: @@ -1433,14 +1373,14 @@ class NWProject: with open(sessionFile, mode="a+", encoding="utf-8") as outFile: if not isFile: # It's a new file, so add a header - if self.lastWCount > 0: - outFile.write("# Offset %d\n" % self.lastWCount) + if lastCount > 0: + outFile.write("# Offset %d\n" % lastCount) outFile.write("# %-17s %-19s %8s %8s %8s\n" % ( "Start Time", "End Time", "Novel", "Notes", "Idle" )) outFile.write("%-19s %-19s %8d %8d %8d\n" % ( - formatTimeStamp(self.projOpened), + formatTimeStamp(self._projOpened), formatTimeStamp(nowTime), self.currNovelWC, self.currNotesWC, diff --git a/novelwriter/core/projectdata.py b/novelwriter/core/projectdata.py index 49ac64af..d87c5660 100644 --- a/novelwriter/core/projectdata.py +++ b/novelwriter/core/projectdata.py @@ -25,7 +25,9 @@ along with this program. If not, see . import logging -from novelwriter.common import checkInt, simplified +from novelwriter.common import ( + checkBool, checkInt, checkStringNone, simplified +) logger = logging.getLogger(__name__) @@ -42,6 +44,14 @@ class NWProjectData: self._autoCount = 0 self._editTime = 0 + # Project Settings + self._doBackup = True + self._language = None + self._spellCheck = False + self._spellLang = None + self._lastHandle = {} + self._lastCount = {} + # Internal self._changed = False @@ -75,6 +85,26 @@ class NWProjectData: def editTime(self): return self._editTime + @property + def doBackup(self): + return self._doBackup + + @property + def language(self): + return self._language + + @property + def spellCheck(self): + return self._spellCheck + + @property + def spellLang(self): + return self._spellLang + + @property + def changed(self): + return self._changed + ## # Methods ## @@ -94,10 +124,19 @@ class NWProjectData: self._changed = True return + def resetProjectChanged(self): + self._changed = False + ## # Getters ## + def getLastHandle(self, component): + return self._lastHandle.get(component, None) + + def getLastCount(self, type): + return self._lastCount.get(type, 0) + def getAuthors(self, trAnd="and"): """Return a formatted string of authors. """ @@ -155,4 +194,34 @@ class NWProjectData: self._changed = True return + def setDoBackup(self, value): + self._doBackup = checkBool(value, False) + self._changed = True + return + + def setLanguage(self, value): + self._language = checkStringNone(value, None) + self._changed = True + return + + def setSpellCheck(self, value): + self._spellCheck = checkBool(value, False) + self._changed = True + return + + def setSpellLang(self, value): + self._spellLang = checkStringNone(value, None) + self._changed = True + return + + def setLastHandle(self, value, component): + self._lastHandle[component] = checkStringNone(value, None) + self._changed = True + return + + def setLastCount(self, value, type): + self._lastCount[type] = checkInt(value, 0) + self._changed = True + return + # END Class NWProjectData diff --git a/novelwriter/core/projectxml.py b/novelwriter/core/projectxml.py index 7b78dd2c..8760f6b1 100644 --- a/novelwriter/core/projectxml.py +++ b/novelwriter/core/projectxml.py @@ -69,10 +69,16 @@ class ProjectXMLReader: self._state = XMLReadState.NO_ACTION self._data = {} - self._version = 0x0000 + self._content = [] self._statusData = {} self._statusMap = {} + self._root = "" + self._version = 0x0000 + self._appVersion = "" + self._hexVersion = "" + self._timeStamp = "" + return ## @@ -83,10 +89,34 @@ class ProjectXMLReader: def data(self): return self._data + @property + def content(self): + return self._content + @property def state(self): return self._state + @property + def xmlRoot(self): + return self._root + + @property + def xmlVersion(self): + return self._version + + @property + def appVersion(self): + return self._appVersion + + @property + def hexVersion(self): + return self._hexVersion + + @property + def timeStamp(self): + return self._timeStamp + ## # Methods ## @@ -95,6 +125,7 @@ class ProjectXMLReader: """Read and parse the project XML file. """ self._data = {} + self._content = [] try: xml = etree.parse(self._path) @@ -119,8 +150,8 @@ class ProjectXMLReader: return False xRoot = xml.getroot() - self._data["xmlRoot"] = str(xRoot.tag) - if xRoot.tag != "novelWriterXML": + self._root = str(xRoot.tag) + if self._root != "novelWriterXML": self._state = XMLReadState.NOT_NWX_FILE return False @@ -147,17 +178,16 @@ class ProjectXMLReader: self._state = XMLReadState.UNKNOWN_VERSION return False - self._data["xmlVersion"] = self._version - self._data["appVersion"] = str(xRoot.attrib.get("appVersion", "")) - self._data["hexVersion"] = str(xRoot.attrib.get("appVersion", "")) - self._data["timeStamp"] = str(xRoot.attrib.get("timeStamp", "")) + self._appVersion = str(xRoot.attrib.get("appVersion", "")) + self._hexVersion = str(xRoot.attrib.get("appVersion", "")) + self._timeStamp = str(xRoot.attrib.get("timeStamp", "")) status = True for xSection in xRoot: if xSection.tag == "project": status &= self._parseProjectMeta(xSection, projData) elif xSection.tag == "settings": - status &= self._parseProjectSettings(xSection) + status &= self._parseProjectSettings(xSection, projData) elif xSection.tag == "content": if self._version >= 0x0104: status &= self._parseProjectContent(xSection) @@ -202,7 +232,7 @@ class ProjectXMLReader: logger.warning("Ignored in xml", xItem.tag) return True - def _parseProjectSettings(self, xSection): + def _parseProjectSettings(self, xSection, projData): """Parse the settings section of the XML file. """ logger.debug("Parsing xml ") @@ -212,27 +242,27 @@ class ProjectXMLReader: titleFormat = {} for xItem in xSection: if xItem.tag == "doBackup": - data["doBackup"] = checkBool(xItem.text, False) + projData.setDoBackup(xItem.text) elif xItem.tag == "language": - data["language"] = checkStringNone(xItem.text, None) + projData.setLanguage(xItem.text) elif xItem.tag == "spellCheck": - data["spellCheck"] = checkBool(xItem.text, False) + projData.setSpellCheck(xItem.text) elif xItem.tag == "spellLang": - data["spellLang"] = checkStringNone(xItem.text, None) + projData.setSpellLang(xItem.text) elif xItem.tag == "lastEdited": - data["lastEdited"] = checkStringNone(xItem.text, None) + projData.setLastHandle(xItem.text, "editor") elif xItem.tag == "lastViewed": - data["lastViewed"] = checkStringNone(xItem.text, None) + projData.setLastHandle(xItem.text, "viewer") elif xItem.tag == "lastNovel": - data["lastNovel"] = checkStringNone(xItem.text, None) + projData.setLastHandle(xItem.text, "noveltree") elif xItem.tag == "lastOutline": - data["lastOutline"] = checkStringNone(xItem.text, None) + projData.setLastHandle(xItem.text, "outline") elif xItem.tag == "lastWordCount": - data["lastWordCount"] = checkInt(xItem.text, 0) + projData.setLastCount(xItem.text, "total") elif xItem.tag == "novelWordCount": - data["novelWordCount"] = checkInt(xItem.text, 0) + projData.setLastCount(xItem.text, "novel") elif xItem.tag == "notesWordCount": - data["notesWordCount"] = checkInt(xItem.text, 0) + projData.setLastCount(xItem.text, "notes") elif xItem.tag == "status": data["status"] = self._parseStatusImport(xItem, "status") elif xItem.tag in ("import", "importance"): @@ -293,6 +323,7 @@ class ProjectXMLReader: else: logger.warning("Ignored in xml", xVal.tag) data.append(item) + self._content.append(item) else: logger.warning("Ignored item in xml", xItem.tag) @@ -357,6 +388,7 @@ class ProjectXMLReader: item["type"] = "ROOT" data.append(item) + self._content.append(item) else: logger.warning("Ignored in xml", xItem.tag) diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py index 988b520b..a9ee7188 100644 --- a/novelwriter/dialogs/projsettings.py +++ b/novelwriter/dialogs/projsettings.py @@ -117,7 +117,7 @@ class GuiProjectSettings(PagedDialog): self.theProject.data.setName(projName) self.theProject.data.setTitle(bookTitle) self.theProject.data.setAuthors(bookAuthors) - self.theProject.setProjBackup(doBackup) + self.theProject.data.setDoBackup(doBackup) # Remember this as updating spell dictionary can be expensive self._spellChanged = self.theProject.setSpellLang(spellLang) @@ -258,7 +258,7 @@ class GuiProjectEditMain(QWidget): self.spellLang.setCurrentIndex(spellIdx) self.doBackup = QSwitch(self) - self.doBackup.setChecked(not self.theProject.doBackup) + self.doBackup.setChecked(not self.theProject.data.doBackup) self.mainForm.addRow( self.tr("No backup on close"), self.doBackup, diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 0437363e..808749df 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -217,7 +217,7 @@ class GuiDocViewer(QTextBrowser): self.verticalScrollBar().setValue(sPos) self._docHandle = tHandle - self.theProject.setLastViewed(tHandle) + self.theProject._data.setLastHandle(tHandle, "viewer") self.docHeader.setTitleFromHandle(self._docHandle) self.updateDocMargins() diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index 210626b5..bfa1da1c 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -109,7 +109,7 @@ class GuiNovelView(QWidget): def refreshTree(self): """Refresh the current tree. """ - self.novelTree.refreshTree(rootHandle=self.theProject.lastNovel) + self.novelTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("noveltree")) return def clearProject(self): @@ -122,7 +122,7 @@ class GuiNovelView(QWidget): def openProjectTasks(self): """Run open project tasks. """ - lastNovel = self.theProject.lastNovel + lastNovel = self.theProject.data.getLastHandle("noveltree") if lastNovel not in self.theProject.tree: lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL) @@ -319,7 +319,7 @@ class GuiNovelToolBar(QWidget): def _refreshNovelTree(self): """Rebuild the current tree. """ - rootHandle = self.theProject.lastNovel + rootHandle = self.theProject.data.getLastHandle("noveltree") self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True) return @@ -485,7 +485,7 @@ class GuiNovelTree(QTreeWidget): titleKey = selItem[0].data(self.C_TITLE, self.D_KEY) self._populateTree(rootHandle) - self.theProject.setLastNovelViewed(rootHandle) + self.theProject.data.setLastHandle(rootHandle, "noveltree") if titleKey is not None and titleKey in self._treeMap: self._treeMap[titleKey].setSelected(True) @@ -523,7 +523,8 @@ class GuiNovelTree(QTreeWidget): self._lastCol = colType self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN) if doRefresh: - self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True) + lastNovel = self.theProject.data.getLastHandle("noveltree") + self.refreshTree(rootHandle=lastNovel, overRide=True) return def setActiveHandle(self, tHandle): diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py index b5a1060a..5d66d139 100644 --- a/novelwriter/gui/outline.py +++ b/novelwriter/gui/outline.py @@ -114,7 +114,7 @@ class GuiOutlineView(QWidget): def refreshTree(self): """Refresh the current tree. """ - self.outlineTree.refreshTree(rootHandle=self.theProject.lastOutline) + self.outlineTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("outline")) return def clearProject(self): @@ -126,7 +126,7 @@ class GuiOutlineView(QWidget): def openProjectTasks(self): """Run open project tasks. """ - lastOutline = self.theProject.lastOutline + lastOutline = self.theProject.data.getLastHandle("outline") if not (lastOutline in self.theProject.tree or lastOutline is None): lastOutline = self.theProject.tree.findRoot(nwItemClass.NOVEL) @@ -504,7 +504,7 @@ class GuiOutlineTree(QTreeWidget): return self._populateTree(rootHandle) - self.theProject.setLastOutlineViewed(rootHandle or None) + self.theProject.data.setLastHandle(rootHandle or None, "outline") return diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index af76edf8..d3eb4f2b 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -417,7 +417,7 @@ class GuiMain(QMainWindow): if self.theProject.projAltered: saveOK = self.saveProject() doBackup = False - if self.theProject.doBackup and self.mainConf.backupOnClose: + if self.theProject.data.doBackup and self.mainConf.backupOnClose: doBackup = True if self.mainConf.askBeforeBackup: msgYes = self.askQuestion( @@ -532,11 +532,13 @@ class GuiMain(QMainWindow): self._updateStatusWordCount() # Restore previously open documents, if any - if self.theProject.lastEdited is not None: - self.openDocument(self.theProject.lastEdited, doScroll=True) + lastEdited = self.theProject.data.getLastHandle("editor") + if lastEdited is not None: + self.openDocument(lastEdited, doScroll=True) - if self.theProject.lastViewed is not None: - self.viewDocument(self.theProject.lastViewed) + lastViewed = self.theProject.data.getLastHandle("viewer") + if lastViewed is not None: + self.viewDocument(lastViewed) # Check if we need to rebuild the index if self.theProject.index.indexBroken: @@ -607,7 +609,7 @@ class GuiMain(QMainWindow): if self.docEditor.loadText(tHandle, tLine): if changeFocus: self.docEditor.setFocus() - self.theProject.setLastEdited(tHandle) + self.theProject.data.setLastHandle(tHandle, "editor") self.projView.setSelectedHandle(tHandle, doScroll=doScroll) self.novelView.setActiveHandle(tHandle) else: @@ -676,7 +678,7 @@ class GuiMain(QMainWindow): tHandle = self.projView.getSelectedHandle() if tHandle is None: - tHandle = self.theProject.lastViewed + tHandle = self.theProject.data.getLastHandle("viewer") if tHandle is None: logger.debug("No document to view, giving up") @@ -1223,14 +1225,14 @@ class GuiMain(QMainWindow): """Close the document edit panel. This does not hide the editor. """ self.closeDocument() - self.theProject.setLastEdited(None) + self.theProject.data.setLastHandle(None, "editor") return def closeDocViewer(self): """Close the document view panel. """ self.docViewer.clearViewer() - self.theProject.setLastViewed(None) + self.theProject.data.setLastHandle(None, "viewer") bPos = self.splitMain.sizes() self.splitView.setVisible(False) self.splitDocs.setSizes([bPos[1], 0]) @@ -1556,10 +1558,10 @@ class GuiMain(QMainWindow): self.theProject.updateWordCounts() if self.mainConf.incNotesWCount: currWords = self.theProject.currWCount - diffWords = currWords - self.theProject.lastWCount + diffWords = currWords - self.theProject.data.getLastCount("total") else: currWords = self.theProject.currNovelWC - diffWords = currWords - self.theProject.lastNovelWC + diffWords = currWords - self.theProject.data.getLastCount("novel") self.mainStatus.setProjectStats(currWords, diffWords) diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py index e9aa37cd..979e3e98 100644 --- a/novelwriter/tools/build.py +++ b/novelwriter/tools/build.py @@ -168,7 +168,7 @@ class GuiBuildNovel(QDialog): for langID, langName in theLangs: self.buildLang.addItem(langName, langID) - langIdx = self.buildLang.findData(self.theProject.projLang) + langIdx = self.buildLang.findData(self.theProject.data.language) if langIdx != -1: self.buildLang.setCurrentIndex(langIdx) diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py index 16ba37d4..7d1edf17 100644 --- a/tests/test_core/test_core_project.py +++ b/tests/test_core/test_core_project.py @@ -927,7 +927,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd): # Edit Time theProject.data.setEditTime(1234) - theProject.projOpened = 1600000000 + theProject._projOpened = 1600000000 with monkeypatch.context() as mp: mp.setattr("novelwriter.core.project.time", lambda: 1600005600) assert theProject.getCurrentEditTime() == 6834 @@ -939,28 +939,14 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd): assert theProject.trashFolder() == hTrash assert theProject.trashFolder() == hTrash - # Project backup - assert theProject.doBackup is True - assert theProject.setProjBackup(False) - assert theProject.doBackup is False - - assert not theProject.setProjBackup(True) - theProject.mainConf.backupPath = tmpDir - assert theProject.setProjBackup(True) - - theProject.data.setName("") - assert not theProject.setProjBackup(True) - theProject.data.setName("A Name") - assert theProject.setProjBackup(True) - # Spell check - theProject.projChanged = False + theProject.setProjectChanged(False) assert theProject.setSpellCheck(True) assert not theProject.setSpellCheck(False) assert theProject.projChanged # Spell language - theProject.projChanged = False + theProject.setProjectChanged(False) assert theProject.projSpell is None assert theProject.setSpellLang(None) is False assert theProject.projSpell is None @@ -971,31 +957,31 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd): assert theProject.projChanged # Project Language - theProject.projChanged = False - theProject.projLang = "en" + theProject.setProjectChanged(False) + theProject.data.setLanguage("en") assert theProject.setProjectLang(None) is True - assert theProject.projLang is None + assert theProject.data.language is None assert theProject.setProjectLang("en_GB") is True - assert theProject.projLang == "en_GB" + assert theProject.data.language == "en_GB" # Language Lookup assert theProject.localLookup(1) == "One" assert theProject.localLookup(10) == "Ten" # Last edited - theProject.projChanged = False - assert theProject.setLastEdited("0123456789abc") - assert theProject.lastEdited == "0123456789abc" + theProject.setProjectChanged(False) + theProject._data.setLastHandle("0123456789abc", "editor") + assert theProject._data.getLastHandle("editor") == "0123456789abc" assert theProject.projChanged # Last viewed - theProject.projChanged = False - assert theProject.setLastViewed("0123456789abc") - assert theProject.lastViewed == "0123456789abc" + theProject.setProjectChanged(False) + theProject._data.setLastHandle("0123456789abc", "viewer") + assert theProject._data.getLastHandle("viewer") == "0123456789abc" assert theProject.projChanged # Autoreplace - theProject.projChanged = False + theProject.setProjectChanged(False) assert theProject.setAutoReplace({"A": "B", "C": "D"}) assert theProject.autoReplace == {"A": "B", "C": "D"} assert theProject.projChanged @@ -1019,7 +1005,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd): # Session stats theProject.currWCount = 200 - theProject.lastWCount = 100 + theProject.data.setLastCount(100, "total") with monkeypatch.context() as mp: mp.setattr("os.path.isdir", lambda *a, **k: False) assert not theProject._appendSessionStats(idleTime=0) @@ -1033,7 +1019,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd): assert theProject.projMeta == os.path.join(fncDir, "meta") statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS) - theProject.projOpened = 1600002000 + theProject._projOpened = 1600002000 theProject.currNovelWC = 200 theProject.currNotesWC = 100 diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index 38121268..23f47565 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -137,7 +137,7 @@ def testCoreToken_TextOps(monkeypatch, nwMinimal, mockGUI): """Test handling files and text in the Tokenizer class. """ theProject = NWProject(mockGUI) - theProject.projLang = "en" + theProject.data.setLanguage("en") theProject._loadProjectLocalisation() theToken = BareTokenizer(theProject) @@ -884,7 +884,7 @@ def testCoreToken_ProcessHeaders(mockGUI): """Test the header and page parser of the Tokenizer class. """ theProject = NWProject(mockGUI) - theProject.projLang = "en" + theProject.data.setLanguage("en") theProject._loadProjectLocalisation() theToken = BareTokenizer(theProject) diff --git a/tests/tools.py b/tests/tools.py index 82e528fe..1cbc0359 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -195,7 +195,7 @@ def buildTestProject(theObject, projPath): aDoc.writeDocument("### %s\n\n" % theProject.tr("New Scene")) theProject.index.reIndexHandle(xHandle[8]) - theProject.projOpened = time.time() + theProject._projOpened = time.time() theProject.setProjectChanged(True) theProject.saveProject(autoSave=True)