def saveConfig(self): """Save the current preferences to file. """ logger.debug("Saving config file") if self.confPath is None: return False cnfParse = configparser.ConfigParser() # Set options ## Main cnfSec = "Main" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "timestamp", formatTimeStamp(time())) cnfParse.set(cnfSec, "theme", str(self.guiTheme)) cnfParse.set(cnfSec, "syntax", str(self.guiSyntax)) cnfParse.set(cnfSec, "icons", str(self.guiIcons)) cnfParse.set(cnfSec, "guidark", str(self.guiDark)) cnfParse.set(cnfSec, "guifont", str(self.guiFont)) cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize)) cnfParse.set(cnfSec, "lastnotes", str(self.lastNotes)) cnfParse.set(cnfSec, "guilang", str(self.guiLang)) ## Sizes cnfSec = "Sizes" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "geometry", self._packList(self.winGeometry)) cnfParse.set(cnfSec, "preferences", self._packList(self.prefGeometry)) cnfParse.set(cnfSec, "treecols", self._packList(self.treeColWidth)) cnfParse.set(cnfSec, "novelcols", self._packList(self.novelColWidth)) cnfParse.set(cnfSec, "projcols", self._packList(self.projColWidth)) cnfParse.set(cnfSec, "mainpane", self._packList(self.mainPanePos)) cnfParse.set(cnfSec, "docpane", self._packList(self.docPanePos)) cnfParse.set(cnfSec, "viewpane", self._packList(self.viewPanePos)) cnfParse.set(cnfSec, "outlinepane", self._packList(self.outlnPanePos)) cnfParse.set(cnfSec, "fullscreen", str(self.isFullScreen)) cnfParse.set(cnfSec, "hidevscroll", str(self.hideVScroll)) cnfParse.set(cnfSec, "hidehscroll", str(self.hideHScroll)) ## Project cnfSec = "Project" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "autosaveproject", str(self.autoSaveProj)) cnfParse.set(cnfSec, "autosavedoc", str(self.autoSaveDoc)) ## Editor cnfSec = "Editor" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "textfont", str(self.textFont)) cnfParse.set(cnfSec, "textsize", str(self.textSize)) cnfParse.set(cnfSec, "fixedwidth", str(self.textFixedW)) cnfParse.set(cnfSec, "width", str(self.textWidth)) cnfParse.set(cnfSec, "margin", str(self.textMargin)) cnfParse.set(cnfSec, "tabwidth", str(self.tabWidth)) cnfParse.set(cnfSec, "focuswidth", str(self.focusWidth)) cnfParse.set(cnfSec, "hidefocusfooter", str(self.hideFocusFooter)) cnfParse.set(cnfSec, "justify", str(self.doJustify)) cnfParse.set(cnfSec, "autoselect", str(self.autoSelect)) cnfParse.set(cnfSec, "autoreplace", str(self.doReplace)) cnfParse.set(cnfSec, "repsquotes", str(self.doReplaceSQuote)) cnfParse.set(cnfSec, "repdquotes", str(self.doReplaceDQuote)) cnfParse.set(cnfSec, "repdash", str(self.doReplaceDash)) cnfParse.set(cnfSec, "repdots", str(self.doReplaceDots)) cnfParse.set(cnfSec, "scrollpastend", str(self.scrollPastEnd)) cnfParse.set(cnfSec, "autoscroll", str(self.autoScroll)) cnfParse.set(cnfSec, "autoscrollpos", str(self.autoScrollPos)) cnfParse.set(cnfSec, "fmtsinglequote", self._packList(self.fmtSingleQuotes)) cnfParse.set(cnfSec, "fmtdoublequote", self._packList(self.fmtDoubleQuotes)) cnfParse.set(cnfSec, "fmtpadbefore", str(self.fmtPadBefore)) cnfParse.set(cnfSec, "fmtpadafter", str(self.fmtPadAfter)) cnfParse.set(cnfSec, "fmtpadthin", str(self.fmtPadThin)) cnfParse.set(cnfSec, "spelltool", str(self.spellTool)) cnfParse.set(cnfSec, "spellcheck", str(self.spellLanguage)) cnfParse.set(cnfSec, "showtabsnspaces", str(self.showTabsNSpaces)) cnfParse.set(cnfSec, "showlineendings", str(self.showLineEndings)) cnfParse.set(cnfSec, "bigdoclimit", str(self.bigDocLimit)) cnfParse.set(cnfSec, "showfullpath", str(self.showFullPath)) cnfParse.set(cnfSec, "highlightquotes", str(self.highlightQuotes)) cnfParse.set(cnfSec, "allowopensquote", str(self.allowOpenSQuote)) cnfParse.set(cnfSec, "allowopendquote", str(self.allowOpenDQuote)) cnfParse.set(cnfSec, "highlightemph", str(self.highlightEmph)) cnfParse.set(cnfSec, "stopwhenidle", str(self.stopWhenIdle)) cnfParse.set(cnfSec, "useridletime", str(self.userIdleTime)) ## Backup cnfSec = "Backup" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "backuppath", str(self.backupPath)) cnfParse.set(cnfSec, "backuponclose", str(self.backupOnClose)) cnfParse.set(cnfSec, "askbeforebackup", str(self.askBeforeBackup)) ## State cnfSec = "State" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "showrefpanel", str(self.showRefPanel)) cnfParse.set(cnfSec, "viewcomments", str(self.viewComments)) cnfParse.set(cnfSec, "viewsynopsis", str(self.viewSynopsis)) cnfParse.set(cnfSec, "searchcase", str(self.searchCase)) cnfParse.set(cnfSec, "searchword", str(self.searchWord)) cnfParse.set(cnfSec, "searchregex", str(self.searchRegEx)) cnfParse.set(cnfSec, "searchloop", str(self.searchLoop)) cnfParse.set(cnfSec, "searchnextfile", str(self.searchNextFile)) cnfParse.set(cnfSec, "searchmatchcap", str(self.searchMatchCap)) ## Path cnfSec = "Path" cnfParse.add_section(cnfSec) cnfParse.set(cnfSec, "lastpath", str(self.lastPath)) # Write config file cnfPath = os.path.join(self.confPath, self.confFile) try: with open(cnfPath, mode="w", encoding="utf8") as outFile: cnfParse.write(outFile) self.confChanged = False except Exception as e: logger.error("Could not save config file") logException() self.hasError = True self.errData.append("Could not save config file") self.errData.append(str(e)) return False return True
def testFormatTimeStamp(): tTime = time.mktime(time.gmtime(0)) assert formatTimeStamp(tTime, False) == "1970-01-01 00:00:00" assert formatTimeStamp(tTime, True) == "1970-01-01 00.00.00"
def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI, tmpDir): """Test other project class methods and functions. """ theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwMinimal) assert theProject.projPath == nwMinimal # Setting project path assert theProject.setProjectPath(None) assert theProject.projPath is None assert theProject.setProjectPath("") assert theProject.projPath is None assert theProject.setProjectPath("~") assert theProject.projPath == os.path.expanduser("~") # Create a new folder and populate it projPath = os.path.join(nwMinimal, "dummy1") assert theProject.setProjectPath(projPath, newProject=True) # Make os.mkdir fail monkeypatch.setattr("os.mkdir", causeOSError) projPath = os.path.join(nwMinimal, "dummy2") assert not theProject.setProjectPath(projPath, newProject=True) # Set back assert theProject.setProjectPath(nwMinimal) # Project Name assert theProject.setProjectName(" A Name ") assert theProject.projName == "A Name" # Project Title assert theProject.setBookTitle(" A Title ") assert theProject.bookTitle == "A Title" # Project Authors # Check that the list is cleaned up and that it can be extracted as # a properly formatted string, depending on number of names assert not theProject.setBookAuthors([]) assert theProject.setBookAuthors(" Jane Doe \n John Doh \n ") assert theProject.bookAuthors == ["Jane Doe", "John Doh"] assert theProject.setBookAuthors("") assert theProject.getAuthors() == "" assert theProject.setBookAuthors("Jane Doe") assert theProject.getAuthors() == "Jane Doe" assert theProject.setBookAuthors("Jane Doe\nJohn Doh") assert theProject.getAuthors() == "Jane Doe and John Doh" assert theProject.setBookAuthors("Jane Doe\nJohn Doh\nBod Owens") assert theProject.getAuthors() == "Jane Doe, John Doh and Bod Owens" # Edit Time theProject.editTime = 1234 theProject.projOpened = 1600000000 monkeypatch.setattr("nw.core.project.time", lambda: 1600005600) assert theProject.getCurrentEditTime() == 6834 monkeypatch.undo() # Trash folder # Should create on first call, and just returned on later calls assert theProject.projTree["73475cb40a568"] is None assert theProject.trashFolder() == "73475cb40a568" assert theProject.trashFolder() == "73475cb40a568" # 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) assert theProject.setProjectName("") assert not theProject.setProjBackup(True) assert theProject.setProjectName("A Name") assert theProject.setProjBackup(True) # Spell check theProject.projChanged = False assert theProject.setSpellCheck(True) assert not theProject.setSpellCheck(False) assert theProject.projChanged # Spell language theProject.projChanged = False assert theProject.setSpellLang(None) assert theProject.projLang is None assert theProject.setSpellLang("None") assert theProject.projLang is None assert theProject.setSpellLang("en_GB") assert theProject.projLang == "en_GB" assert theProject.projChanged # Automatic outline update theProject.projChanged = False assert theProject.setAutoOutline(True) assert not theProject.setAutoOutline(False) assert theProject.projChanged # Last edited theProject.projChanged = False assert theProject.setLastEdited("0123456789abc") assert theProject.lastEdited == "0123456789abc" assert theProject.projChanged # Last viewed theProject.projChanged = False assert theProject.setLastViewed("0123456789abc") assert theProject.lastViewed == "0123456789abc" assert theProject.projChanged # Autoreplace theProject.projChanged = False assert theProject.setAutoReplace({"A": "B", "C": "D"}) assert theProject.autoReplace == {"A": "B", "C": "D"} assert theProject.projChanged # Change project tree order oldOrder = [ "a508bb932959c", "a35baf2e93843", "a6d311a93600a", "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", "afb3043c7b2b3", "9d5247ab588e0", "73475cb40a568", ] newOrder = [ "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", "a508bb932959c", "a35baf2e93843", "a6d311a93600a", "afb3043c7b2b3", "9d5247ab588e0", ] assert theProject.projTree.handles() == oldOrder assert theProject.setTreeOrder(newOrder) assert theProject.projTree.handles() == newOrder assert theProject.setTreeOrder(oldOrder) assert theProject.projTree.handles() == oldOrder # Change status theProject.projTree["a35baf2e93843"].setStatus("Finished") theProject.projTree["a6d311a93600a"].setStatus("Draft") theProject.projTree["f5ab3e30151e1"].setStatus("Note") theProject.projTree["8c659a11cd429"].setStatus("Finished") newList = [ ("New", 1, 1, 1, "New"), ("Draft", 2, 2, 2, "Note"), # These are swapped ("Note", 3, 3, 3, "Draft"), # These are swapped ("Edited", 4, 4, 4, "Finished"), # Renamed ("Finished", 5, 5, 5, None), # New, with reused name ] assert theProject.setStatusColours(newList) assert theProject.statusItems._theLabels == [ "New", "Draft", "Note", "Edited", "Finished" ] assert theProject.statusItems._theColours == [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)] assert theProject.projTree[ "a35baf2e93843"].itemStatus == "Edited" # Renamed assert theProject.projTree["a6d311a93600a"].itemStatus == "Note" # Swapped assert theProject.projTree["f5ab3e30151e1"].itemStatus == "Draft" # Swapped assert theProject.projTree[ "8c659a11cd429"].itemStatus == "Edited" # Renamed # Change importance fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "afb3043c7b2b3") theProject.projTree[fHandle].setStatus("Main") newList = [ ("New", 1, 1, 1, "New"), ("Minor", 2, 2, 2, "Minor"), ("Major", 3, 3, 3, "Major"), ("Min", 4, 4, 4, "Main"), ("Max", 5, 5, 5, None), ] assert theProject.setImportColours(newList) assert theProject.importItems._theLabels == [ "New", "Minor", "Major", "Min", "Max" ] assert theProject.importItems._theColours == [(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)] assert theProject.projTree[fHandle].itemStatus == "Min" # Check status counts assert theProject.statusItems._theCounts == [0, 0, 0, 0, 0] assert theProject.importItems._theCounts == [0, 0, 0, 0, 0] theProject.countStatus() assert theProject.statusItems._theCounts == [1, 1, 1, 2, 0] assert theProject.importItems._theCounts == [3, 0, 0, 1, 0] # Check word counts theProject.currWCount = 200 theProject.lastWCount = 100 assert theProject.getSessionWordCount() == 100 # Session stats monkeypatch.setattr("os.path.isdir", lambda *args, **kwargs: False) assert not theProject._appendSessionStats() monkeypatch.undo() # Block open monkeypatch.setattr("builtins.open", causeOSError) assert not theProject._appendSessionStats() monkeypatch.undo() # Write entry assert theProject.projMeta == os.path.join(nwMinimal, "meta") statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS) theProject.projOpened = 1600002000 theProject.novelWCount = 200 theProject.notesWCount = 100 monkeypatch.setattr("nw.core.project.time", lambda: 1600005600) assert theProject._appendSessionStats() monkeypatch.undo() assert readFile(statsFile) == ( "# Offset 100\n" "# Start Time End Time Novel Notes\n" "%s %s 200 100\n") % (formatTimeStamp(1600002000), formatTimeStamp(1600005600)) # Pack XML Value xElem = etree.Element("element") theProject._packProjectValue(xElem, "A", "B", allowNone=False) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element><A>B</A></element>") xElem = etree.Element("element") theProject._packProjectValue(xElem, "A", "", allowNone=False) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element/>") # Pack XML Key/Value xElem = etree.Element("element") theProject._packProjectKeyValue(xElem, "item", {"A": "B", "C": "D"}) assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == (b"<element>" b"<item>" b"<entry key=\"A\">B</entry>" b"<entry key=\"C\">D</entry>" b"</item>" b"</element>")
def testBaseCommon_FormatTimeStamp(): """Test the formatTimeStamp function. """ tTime = time.mktime(time.gmtime(0)) assert formatTimeStamp(tTime, False) == "1970-01-01 00:00:00" assert formatTimeStamp(tTime, True) == "1970-01-01 00.00.00"